1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
33 #include <gdk/gdkkeysyms.h>
35 #ifdef HAVE_LIBDMALLOC
39 #define GLADE_HOOKUP_OBJECT(component,widget,name) \
40 g_object_set_data_full (G_OBJECT (component), name, \
41 gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
43 /** @brief How many entries to keep in the "Search text" combo box. */
44 #define HISTORY_LENGTH 15
46 /* autonumber text structs and enums */
48 AUTONUMBER_SORT_DIAGONAL
,
50 AUTONUMBER_SORT_YX_REV
,
52 AUTONUMBER_SORT_XY_REV
,
68 typedef struct autonumber_text_t AUTONUMBER_TEXT
;
70 /** @brief Stored state of the autonumber text dialog */
71 struct autonumber_text_t
{
72 /** @brief Search text history */
75 /** @brief Scope for searching existing numbers */
78 /** @brief Scope for autonumbering text */
81 /** @brief Overwrite existing numbers in scope */
82 gboolean scope_overwrite
;
84 /** @brief Sort order */
87 /** @brief Starting number for automatic numbering */
90 /** @brief Remove numbers instead of automatic numbering */
93 /** @brief Automatic assignments of slots */
96 /** @brief Pointer to the dialog */
99 /** @brief Pointer to the GSCHEM_TOPLEVEL struct */
100 GSCHEM_TOPLEVEL
*w_current
;
102 /* variables used while autonumbering */
103 gchar
* current_searchtext
;
104 gint root_page
; /* flag whether its the root page or not */
105 GList
*used_numbers
; /* list of used numbers */
106 GList
*free_slots
; /* list of FREE_SLOT objects */
107 GList
*used_slots
; /* list of USED_SLOT objects */
110 typedef struct autonumber_slot_t AUTONUMBER_SLOT
;
112 struct autonumber_slot_t
{
113 gchar
*symbolname
; /* or should I use the device name? (Werner) */
114 gint number
; /* usually this is the refdes number */
115 gint slotnr
; /* just the number of the free slot */
120 /* ***** BACK-END CODE ***************************************************** */
122 /********** compare functions for g_list_sort, ... ***********************/
123 /*! \brief GCompareFunc function to sort a list with g_list_sort().
124 * \par Function Description
125 * Compares the integer values of the gconstpointers a and b.
126 * \return -1 if a<b, 1 if a>b, 0 if a==b
128 gint
autonumber_sort_numbers(gconstpointer a
, gconstpointer b
) {
129 if (GPOINTER_TO_INT(a
) < GPOINTER_TO_INT(b
))
131 if (GPOINTER_TO_INT(a
) > GPOINTER_TO_INT(b
))
136 /*! \brief GCompareFunc function to sort text objects by there location
137 * \par Function Description
138 * This Funcion takes two <B>OBJECT*</B> arguments and compares the
139 * location of the two text objects. The first sort criteria is the x location,
140 * the second sort criteria is the y location.
141 * The Function is used as GCompareFunc by g_list_sort().
143 gint
autonumber_sort_xy(gconstpointer a
, gconstpointer b
) {
145 aa
=(OBJECT
*) a
; bb
=(OBJECT
*) b
;
146 if (aa
->text
->x
< bb
->text
->x
)
148 if (aa
->text
->x
> bb
->text
->x
)
151 if (aa
->text
->y
> bb
->text
->y
)
153 if (aa
->text
->y
< bb
->text
->y
)
158 /*! \brief GCompareFunc function to sort text objects by there location
159 * \par Function Description
160 * This funcion takes two <B>OBJECT*</B> arguments and compares the
161 * location of the two text objects. The first sort criteria is the x location,
162 * the second sort criteria is the y location.
163 * This function sorts the objects in reverse order.
164 * The function is used as GCompareFunc by g_list_sort().
166 gint
autonumber_sort_xy_rev(gconstpointer a
, gconstpointer b
) {
168 aa
=(OBJECT
*) a
; bb
=(OBJECT
*) b
;
169 if (aa
->text
->x
< bb
->text
->x
)
171 if (aa
->text
->x
> bb
->text
->x
)
174 if (aa
->text
->y
< bb
->text
->y
)
176 if (aa
->text
->y
> bb
->text
->y
)
181 /*! \brief GCompareFunc function to sort text objects by there location
182 * \par Function Description
183 * This funcion takes two <B>OBJECT*</B> arguments and compares the
184 * location of the two text objects. The first sort criteria is the y location,
185 * the second sort criteria is the x location.
186 * The function is used as GCompareFunc by g_list_sort().
188 int autonumber_sort_yx(gconstpointer a
, gconstpointer b
) {
190 aa
=(OBJECT
*) a
; bb
=(OBJECT
*) b
;
191 if (aa
->text
->y
> bb
->text
->y
)
193 if (aa
->text
->y
< bb
->text
->y
)
196 if (aa
->text
->x
< bb
->text
->x
)
198 if (aa
->text
->x
> bb
->text
->x
)
203 /*! \brief GCompareFunc function to sort text objects by there location
204 * \par Function Description
205 * This Funcion takes two <B>OBJECT*</B> arguments and compares the
206 * location of the two text objects. The first sort criteria is the y location,
207 * the second sort criteria is the x location.
208 * This function sorts the objects in reverse order.
209 * The function is used as GCompareFunc by g_list_sort().
211 int autonumber_sort_yx_rev(gconstpointer a
, gconstpointer b
) {
213 aa
=(OBJECT
*) a
; bb
=(OBJECT
*) b
;
214 if (aa
->text
->y
> bb
->text
->y
)
216 if (aa
->text
->y
< bb
->text
->y
)
219 if (aa
->text
->x
> bb
->text
->x
)
221 if (aa
->text
->x
< bb
->text
->x
)
226 /*! \brief GCompareFunc function to sort text objects by there location
227 * \par Function Description
228 * This Funcion takes two <B>OBJECT*</B> arguments and compares the
229 * location of the two text objects. The sort criteria is the combined x- and the
230 * y-location. The function sorts from top left to bottom right.
231 * The function is used as GCompareFunc by g_list_sort().
233 int autonumber_sort_diagonal(gconstpointer a
, gconstpointer b
) {
235 aa
=(OBJECT
*) a
; bb
=(OBJECT
*) b
;
236 if (aa
->text
->x
- aa
->text
->y
< bb
->text
->x
- bb
->text
->y
)
238 if (aa
->text
->x
- aa
->text
->y
> bb
->text
->x
- bb
->text
->y
)
243 /*! \brief GCompareFunc function to acces <B>AUTONUMBER_SLOT</B> object in a GList
244 * \par Function Description
245 * This Funcion takes two <B>AUTONUMBER_SLOT*</B> arguments and compares them.
246 * Sorting criteria is are the AUTONUMBER_SLOT members: first the symbolname, than the
247 * number and last the slotnr.
248 * If the number or the slotnr is set to zero it acts as a wildcard.
249 * The function is used as GCompareFunc by GList functions.
251 gint
freeslot_compare(gconstpointer a
, gconstpointer b
)
253 AUTONUMBER_SLOT
*aa
, *bb
;
255 aa
= (AUTONUMBER_SLOT
*) a
; bb
= (AUTONUMBER_SLOT
*) b
;
257 if ((res
= strcmp(aa
->symbolname
, bb
->symbolname
)) != 0)
260 /* aa->symbolname == bb->symbolname */
261 if (aa
->number
== 0 || bb
->number
== 0)
263 if (aa
->number
> bb
->number
)
265 if (aa
->number
< bb
->number
)
268 /* aa->number == bb->number */
269 if (aa
->slotnr
== 0 || bb
->slotnr
== 0)
271 if (aa
->slotnr
> bb
->slotnr
)
273 if (aa
->slotnr
< bb
->slotnr
)
279 /*! \brief Prints a <B>GList</B> of <B>AUTONUMBER_SLOT</B> elements
280 * \par Function Description
281 * This funcion prints the elements of a GList that contains <B>AUTONUMBER_SLOT</B> elements
282 * It is only used for debugging purposes.
284 void freeslot_print(GList
*list
) {
288 printf("freeslot_print(): symname, number, slot\n");
289 for (item
= list
; item
!= NULL
; item
= g_list_next(item
)) {
291 printf(" %s, %d, %d\n",fs
->symbolname
, fs
->number
, fs
->slotnr
);
296 /*! \brief Function to clear the databases of used parts
297 * \par Function Descriptions
298 * Just remove the list of used numbers, used slots and free slots.
300 void autonumber_clear_database (AUTONUMBER_TEXT
*autotext
)
302 /* cleanup everything for the next searchtext */
303 if (autotext
->used_numbers
!= NULL
) {
304 g_list_free(autotext
->used_numbers
);
305 autotext
->used_numbers
= NULL
;
307 if (autotext
->free_slots
!= NULL
) {
308 g_list_foreach(autotext
->free_slots
, (GFunc
) g_free
, NULL
);
309 g_list_free(autotext
->free_slots
);
310 autotext
->free_slots
= NULL
;
312 if (autotext
->used_slots
!= NULL
) {
313 g_list_foreach(autotext
->used_slots
, (GFunc
) g_free
, NULL
);
314 g_list_free(autotext
->used_slots
);
315 autotext
->used_slots
= NULL
;
319 /*! \brief Function to test, whether the OBJECT matches the autotext criterias
320 * \par Function Description
321 * The criterias are those of the autonumber text dialog. The function decides
322 * whether the <B>OBJECT</B> has to be renumberd, ignored or taken care of when
323 * renumbering all other objects.
324 * \return one of these integer values: <B>AUTONUMBER_IGNORE</B>,
325 * <B>AUTONUMBER_RESPECT</B> or <B>AUTONUMBER_RENUMBER</B> and the current number
326 * of the text object in <B>*number</B>.
328 gint
autonumber_match(AUTONUMBER_TEXT
*autotext
, OBJECT
*o_current
, gint
*number
)
330 gint i
, len
, isnumbered
=1;
331 const gchar
*str
= NULL
;
333 len
= strlen(autotext
->current_searchtext
);
334 /* first find out whether we can ignore that object */
335 if (o_current
->type
!= OBJ_TEXT
) /* text object */
336 return AUTONUMBER_IGNORE
;
338 str
= o_text_get_string (autotext
->w_current
->toplevel
, o_current
);
340 if (!(strlen(str
) - len
> 0)
341 || !g_str_has_prefix(str
, autotext
->current_searchtext
))
342 return AUTONUMBER_IGNORE
;
344 /* the string object matches with its leading characters to the searchtext */
345 /* now look for the extension, either a number or the "?" */
346 if (g_str_has_suffix (str
,"?")) {
348 /* There must not be any character between the "?" and the searchtext */
349 if (strlen(str
) != len
+1)
350 return AUTONUMBER_IGNORE
;
353 if (!isdigit( (int) (str
[len
]) )) /* has at least one digit */
354 return AUTONUMBER_IGNORE
;
356 for (i
=len
+1; str
[i
]; i
++) /* and only digits */
357 if (!isdigit( (int) (str
[i
]) ))
358 return AUTONUMBER_IGNORE
;
361 /* we have six cases, 3 from focus multiplied by 2 selection cases */
362 if ((autotext
->root_page
|| autotext
->scope_number
== SCOPE_HIERARCHY
)
363 && (o_current
->selected
364 || autotext
->scope_number
== SCOPE_HIERARCHY
|| autotext
->scope_number
== SCOPE_PAGE
)
365 && (!isnumbered
|| (autotext
->scope_overwrite
)))
366 return AUTONUMBER_RENUMBER
;
369 && !(autotext
->scope_skip
== SCOPE_SELECTED
370 && !(o_current
->selected
) && autotext
->root_page
)) {
371 sscanf(&(str
[len
])," %d", number
);
372 return AUTONUMBER_RESPECT
; /* numbered objects which we don't renumber */
375 return AUTONUMBER_IGNORE
; /* unnumbered objects outside the focus */
379 /*! \brief Creates a list of already numbered objects and slots
380 * \par Function Description
381 * This function collects the used numbers of a single schematic page.
382 * The used element numbers are stored in a GList container
383 * inside the <B>AUTONUMBER_TEXT</B> struct.
384 * The slotting container is a little bit different. It stores free slots of
385 * multislotted symbols, that were used only partially.
386 * The criterias are derivated from the autonumber dialog entries.
388 void autonumber_get_used(GSCHEM_TOPLEVEL
*w_current
, AUTONUMBER_TEXT
*autotext
)
390 gint number
, numslots
, slotnr
, i
;
391 OBJECT
*o_current
, *o_parent
;
392 AUTONUMBER_SLOT
*slot
;
394 char *numslot_str
, *slot_str
;
397 for (iter
= s_page_objects (w_current
->toplevel
->page_current
);
399 iter
= g_list_next (iter
)) {
400 o_current
= iter
->data
;
401 if (autonumber_match(autotext
, o_current
, &number
) == AUTONUMBER_RESPECT
) {
402 /* check slot and maybe add it to the lists */
403 o_parent
= o_current
->attached_to
;
404 if (autotext
->slotting
&& o_parent
!= NULL
) {
405 /* check for slotted symbol */
407 o_attrib_search_object_attribs_by_name (o_parent
, "numslots", 0);
408 if (numslot_str
!= NULL
) {
409 sscanf(numslot_str
," %d",&numslots
);
413 slot_str
= o_attrib_search_object_attribs_by_name (o_parent
, "slot", 0);
414 if (slot_str
== NULL
) {
415 s_log_message(_("slotted object without slot attribute may cause "
416 "problems when autonumbering slots\n"));
419 sscanf(slot_str
, " %d", &slotnr
);
420 slot
= g_new(AUTONUMBER_SLOT
,1);
421 slot
->number
= number
;
422 slot
->slotnr
= slotnr
;
423 slot
->symbolname
= o_parent
->complex_basename
;
426 slot_item
= g_list_find_custom(autotext
->used_slots
,
428 (GCompareFunc
) freeslot_compare
);
429 if (slot_item
!= NULL
) { /* duplicate slot in used_slots */
430 s_log_message(_("duplicate slot may cause problems: "
431 "[symbolname=%s, number=%d, slot=%d]\n"),
432 slot
->symbolname
, slot
->number
, slot
->slotnr
);
436 autotext
->used_slots
= g_list_insert_sorted(autotext
->used_slots
,
438 (GCompareFunc
) freeslot_compare
);
440 slot_item
= g_list_find_custom(autotext
->free_slots
,
442 (GCompareFunc
) freeslot_compare
);
443 if (slot_item
== NULL
) {
444 /* insert all slots to the list, except of the current one */
445 for (i
=1; i
<= numslots
; i
++) {
447 slot
= g_memdup(slot
, sizeof(AUTONUMBER_SLOT
));
449 autotext
->free_slots
= g_list_insert_sorted(autotext
->free_slots
,
451 (GCompareFunc
) freeslot_compare
);
456 g_free(slot_item
->data
);
457 autotext
->free_slots
= g_list_delete_link(autotext
->free_slots
, slot_item
);
464 /* put number into the used list */
465 autotext
->used_numbers
= g_list_insert_sorted(autotext
->used_numbers
,
466 GINT_TO_POINTER(number
),
467 (GCompareFunc
) autonumber_sort_numbers
);
473 /*! \brief Gets or generates free numbers for the autonumbering process.
474 * \par Function Description
475 * This function gets or generates new numbers for the <B>OBJECT o_current</B>.
476 * It uses the element numbers <B>used_numbers</B> and the list of the free slots
477 * <B>free_slots</B> of the <B>AUTONUMBER_TEXT</B> struct.
479 * The new number is returned into the <B>number</B> parameter.
480 * <B>slot</B> is set if autoslotting is active, else it is set to zero.
482 void autonumber_get_new_numbers(AUTONUMBER_TEXT
*autotext
, OBJECT
*o_current
,
483 gint
*number
, gint
*slot
)
486 gint new_number
, numslots
, i
;
487 AUTONUMBER_SLOT
*freeslot
;
488 OBJECT
*o_parent
= NULL
;
489 GList
*freeslot_item
;
492 new_number
= autotext
->startnum
;
494 /* Check for slots first */
495 /* 1. are there any unused slots in the database? */
496 o_parent
= o_current
->attached_to
;
497 if (autotext
->slotting
&& o_parent
!= NULL
) {
498 freeslot
= g_new(AUTONUMBER_SLOT
,1);
499 freeslot
->symbolname
= o_parent
->complex_basename
;
500 freeslot
->number
= 0;
501 freeslot
->slotnr
= 0;
502 freeslot_item
= g_list_find_custom(autotext
->free_slots
,
504 (GCompareFunc
) freeslot_compare
);
506 /* Yes! -> remove from database, apply it */
507 if (freeslot_item
!= NULL
) {
508 freeslot
= freeslot_item
->data
;
509 *number
= freeslot
->number
;
510 *slot
= freeslot
->slotnr
;
512 autotext
->free_slots
= g_list_delete_link(autotext
->free_slots
, freeslot_item
);
518 /* get a new number */
519 item
= autotext
->used_numbers
;
521 while (item
!= NULL
&& GPOINTER_TO_INT(item
->data
) < new_number
)
522 item
= g_list_next(item
);
524 if (item
== NULL
|| GPOINTER_TO_INT(item
->data
) > new_number
)
526 else /* new_number == item->data */
529 *number
= new_number
;
532 /* insert the new number to the used list */
533 autotext
->used_numbers
= g_list_insert_sorted(autotext
->used_numbers
,
534 GINT_TO_POINTER(new_number
),
535 (GCompareFunc
) autonumber_sort_numbers
);
537 /* 3. is o_current a slotted object ? */
538 if ((autotext
->slotting
) && o_parent
!= NULL
) {
540 o_attrib_search_object_attribs_by_name (o_parent
, "numslots", 0);
541 if (numslot_str
!= NULL
) {
542 sscanf(numslot_str
," %d",&numslots
);
545 /* Yes! -> new number and slot=1; add the other slots to the database */
547 for (i
=2; i
<=numslots
; i
++) {
548 freeslot
= g_new(AUTONUMBER_SLOT
,1);
549 freeslot
->symbolname
= o_parent
->complex_basename
;
550 freeslot
->number
= new_number
;
551 freeslot
->slotnr
= i
;
552 autotext
->free_slots
= g_list_insert_sorted(autotext
->free_slots
,
554 (GCompareFunc
) freeslot_compare
);
561 /** @brief Removes the number from the element.
563 * This function updates the text content of the \a o_current object.
565 * @param autotext Pointer to the state structure
566 * @param o_current Pointer to the object from which to remove the number
569 void autonumber_remove_number(AUTONUMBER_TEXT
* autotext
, OBJECT
*o_current
)
571 OBJECT
*o_parent
, *o_slot
;
575 /* replace old text */
576 str
= g_strdup_printf("%s?", autotext
->current_searchtext
);
577 o_text_set_string (autotext
->w_current
->toplevel
, o_current
, str
);
580 /* redraw the text */
581 o_invalidate (autotext
->w_current
, o_current
);
582 o_text_recreate(autotext
->w_current
->toplevel
, o_current
);
583 o_invalidate (autotext
->w_current
, o_current
);
585 /* remove the slot attribute if slotting is active */
586 if (autotext
->slotting
) {
587 /* get the slot attribute */
588 o_parent
= o_current
->attached_to
;
589 if (o_parent
!= NULL
) {
590 slot_str
= s_slot_search_slot (o_parent
, &o_slot
);
592 /* Only attempt to remove non-inherited slot attributes */
593 if (o_slot
!= NULL
&& !o_attrib_is_inherited (o_slot
)) {
594 /* delete the slot attribute */
595 o_selection_remove (autotext
->w_current
->toplevel
,
596 autotext
->w_current
->toplevel
->
597 page_current
->selection_list
, o_slot
);
598 o_delete (autotext
->w_current
, o_slot
);
602 autotext
->w_current
->toplevel
->page_current
->CHANGED
= 1;
605 /*! \brief Changes the number <B>OBJECT</B> element. Changes the slot attribute.
606 * \par Function Description
607 * This function updates the text content of the <B>o_current</B> object.
608 * If the <B>slot</B> value is not zero. It updates the slot attribut of the
609 * complex element that is also the parent object of the o_current element.
611 void autonumber_apply_new_text(AUTONUMBER_TEXT
* autotext
, OBJECT
*o_current
,
612 gint number
, gint slot
)
616 /* update the slot on the owning object */
617 str
= g_strdup_printf ("slot=%d", slot
);
618 o_slot_end (autotext
->w_current
, o_current
->attached_to
, str
);
621 /* replace old text */
622 str
= g_strdup_printf("%s%d", autotext
->current_searchtext
, number
);
623 o_text_set_string (autotext
->w_current
->toplevel
, o_current
, str
);
626 /* redraw the text */
627 o_invalidate (autotext
->w_current
, o_current
);
628 o_text_recreate(autotext
->w_current
->toplevel
, o_current
);
629 o_invalidate (autotext
->w_current
, o_current
);
630 autotext
->w_current
->toplevel
->page_current
->CHANGED
= 1;
634 /*! \brief Handles all the options of the autonumber text dialog
635 * \par Function Description
636 * This function is the master of all autonumber code. It receives the options of
637 * the the autonumber text dialog in an <B>AUTONUMBER_TEXT</B> structure.
638 * First it collects all pages of a hierarchical schematic.
639 * Second it gets all matching text elements for the searchtext.
640 * Then it renumbers all text elements of all schematic pages. The renumbering
641 * follows the rules of the parameters given in the autonumber text dialog.
643 void autonumber_text_autonumber(AUTONUMBER_TEXT
*autotext
)
646 GList
*searchtext_list
=NULL
;
647 GList
*text_item
, *obj_item
, *page_item
;
649 GSCHEM_TOPLEVEL
*w_current
;
652 gchar
*new_searchtext
;
653 gint i
, number
, slot
;
654 GList
*o_list
= NULL
;
657 w_current
= autotext
->w_current
;
658 autotext
->current_searchtext
= NULL
;
659 autotext
->root_page
= 1;
660 autotext
->used_numbers
= NULL
;
661 autotext
->free_slots
= NULL
;
662 autotext
->used_slots
= NULL
;
664 scope_text
= g_list_first(autotext
->scope_text
)->data
;
666 /* Step1: get all pages of the hierarchy */
667 pages
= s_hierarchy_traversepages(w_current
->toplevel
, HIERARCHY_NODUPS
);
669 /* g_list_foreach(pages, (GFunc) s_hierarchy_print_page, NULL); */
671 /* Step2: if searchtext has an asterisk at the end we have to find
672 all matching searchtextes.
674 Example: "refdes=*" will match each text that starts with "refdes="
675 and has a trailing "?" or a trailing number if the "all"-option is set.
676 We get a list of possible prefixes: refdes=R, refdes=C.
678 If there is only one search pattern, it becomes a single item
679 in the searchtext list */
681 if (strlen(scope_text
) == 0) {
682 s_log_message(_("No searchstring given in autonumber text.\n"));
685 else if (g_str_has_suffix(scope_text
,"?") == TRUE
) {
686 /* single searchtext, strip of the "?" */
687 searchtext
= g_strndup(scope_text
, strlen(scope_text
)-1);
688 searchtext_list
=g_list_append (searchtext_list
, searchtext
);
690 else if (g_str_has_suffix(scope_text
,"*") == TRUE
) {
691 /* strip of the "*" */
692 searchtext
= g_strndup(scope_text
, strlen(scope_text
)-1);
693 /* collect all the possible searchtexts in all pages of the hierarchy */
694 for (page_item
= pages
; page_item
!= NULL
; page_item
= g_list_next(page_item
)) {
695 s_page_goto(w_current
->toplevel
, page_item
->data
);
696 /* iterate over all objects an look for matching searchtext's */
697 for (iter
= s_page_objects (w_current
->toplevel
->page_current
);
699 iter
= g_list_next (iter
)) {
700 o_current
= iter
->data
;
701 if (o_current
->type
== OBJ_TEXT
) {
702 if (autotext
->scope_number
== SCOPE_HIERARCHY
703 || autotext
->scope_number
== SCOPE_PAGE
704 || ((autotext
->scope_number
== SCOPE_SELECTED
) && (o_current
->selected
))) {
705 const gchar
*str
= o_text_get_string (w_current
->toplevel
, o_current
);
706 if (g_str_has_prefix (str
, searchtext
)) {
707 /* the beginnig of the current text matches with the searchtext now */
708 /* strip of the trailing [0-9?] chars and add it too the searchtext */
709 for (i
= strlen (str
)-1;
710 (i
>= strlen(searchtext
))
712 || isdigit( (int) (str
[i
]) ));
716 new_searchtext
= g_strndup (str
, i
+1);
717 if (g_list_find_custom(searchtext_list
, new_searchtext
,
718 (GCompareFunc
) strcmp
) == NULL
) {
719 searchtext_list
= g_list_append(searchtext_list
, new_searchtext
);
722 g_free(new_searchtext
);
728 if (autotext
->scope_number
== SCOPE_SELECTED
|| autotext
->scope_number
== SCOPE_PAGE
)
729 break; /* search only in the first page */
734 s_log_message(_("No '*' or '?' given at the end of the autonumber text.\n"));
738 /* Step3: iterate over the search items in the list */
739 for (text_item
=searchtext_list
; text_item
!=NULL
; text_item
=g_list_next(text_item
)) {
740 autotext
->current_searchtext
= text_item
->data
;
741 /* printf("autonumber_text_autonumber: searchtext %s\n", autotext->current_searchtext); */
742 /* decide whether to renumber page by page or get a global used-list */
743 if (autotext
->scope_skip
== SCOPE_HIERARCHY
) { /* whole hierarchy database */
744 /* renumbering all means that no db is required */
745 if (!(autotext
->scope_number
== SCOPE_HIERARCHY
746 && autotext
->scope_overwrite
)) {
747 for (page_item
= pages
; page_item
!= NULL
; page_item
= g_list_next(page_item
)) {
748 autotext
->root_page
= (pages
->data
== page_item
->data
);
749 s_page_goto(w_current
->toplevel
, page_item
->data
);
750 autonumber_get_used(w_current
, autotext
);
755 /* renumber the elements */
756 for (page_item
= pages
; page_item
!= NULL
; page_item
= g_list_next(page_item
)) {
757 s_page_goto(w_current
->toplevel
, page_item
->data
);
758 autotext
->root_page
= (pages
->data
== page_item
->data
);
759 /* build a page database if we're numbering pagebypage or selection only*/
760 if (autotext
->scope_skip
== SCOPE_PAGE
|| autotext
->scope_skip
== SCOPE_SELECTED
) {
761 autonumber_get_used(w_current
, autotext
);
764 /* RENUMBER CODE FOR ONE PAGE AND ONE SEARCHTEXT*/
765 /* 1. get objects to renumber */
766 for (iter
= s_page_objects (w_current
->toplevel
->page_current
);
768 iter
= g_list_next (iter
)) {
769 o_current
= iter
->data
;
770 if (autonumber_match(autotext
, o_current
, &number
) == AUTONUMBER_RENUMBER
) {
771 /* put number into the used list */
772 o_list
= g_list_append(o_list
, o_current
);
776 /* 2. sort object list */
777 switch (autotext
->order
) {
778 case AUTONUMBER_SORT_YX
:
779 o_list
=g_list_sort(o_list
, autonumber_sort_yx
);
781 case AUTONUMBER_SORT_YX_REV
:
782 o_list
=g_list_sort(o_list
, autonumber_sort_yx_rev
);
784 case AUTONUMBER_SORT_XY
:
785 o_list
=g_list_sort(o_list
, autonumber_sort_xy
);
787 case AUTONUMBER_SORT_XY_REV
:
788 o_list
=g_list_sort(o_list
, autonumber_sort_xy_rev
);
790 case AUTONUMBER_SORT_DIAGONAL
:
791 o_list
=g_list_sort(o_list
, autonumber_sort_diagonal
);
794 ; /* unsorted file order */
797 /* 3. renumber/reslot the objects */
798 for(obj_item
=o_list
; obj_item
!= NULL
; obj_item
=g_list_next(obj_item
)) {
799 o_current
= obj_item
->data
;
800 if(autotext
->removenum
) {
801 autonumber_remove_number(autotext
, o_current
);
803 /* get valid numbers from the database */
804 autonumber_get_new_numbers(autotext
, o_current
, &number
, &slot
);
805 /* and apply it. TODO: join these two functions */
806 autonumber_apply_new_text(autotext
, o_current
, number
, slot
);
812 /* destroy the page database */
813 if (autotext
->scope_skip
== SCOPE_PAGE
814 || autotext
->scope_skip
== SCOPE_SELECTED
)
815 autonumber_clear_database(autotext
);
817 if (autotext
->scope_number
== SCOPE_SELECTED
818 || autotext
->scope_number
== SCOPE_PAGE
)
819 break; /* only renumber the parent page (the first page) */
821 autonumber_clear_database(autotext
); /* cleanup */
824 /* cleanup and redraw all*/
825 g_list_foreach(searchtext_list
, (GFunc
) g_free
, NULL
);
826 g_list_free(searchtext_list
);
827 s_page_goto(w_current
->toplevel
, pages
->data
); /* go back to the root page */
828 o_invalidate_all (w_current
);
830 o_undo_savestate(w_current
, UNDO_ALL
);
833 /* ***** UTILITY GUI FUNCTIONS (move to a separate file in the future?) **** */
835 /** @brief Finds a widget by its name given a pointer to its parent.
837 * @param widget Pointer to the parent widget.
838 * @param widget_name Name of the widget.
839 * @return Pointer to the widget or NULL if not found. */
840 GtkWidget
* lookup_widget(GtkWidget
*widget
, const gchar
*widget_name
)
842 GtkWidget
*found_widget
;
844 found_widget
= (GtkWidget
*) g_object_get_data(G_OBJECT(widget
),
850 /*! \brief Put the icons and the text into the sortorder combobox
851 * \par Function Description
852 * Load all bitmaps for the combobox and store them together with the label
855 void autonumber_sortorder_create(GSCHEM_TOPLEVEL
*w_current
, GtkWidget
*sort_order
)
859 GtkCellRenderer
*renderer
;
864 gchar
*filenames
[] = {"gschem-diagonal.png",
865 "gschem-top2bottom.png", "gschem-bottom2top.png",
866 "gschem-left2right.png", "gschem-right2left.png",
867 "gschem-fileorder.png",
869 gchar
*names
[] = {N_("Diagonal"),
870 N_("Top to bottom"), N_("Bottom to top"),
871 N_("Left to right"), N_("Right to left"),
876 store
= gtk_list_store_new(2, G_TYPE_STRING
, GDK_TYPE_PIXBUF
);
878 for (i
=0; filenames
[i
] != NULL
; i
++) {
879 path
=g_build_filename(w_current
->toplevel
->bitmap_directory
,
881 pixbuf
= gdk_pixbuf_new_from_file(path
, &error
);
883 gtk_list_store_append(store
, &iter
);
884 gtk_list_store_set(store
, &iter
,
890 gtk_combo_box_set_model(GTK_COMBO_BOX(sort_order
), GTK_TREE_MODEL(store
));
891 renderer
= gtk_cell_renderer_text_new ();
893 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (sort_order
),
895 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (sort_order
),
896 renderer
, "text", 0, NULL
);
897 renderer
= gtk_cell_renderer_pixbuf_new();
898 g_object_set(G_OBJECT(renderer
), "xpad", 5, "ypad", 5, NULL
);
900 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (sort_order
),
902 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (sort_order
),
903 renderer
, "pixbuf", 1, NULL
);
906 /* ***** STATE STRUCT HANDLING (interface between GUI and backend code) **** */
908 /** @brief Adds a line to the search text history list
910 * Function makes sure that: 1) There are no duplicates in the list and 2) the
911 * last search text is always at the top of the list.
913 GList
*autonumber_history_add(GList
*history
, gchar
*text
)
915 /* Search for this text in history and delete it (so we don't have
916 * duplicate entries) */
922 if(!strcmp(text
, cur
->data
)) {
923 history
=g_list_remove_link(history
, cur
);
929 cur
=g_list_next(cur
);
932 /* Add the new text at the beginning of the list */
934 history
=g_list_prepend(history
, text
);
936 /* Truncate history */
937 while(g_list_length(history
) > HISTORY_LENGTH
) {
938 GList
*last
= g_list_last(history
);
940 history
= g_list_remove_link(history
, last
);
949 /** @brief Allocate and initialize the state structure
951 * @return Pointer to the allocated structure or NULL on error.
953 AUTONUMBER_TEXT
*autonumber_init_state()
955 AUTONUMBER_TEXT
*autotext
;
957 /* Default contents of the combo box history */
958 gchar
*default_text
[] = {
976 autotext
= g_new(AUTONUMBER_TEXT
, 1);
978 if(autotext
==NULL
) return NULL
;
980 autotext
->scope_text
= NULL
;
983 autotext
->scope_text
=g_list_append(autotext
->scope_text
,
988 autotext
->scope_skip
= SCOPE_PAGE
;
989 autotext
->scope_number
= SCOPE_SELECTED
;
991 autotext
->scope_overwrite
= 0;
992 autotext
->order
= AUTONUMBER_SORT_DIAGONAL
;
994 autotext
->startnum
=1;
996 autotext
->removenum
=0;
997 autotext
->slotting
=0;
999 autotext
->dialog
= NULL
;
1004 /** @brief Restore the settings for the autonumber text dialog
1006 * @param autotext Pointer to the state struct.
1008 void autonumber_set_state(AUTONUMBER_TEXT
*autotext
)
1011 GtkTreeModel
*model
;
1015 /* Search text history */
1016 widget
= lookup_widget(autotext
->dialog
, "scope_text");
1018 /* Simple way to clear the ComboBox. Owen from #gtk+ says:
1020 * Yeah, it's just slightly "shady" ... if you want to stick to fully
1021 * advertised API, you need to remember how many rows you added and
1022 * use gtk_combo_box_remove_text() */
1024 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(widget
));
1025 gtk_list_store_clear(GTK_LIST_STORE(model
));
1027 for (el
= autotext
->scope_text
; el
!= NULL
; el
=g_list_next(el
)) {
1028 gtk_combo_box_append_text(GTK_COMBO_BOX(widget
), el
->data
);
1031 widget
= gtk_bin_get_child(GTK_BIN(widget
));
1032 gtk_entry_set_text(GTK_ENTRY(widget
), g_list_first(autotext
->scope_text
)->data
);
1034 widget
= lookup_widget(autotext
->dialog
, "scope_skip");
1035 gtk_combo_box_set_active(GTK_COMBO_BOX(widget
),
1036 autotext
->scope_skip
);
1038 widget
= lookup_widget(autotext
->dialog
, "scope_number");
1039 gtk_combo_box_set_active(GTK_COMBO_BOX(widget
),
1040 autotext
->scope_number
);
1042 widget
= lookup_widget(autotext
->dialog
, "scope_overwrite");
1043 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
1044 autotext
->scope_overwrite
);
1047 widget
= lookup_widget(autotext
->dialog
, "opt_startnum");
1048 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget
),
1049 autotext
->startnum
);
1051 widget
= lookup_widget(autotext
->dialog
, "sort_order");
1052 gtk_combo_box_set_active(GTK_COMBO_BOX(widget
), autotext
->order
);
1054 widget
= lookup_widget(autotext
->dialog
, "opt_removenum");
1055 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
1056 autotext
->removenum
);
1058 widget
= lookup_widget(autotext
->dialog
, "opt_slotting");
1059 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
1060 autotext
->slotting
);
1063 /** @brief Get the settings from the autonumber text dialog
1065 * Get the settings from the autonumber text dialog and store it in the
1066 * <B>AUTONUMBER_TEXT</B> structure.
1068 * @param autotext Pointer to the state struct.
1070 void autonumber_get_state(AUTONUMBER_TEXT
*autotext
)
1077 /* Search text history */
1078 widget
= lookup_widget(autotext
->dialog
, "scope_text");
1079 widget
= gtk_bin_get_child(GTK_BIN(widget
));
1080 text
= g_strdup(gtk_entry_get_text( GTK_ENTRY(widget
)));
1082 autotext
->scope_text
=autonumber_history_add(autotext
->scope_text
, text
);
1084 widget
= lookup_widget(autotext
->dialog
, "scope_skip");
1085 autotext
->scope_skip
= gtk_combo_box_get_active( GTK_COMBO_BOX(widget
) );
1087 widget
= lookup_widget(autotext
->dialog
, "scope_number");
1088 autotext
->scope_number
= gtk_combo_box_get_active(GTK_COMBO_BOX(widget
) );
1090 widget
= lookup_widget(autotext
->dialog
, "scope_overwrite");
1091 autotext
->scope_overwrite
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
1094 widget
= lookup_widget(autotext
->dialog
, "sort_order");
1095 autotext
->order
= gtk_combo_box_get_active(GTK_COMBO_BOX(widget
));
1098 widget
= lookup_widget(autotext
->dialog
, "opt_startnum");
1099 autotext
->startnum
=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget
));
1101 widget
= lookup_widget(autotext
->dialog
, "opt_removenum");
1102 autotext
->removenum
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
1104 widget
= lookup_widget(autotext
->dialog
, "opt_slotting");
1105 autotext
->slotting
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
1108 /* ***** CALLBACKS (functions that get called directly from the GTK) ******* */
1110 /*! \brief response callback for the autonumber text dialog
1111 * \par Function Description
1112 * The function just closes the dialog if the close button is pressed or the
1113 * user closes the dialog window.
1114 * Triggering the apply button will call the autonumber action functions.
1116 void autonumber_text_response(GtkWidget
* widget
, gint response
,
1117 AUTONUMBER_TEXT
*autotext
)
1120 case GTK_RESPONSE_ACCEPT
:
1121 autonumber_get_state(autotext
);
1122 if (autotext
->removenum
== TRUE
&& autotext
->scope_overwrite
== FALSE
) {
1123 /* temporarly set the overwrite flag */
1124 autotext
->scope_overwrite
= TRUE
;
1125 autonumber_text_autonumber(autotext
);
1126 autotext
->scope_overwrite
= FALSE
;
1129 autonumber_text_autonumber(autotext
);
1132 case GTK_RESPONSE_REJECT
:
1133 case GTK_RESPONSE_DELETE_EVENT
:
1134 gtk_widget_destroy(autotext
->dialog
);
1135 autotext
->dialog
= NULL
;
1138 printf("ERROR: autonumber_text_response(): strange signal %d\n",response
);
1143 /** @brief Callback that activates or deactivates "overwrite existing numbers"
1146 * This gets called each time "remove numbers" check box gets clicked.
1148 void autonumber_removenum_toggled(GtkWidget
* opt_removenum
,
1149 AUTONUMBER_TEXT
*autotext
)
1151 GtkWidget
*scope_overwrite
;
1153 scope_overwrite
=lookup_widget(autotext
->dialog
, "scope_overwrite");
1155 /* toggle activity of scope overwrite with respect to removenum */
1156 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(opt_removenum
))) {
1157 gtk_widget_set_sensitive(scope_overwrite
, 0);
1159 gtk_widget_set_sensitive(scope_overwrite
, 1);
1164 /* ***** DIALOG SET-UP ***************************************************** */
1166 /** @brief Creates the autonumber text dialog.
1168 * Dialog is not shown. No callbacks are registered. This is basically
1169 * unmodified code returned by Glade.
1171 * Only modification was the following substitution:
1173 * %s/create_pixmap (autonumber_text, "\(.*\)")/autonumber_create_pixmap("gschem-\1", w_current)/
1175 * and addition of the "w_current" parameter.
1177 * @param w_current Pointer to the top level struct.
1178 * @return Pointer to the dialog window.
1180 GtkWidget
* autonumber_create_dialog(GSCHEM_TOPLEVEL
*w_current
)
1182 GtkWidget
*autonumber_text
;
1184 GtkWidget
*alignment1
;
1188 GtkWidget
*scope_text
;
1191 GtkWidget
*scope_number
;
1192 GtkWidget
*scope_skip
;
1193 GtkWidget
*scope_overwrite
;
1195 GtkWidget
*alignment3
;
1200 GtkObject
*opt_startnum_adj
;
1201 GtkWidget
*opt_startnum
;
1202 GtkWidget
*sort_order
;
1203 GtkWidget
*opt_removenum
;
1204 GtkWidget
*opt_slotting
;
1208 autonumber_text
= gschem_dialog_new_with_buttons(_("Autonumber text"),
1209 GTK_WINDOW(w_current
->main_window
),
1211 "autonumber", w_current
,
1213 GTK_RESPONSE_REJECT
,
1215 GTK_RESPONSE_ACCEPT
,
1217 /* Set the alternative button order (ok, cancel, help) for other systems */
1218 gtk_dialog_set_alternative_button_order(GTK_DIALOG(autonumber_text
),
1219 GTK_RESPONSE_ACCEPT
,
1220 GTK_RESPONSE_REJECT
,
1223 gtk_window_position (GTK_WINDOW (autonumber_text
),
1226 gtk_container_border_width(GTK_CONTAINER(autonumber_text
),
1227 DIALOG_BORDER_SPACING
);
1228 vbox1
= GTK_DIALOG(autonumber_text
)->vbox
;
1229 gtk_box_set_spacing(GTK_BOX(vbox1
), DIALOG_V_SPACING
);
1232 label1
= gtk_label_new (_("<b>Scope</b>"));
1233 gtk_label_set_use_markup (GTK_LABEL (label1
), TRUE
);
1234 gtk_misc_set_alignment (GTK_MISC(label1
), 0, 0);
1235 gtk_box_pack_start (GTK_BOX(vbox1
), label1
, TRUE
, TRUE
, 0);
1236 gtk_widget_show (label1
);
1238 alignment1
= gtk_alignment_new (0, 0, 1, 1);
1239 gtk_widget_show (alignment1
);
1240 gtk_box_pack_start (GTK_BOX (vbox1
), alignment1
, TRUE
, TRUE
, 0);
1241 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1
),
1242 0, 0, DIALOG_INDENTATION
, 0);
1244 vbox3
= gtk_vbox_new (FALSE
, 0);
1245 gtk_widget_show (vbox3
);
1246 gtk_container_add (GTK_CONTAINER (alignment1
), vbox3
);
1248 table1
= gtk_table_new (3, 2, FALSE
);
1249 gtk_widget_show (table1
);
1250 gtk_box_pack_start (GTK_BOX (vbox3
), table1
, TRUE
, TRUE
, 0);
1251 gtk_table_set_row_spacings (GTK_TABLE (table1
), DIALOG_V_SPACING
);
1252 gtk_table_set_col_spacings (GTK_TABLE (table1
), DIALOG_H_SPACING
);
1254 label4
= gtk_label_new (_("Search for:"));
1255 gtk_widget_show (label4
);
1256 gtk_table_attach (GTK_TABLE (table1
), label4
, 0, 1, 0, 1,
1257 (GtkAttachOptions
) (GTK_FILL
),
1258 (GtkAttachOptions
) (0), 0, 0);
1259 gtk_misc_set_alignment (GTK_MISC (label4
), 0, 0.5);
1261 scope_text
= gtk_combo_box_entry_new_text ();
1262 gtk_entry_set_activates_default(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(scope_text
))), TRUE
);
1263 gtk_widget_show (scope_text
);
1264 gtk_table_attach (GTK_TABLE (table1
), scope_text
, 1, 2, 0, 1,
1265 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1266 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1268 label8
= gtk_label_new (_("Autonumber text in:"));
1269 gtk_widget_show (label8
);
1270 gtk_table_attach (GTK_TABLE (table1
), label8
, 0, 1, 1, 2,
1271 (GtkAttachOptions
) (GTK_FILL
),
1272 (GtkAttachOptions
) (0), 0, 0);
1273 gtk_misc_set_alignment (GTK_MISC (label8
), 0, 0.5);
1275 label6
= gtk_label_new (_("Skip numbers found in:"));
1276 gtk_widget_show (label6
);
1277 gtk_table_attach (GTK_TABLE (table1
), label6
, 0, 1, 2, 3,
1278 (GtkAttachOptions
) (GTK_FILL
),
1279 (GtkAttachOptions
) (0), 0, 0);
1280 gtk_misc_set_alignment (GTK_MISC (label6
), 0, 0.5);
1282 scope_number
= gtk_combo_box_new_text ();
1283 gtk_widget_show (scope_number
);
1284 gtk_table_attach (GTK_TABLE (table1
), scope_number
, 1, 2, 1, 2,
1285 (GtkAttachOptions
) (GTK_FILL
),
1286 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1287 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_number
), _("Selected objects"));
1288 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_number
), _("Current page"));
1289 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_number
), _("Whole hierarchy"));
1291 scope_skip
= gtk_combo_box_new_text ();
1292 gtk_widget_show (scope_skip
);
1293 gtk_table_attach (GTK_TABLE (table1
), scope_skip
, 1, 2, 2, 3,
1294 (GtkAttachOptions
) (GTK_FILL
),
1295 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1296 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_skip
), _("Selected objects"));
1297 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_skip
), _("Current page"));
1298 gtk_combo_box_append_text (GTK_COMBO_BOX (scope_skip
), _("Whole hierarchy"));
1300 scope_overwrite
= gtk_check_button_new_with_mnemonic (_("Overwrite existing numbers"));
1301 gtk_widget_show (scope_overwrite
);
1302 gtk_box_pack_start (GTK_BOX (vbox3
), scope_overwrite
, FALSE
, FALSE
, 6);
1304 /* Options section */
1305 label3
= gtk_label_new (_("<b>Options</b>"));
1306 gtk_label_set_use_markup (GTK_LABEL (label3
), TRUE
);
1307 gtk_misc_set_alignment(GTK_MISC(label3
), 0, 0);
1308 gtk_widget_show (label3
);
1309 gtk_box_pack_start(GTK_BOX(vbox1
), label3
, TRUE
, TRUE
, 0);
1311 alignment3
= gtk_alignment_new (0, 0, 1, 1);
1312 gtk_widget_show (alignment3
);
1313 gtk_box_pack_start(GTK_BOX(vbox1
), alignment3
, TRUE
, TRUE
, 0);
1314 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3
),
1315 0, 0, DIALOG_INDENTATION
, 0);
1317 vbox4
= gtk_vbox_new (FALSE
, 3);
1318 gtk_widget_show (vbox4
);
1319 gtk_container_add (GTK_CONTAINER (alignment3
), vbox4
);
1321 table3
= gtk_table_new (2, 2, FALSE
);
1322 gtk_widget_show (table3
);
1323 gtk_box_pack_start (GTK_BOX (vbox4
), table3
, TRUE
, TRUE
, 0);
1324 gtk_table_set_row_spacings (GTK_TABLE (table3
), DIALOG_V_SPACING
);
1325 gtk_table_set_col_spacings (GTK_TABLE (table3
), DIALOG_H_SPACING
);
1327 label12
= gtk_label_new (_("Starting number:"));
1328 gtk_widget_show (label12
);
1329 gtk_table_attach (GTK_TABLE (table3
), label12
, 0, 1, 0, 1,
1330 (GtkAttachOptions
) (GTK_FILL
),
1331 (GtkAttachOptions
) (0), 0, 0);
1332 gtk_misc_set_alignment (GTK_MISC (label12
), 0, 0.5);
1334 label13
= gtk_label_new (_("Sort order:"));
1335 gtk_widget_show (label13
);
1336 gtk_table_attach (GTK_TABLE (table3
), label13
, 0, 1, 1, 2,
1337 (GtkAttachOptions
) (GTK_FILL
),
1338 (GtkAttachOptions
) (0), 0, 0);
1339 gtk_misc_set_alignment (GTK_MISC (label13
), 0, 0.5);
1341 opt_startnum_adj
= gtk_adjustment_new (1, 0, 10000, 1, 10, 10);
1342 opt_startnum
= gtk_spin_button_new (GTK_ADJUSTMENT (opt_startnum_adj
), 1, 0);
1343 gtk_entry_set_activates_default(GTK_ENTRY(opt_startnum
), TRUE
);
1344 gtk_widget_show (opt_startnum
);
1345 gtk_table_attach (GTK_TABLE (table3
), opt_startnum
, 1, 2, 0, 1,
1346 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1347 (GtkAttachOptions
) (0), 0, 0);
1349 sort_order
= gtk_combo_box_new();
1350 gtk_widget_show (sort_order
);
1351 gtk_table_attach (GTK_TABLE (table3
), sort_order
, 1, 2, 1, 2,
1352 (GtkAttachOptions
) (GTK_FILL
),
1353 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1355 opt_removenum
= gtk_check_button_new_with_mnemonic (_("Remove numbers"));
1356 gtk_widget_show (opt_removenum
);
1357 gtk_box_pack_start (GTK_BOX (vbox4
), opt_removenum
, FALSE
, FALSE
, 0);
1359 opt_slotting
= gtk_check_button_new_with_mnemonic (_("Automatic slotting"));
1360 gtk_widget_show (opt_slotting
);
1361 gtk_box_pack_start (GTK_BOX (vbox4
), opt_slotting
, FALSE
, FALSE
, 0);
1363 /* Store pointers to all widgets, for use by lookup_widget(). */
1364 GLADE_HOOKUP_OBJECT (autonumber_text
, scope_text
, "scope_text");
1365 GLADE_HOOKUP_OBJECT (autonumber_text
, scope_number
, "scope_number");
1366 GLADE_HOOKUP_OBJECT (autonumber_text
, scope_skip
, "scope_skip");
1367 GLADE_HOOKUP_OBJECT (autonumber_text
, scope_overwrite
, "scope_overwrite");
1368 GLADE_HOOKUP_OBJECT (autonumber_text
, opt_startnum
, "opt_startnum");
1369 GLADE_HOOKUP_OBJECT (autonumber_text
, sort_order
, "sort_order");
1370 GLADE_HOOKUP_OBJECT (autonumber_text
, opt_removenum
, "opt_removenum");
1371 GLADE_HOOKUP_OBJECT (autonumber_text
, opt_slotting
, "opt_slotting");
1373 return autonumber_text
;
1376 /*! \brief Create or restore the autonumber text dialog
1378 * If the function is called the first time the dialog is created.
1379 * If the dialog is only in background it is moved to the foreground.
1381 * @param w_current Pointer to the top level struct
1383 void autonumber_text_dialog(GSCHEM_TOPLEVEL
*w_current
)
1385 static AUTONUMBER_TEXT
*autotext
= NULL
;
1387 GtkWidget
*opt_removenum
= NULL
;
1388 GtkWidget
*sort_order
= NULL
;
1390 if(autotext
== NULL
) {
1391 /* first call of this function, init dialog structure */
1392 autotext
=autonumber_init_state();
1395 /* set the GSCHEM_TOPLEVEL always. Can it be changed between the calls??? */
1396 autotext
->w_current
= w_current
;
1398 if(autotext
->dialog
== NULL
) {
1399 /* Dialog is not currently displayed - create it */
1401 autotext
->dialog
= autonumber_create_dialog(w_current
);
1403 opt_removenum
= lookup_widget(autotext
->dialog
, "opt_removenum");
1404 sort_order
= lookup_widget(autotext
->dialog
, "sort_order");
1406 autonumber_sortorder_create(w_current
, sort_order
);
1408 gtk_dialog_set_default_response (GTK_DIALOG (autotext
->dialog
),
1409 GTK_RESPONSE_ACCEPT
);
1411 gtk_signal_connect(GTK_OBJECT(autotext
->dialog
), "response",
1412 GTK_SIGNAL_FUNC(autonumber_text_response
),
1415 gtk_signal_connect(GTK_OBJECT(opt_removenum
),
1417 GTK_SIGNAL_FUNC(autonumber_removenum_toggled
),
1420 autonumber_set_state(autotext
);
1422 gtk_widget_show_all(autotext
->dialog
);
1425 /* if the dialog is in the background or minimized: show it */
1426 gtk_window_present(GTK_WINDOW(autotext
->dialog
));