missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / gschem_text_properties_dockable.c
blobe5a47d58d4a5f9c408f1e34becec34f1600bf96d
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 2013 Ales Hvezda
4 * Copyright (C) 2013-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /*!
21 * \file gschem_text_properties_dockable.c
23 * \brief A dockable for editing text properties
26 #include <config.h>
28 #include <stdio.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
36 #include "gschem.h"
37 #include <gdk/gdkkeysyms.h>
39 #include "../include/gschem_text_properties_dockable.h"
42 static void
43 adjust_focus (GschemDockable *parent);
45 static void
46 class_init (GschemTextPropertiesDockableClass *klass);
48 static GtkWidget*
49 create_text_content_section (GschemTextPropertiesDockable *widget);
51 static GtkWidget*
52 create_text_property_section (GschemTextPropertiesDockable *widget);
54 static void
55 dispose (GObject *object);
57 static GtkWidget *
58 create_widget (GschemDockable *parent);
60 static void
61 set_selection_adapter (GschemTextPropertiesDockable *widget, GschemSelectionAdapter *adapter);
63 static void
64 update_text_alignment_model (GschemTextPropertiesDockable *widget);
66 static void
67 update_text_alignment_widget (GschemTextPropertiesDockable *widget);
69 static void
70 update_text_color_model (GschemTextPropertiesDockable *widget);
72 static void
73 update_text_color_widget (GschemTextPropertiesDockable *widget);
75 static void
76 update_text_content_model (GschemTextPropertiesDockable *widget);
78 static void
79 update_text_content_widget (GschemTextPropertiesDockable *widget);
81 static void
82 update_text_rotation_model (GschemTextPropertiesDockable *widget);
84 static void
85 update_text_rotation_widget (GschemTextPropertiesDockable *widget);
89 /*! \brief Adjust widget focus for the convienence of the user
91 * If selecting one item, this function selects all the text content and gives
92 * focus to the text view. If multiple items are selected, this function gives
93 * focus to the color combo box.
95 * \param [in] widget This text properties widget
97 static void
98 adjust_focus (GschemDockable *parent)
100 GschemTextPropertiesDockable *widget =
101 GSCHEM_TEXT_PROPERTIES_DOCKABLE (parent);
103 g_return_if_fail (widget != NULL);
104 g_return_if_fail (widget->text_view != NULL);
105 g_return_if_fail (widget->colorcb != NULL);
107 if (gtk_widget_is_sensitive (widget->text_view)) {
108 select_all_text_in_textview (GTK_TEXT_VIEW (widget->text_view));
109 gtk_widget_grab_focus (widget->text_view);
111 else {
112 gtk_widget_grab_focus (widget->colorcb);
118 /*! \brief Get/register text properties widget type.
120 GType
121 gschem_text_properties_dockable_get_type ()
123 static GType type = 0;
125 if (type == 0) {
126 static const GTypeInfo info = {
127 sizeof(GschemTextPropertiesDockableClass),
128 NULL, /* base_init */
129 NULL, /* base_finalize */
130 (GClassInitFunc) class_init,
131 NULL, /* class_finalize */
132 NULL, /* class_data */
133 sizeof(GschemTextPropertiesDockable),
134 0, /* n_preallocs */
135 NULL, /* instance_init */
138 type = g_type_register_static (GSCHEM_TYPE_DOCKABLE,
139 "GschemTextPropertiesDockable",
140 &info,
144 return type;
149 /*! \private
150 * \brief Initialize the text properties widget class structure
152 * \param [in] klass
154 static void
155 class_init (GschemTextPropertiesDockableClass *klass)
157 GObjectClass *object_class;
159 g_return_if_fail (klass != NULL);
161 GSCHEM_DOCKABLE_CLASS (klass)->create_widget = create_widget;
162 GSCHEM_DOCKABLE_CLASS (klass)->post_present = adjust_focus;
164 object_class = G_OBJECT_CLASS (klass);
166 g_return_if_fail (object_class != NULL);
168 object_class->dispose = dispose;
173 /*! \private
174 * \brief Create the text content section widget
176 * \param [in] widget
177 * \return The new text content section widget
179 static GtkWidget*
180 create_text_content_section (GschemTextPropertiesDockable *widget)
182 GtkWidget *bbox = gtk_hbutton_box_new ();
183 GtkWidget *scrolled = gtk_scrolled_window_new (NULL, NULL);
184 GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
186 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
187 GTK_POLICY_AUTOMATIC,
188 GTK_POLICY_AUTOMATIC);
190 widget->text_view = gtk_text_view_new ();
192 gtk_text_view_set_editable (GTK_TEXT_VIEW (widget->text_view), TRUE);
194 /*! \bug FIXME: Set tab's width in the textview widget. */
195 /* See first the code in text_input_dialog and get it working before adding
196 * it here.
199 gtk_container_add (GTK_CONTAINER (scrolled), widget->text_view);
201 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
203 widget->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
205 g_signal_connect_swapped (G_OBJECT (widget->apply_button),
206 "clicked",
207 G_CALLBACK (update_text_content_model),
208 widget);
210 gtk_box_pack_start (GTK_BOX (bbox), /* box */
211 widget->apply_button, /* child */
212 TRUE, /* expand */
213 TRUE, /* fill */
214 0); /* padding */
216 gtk_box_set_spacing (GTK_BOX (vbox), DIALOG_V_SPACING);
218 gtk_box_pack_start (GTK_BOX (vbox), /* box */
219 scrolled, /* child */
220 TRUE, /* expand */
221 TRUE, /* fill */
222 0); /* padding */
224 gtk_box_pack_start (GTK_BOX (vbox), /* box */
225 bbox, /* child */
226 FALSE, /* expand */
227 TRUE, /* fill */
228 0); /* padding */
230 return gschem_dialog_misc_create_section_widget (_("<b>Text Content</b>"), vbox);
235 /*! \private
236 * \brief Create the text property section widget
238 * \param [in] widget
239 * \return The new text property section widget
241 static GtkWidget*
242 create_text_property_section (GschemTextPropertiesDockable *widget)
244 GtkWidget *label[4];
245 GtkWidget *table;
246 GtkWidget *editor[4];
248 label[0] = gschem_dialog_misc_create_property_label(_("Color:"));
249 label[1] = gschem_dialog_misc_create_property_label(_("Size:"));
250 label[2] = gschem_dialog_misc_create_property_label(_("Alignment:"));
251 label[3] = gschem_dialog_misc_create_property_label(_("Rotation:"));
253 editor[0] = widget->colorcb = x_colorcb_new ();
254 editor[1] = widget->textsizecb = gschem_integer_combo_box_new ();
255 editor[2] = widget->aligncb = gschem_alignment_combo_new();
256 editor[3] = widget->rotatecb = gschem_rotation_combo_new();
258 table = gschem_dialog_misc_create_property_table (label, editor, 4);
260 widget->bindings = g_slist_append (widget->bindings,
261 gschem_binding_integer_new ("text-size",
262 editor[1]));
264 g_signal_connect_swapped (G_OBJECT (widget->colorcb),
265 "changed",
266 G_CALLBACK (update_text_color_model),
267 widget);
269 g_signal_connect_swapped (G_OBJECT (widget->aligncb),
270 "changed",
271 G_CALLBACK (update_text_alignment_model),
272 widget);
274 g_signal_connect_swapped (G_OBJECT (widget->rotatecb),
275 "changed",
276 G_CALLBACK (update_text_rotation_model),
277 widget);
279 return gschem_dialog_misc_create_section_widget (_("<b>Text Properties</b>"), table);
284 /*! \private
285 * \brief Dispose
287 * \param [in] object The text edit widget to dispose
289 static void
290 dispose (GObject *object)
292 GschemTextPropertiesDockable *widget;
293 GschemTextPropertiesDockableClass *klass;
294 GObjectClass *parent_class;
296 g_return_if_fail (object != NULL);
298 widget = GSCHEM_TEXT_PROPERTIES_DOCKABLE (object);
300 set_selection_adapter (widget, NULL);
302 g_slist_foreach (widget->bindings, (GFunc) g_object_unref, NULL);
303 g_slist_free (widget->bindings);
304 widget->bindings = NULL;
306 /* lastly, chain up to the parent dispose */
308 klass = GSCHEM_TEXT_PROPERTIES_DOCKABLE_GET_CLASS (object);
309 g_return_if_fail (klass != NULL);
310 parent_class = g_type_class_peek_parent (klass);
311 g_return_if_fail (parent_class != NULL);
312 parent_class->dispose (object);
317 /*! \private
318 * \brief Create text property widgets and set up property change
319 * notifications
321 * \param [in,out] parent This dockable
323 static GtkWidget *
324 create_widget (GschemDockable *parent)
326 GschemTextPropertiesDockable *widget =
327 GSCHEM_TEXT_PROPERTIES_DOCKABLE (parent);
328 GschemToplevel *w_current = parent->w_current;
330 GtkWidget *scrolled;
331 GtkWidget *vbox;
332 GtkWidget *viewport;
334 scrolled = gtk_scrolled_window_new (NULL, NULL);
336 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
337 GTK_POLICY_NEVER,
338 GTK_POLICY_AUTOMATIC);
340 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
341 GTK_SHADOW_NONE);
343 viewport = gtk_viewport_new (NULL, NULL);
344 gtk_container_add (GTK_CONTAINER (scrolled), viewport);
346 gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport),
347 GTK_SHADOW_NONE);
349 vbox = gtk_vbox_new (FALSE, DIALOG_V_SPACING);
350 gtk_container_set_border_width (GTK_CONTAINER (vbox), DIALOG_BORDER_SPACING);
351 gtk_container_add (GTK_CONTAINER (viewport), vbox);
353 gtk_box_pack_start (GTK_BOX (vbox), /* box */
354 create_text_content_section (widget), /* child */
355 TRUE, /* expand */
356 TRUE, /* fill */
357 0); /* padding */
359 gtk_box_pack_start (GTK_BOX (vbox), /* box */
360 create_text_property_section (widget), /* child */
361 FALSE, /* expand */
362 FALSE, /* fill */
363 0); /* padding */
366 gschem_integer_combo_box_set_model (widget->textsizecb,
367 gschem_toplevel_get_text_size_list_store (w_current));
369 set_selection_adapter (widget,
370 gschem_toplevel_get_selection_adapter (w_current));
373 gtk_widget_show_all (scrolled);
374 return scrolled;
379 /*! \private
380 * \brief Set the selection that this widget manipulates
382 * \param [in,out] widget This widget
383 * \param [in] selection The selection to manipulate
385 static void
386 set_selection_adapter (GschemTextPropertiesDockable *widget, GschemSelectionAdapter *adapter)
388 g_return_if_fail (widget != NULL);
390 if (widget->adapter != NULL) {
391 g_signal_handlers_disconnect_by_func (widget->adapter,
392 G_CALLBACK (update_text_content_widget),
393 widget);
395 g_signal_handlers_disconnect_by_func (widget->adapter,
396 G_CALLBACK (update_text_rotation_widget),
397 widget);
399 g_signal_handlers_disconnect_by_func (widget->adapter,
400 G_CALLBACK (update_text_color_widget),
401 widget);
403 g_signal_handlers_disconnect_by_func (widget->adapter,
404 G_CALLBACK (update_text_alignment_widget),
405 widget);
407 g_object_unref (widget->adapter);
410 widget->adapter = adapter;
412 g_slist_foreach (widget->bindings,
413 (GFunc) gschem_binding_set_model_object,
414 adapter);
416 if (widget->adapter != NULL) {
417 g_object_ref (widget->adapter);
419 g_signal_connect_swapped (widget->adapter,
420 "notify::text-alignment",
421 G_CALLBACK (update_text_alignment_widget),
422 widget);
424 g_signal_connect_swapped (widget->adapter,
425 "notify::text-color",
426 G_CALLBACK (update_text_color_widget),
427 widget);
429 g_signal_connect_swapped (widget->adapter,
430 "notify::text-rotation",
431 G_CALLBACK (update_text_rotation_widget),
432 widget);
434 g_signal_connect_swapped (widget->adapter,
435 "notify::text-string",
436 G_CALLBACK (update_text_content_widget),
437 widget);
439 update_text_alignment_widget (widget);
440 update_text_color_widget (widget);
441 update_text_rotation_widget (widget);
442 update_text_content_widget (widget);
448 /*! \private
449 * \brief Update the text alignment in the model
451 * \param [in,out] widget This widget
453 static void
454 update_text_alignment_model (GschemTextPropertiesDockable *widget)
456 g_return_if_fail (widget != NULL);
457 g_return_if_fail (widget->aligncb != NULL);
459 if (widget->adapter != NULL) {
460 int alignment = gschem_alignment_combo_get_align (widget->aligncb);
462 if (alignment >= 0) {
463 gschem_selection_adapter_set_text_alignment (widget->adapter, alignment);
470 /*! \private
471 * \brief Update the value in the text alignment widget
473 * \param [in,out] widget This widget
475 static void
476 update_text_alignment_widget (GschemTextPropertiesDockable *widget)
478 g_return_if_fail (widget != NULL);
479 g_return_if_fail (widget->aligncb != NULL);
481 if (widget->adapter != NULL) {
482 int alignment = gschem_selection_adapter_get_text_alignment (widget->adapter);
484 g_signal_handlers_block_by_func (G_OBJECT (widget->aligncb),
485 G_CALLBACK (update_text_alignment_model),
486 widget);
488 gschem_alignment_combo_set_align (widget->aligncb, alignment);
490 g_signal_handlers_unblock_by_func (G_OBJECT (widget->aligncb),
491 G_CALLBACK (update_text_alignment_model),
492 widget);
494 gtk_widget_set_sensitive (GTK_WIDGET (widget->aligncb), (alignment != NO_SELECTION));
500 /*! \private
501 * \brief Update the text color value in the model
503 * \param [in,out] widget This widget
505 static void
506 update_text_color_model (GschemTextPropertiesDockable *widget)
508 g_return_if_fail (widget != NULL);
509 g_return_if_fail (widget->colorcb != NULL);
511 if (widget->adapter != NULL) {
512 int color = x_colorcb_get_index (widget->colorcb);
514 if (color >= 0) {
515 gschem_selection_adapter_set_text_color (widget->adapter, color);
522 /*! \private
523 * \brief Update the value in the object color widget
525 * \param [in,out] widget This widget
527 static void
528 update_text_color_widget (GschemTextPropertiesDockable *widget)
530 g_return_if_fail (widget != NULL);
531 g_return_if_fail (widget->colorcb != NULL);
533 if (widget->adapter != NULL) {
534 int color = gschem_selection_adapter_get_text_color (widget->adapter);
536 g_signal_handlers_block_by_func (G_OBJECT (widget->colorcb),
537 G_CALLBACK (update_text_color_model),
538 widget);
540 x_colorcb_set_index(widget->colorcb, color);
542 g_signal_handlers_unblock_by_func (G_OBJECT (widget->colorcb),
543 G_CALLBACK (update_text_color_model),
544 widget);
546 gtk_widget_set_sensitive (GTK_WIDGET (widget->colorcb), (color != NO_SELECTION));
552 /*! \private
553 * \brief Update the text string in the model
555 * \param [in,out] widget This widget
557 static void
558 update_text_content_model (GschemTextPropertiesDockable *widget)
560 g_return_if_fail (widget != NULL);
561 g_return_if_fail (widget->text_view != NULL);
563 if (widget->adapter != NULL) {
564 char *string;
565 GtkTextBuffer *buffer;
566 GtkTextIter start;
567 GtkTextIter end;
569 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget->text_view));
570 gtk_text_buffer_get_bounds (buffer, &start, &end);
571 string = gtk_text_iter_get_text (&start, &end);
573 if (string != NULL) {
574 gschem_selection_adapter_set_text_string (widget->adapter, string, widget->parent.w_current);
581 /*! \private
582 * \brief Update the value in the object color widget
584 * \param [in,out] widget This widget
586 static void
587 update_text_content_widget (GschemTextPropertiesDockable *widget)
589 g_return_if_fail (widget != NULL);
590 g_return_if_fail (widget->text_view != NULL);
592 if (widget->adapter != NULL) {
593 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget->text_view));
594 const char *string = gschem_selection_adapter_get_text_string (widget->adapter);
596 g_signal_handlers_block_by_func (G_OBJECT (widget->text_view),
597 G_CALLBACK (update_text_content_model),
598 widget);
600 if (string != NULL) {
601 gtk_text_buffer_set_text (buffer, string, -1);
603 else {
604 GtkTextIter start;
605 GtkTextIter end;
607 gtk_text_buffer_get_bounds (buffer, &start, &end);
608 gtk_text_buffer_delete (buffer, &start, &end);
611 g_signal_handlers_unblock_by_func (G_OBJECT (widget->text_view),
612 G_CALLBACK (update_text_content_model),
613 widget);
615 gtk_widget_set_sensitive (GTK_WIDGET (widget->text_view), (string != NULL));
616 gtk_widget_set_sensitive (GTK_WIDGET (widget->apply_button), (string != NULL));
622 /*! \private
623 * \brief Update the text rotation value in the model
625 * \param [in,out] widget This widget
627 static void
628 update_text_rotation_model (GschemTextPropertiesDockable *widget)
630 g_return_if_fail (widget != NULL);
631 g_return_if_fail (widget->rotatecb != NULL);
633 if (widget->adapter != NULL) {
634 int angle = gschem_rotation_combo_get_angle (widget->rotatecb);
636 if (angle >= 0) {
637 gschem_selection_adapter_set_text_rotation (widget->adapter, angle);
644 /*! \private
645 * \brief Update the value in the text rotation widget
647 * \param [in,out] widget This widget
649 static void
650 update_text_rotation_widget (GschemTextPropertiesDockable *widget)
652 g_return_if_fail (widget != NULL);
653 g_return_if_fail (widget->rotatecb != NULL);
655 if (widget->adapter != NULL) {
656 int angle = gschem_selection_adapter_get_text_rotation (widget->adapter);
658 g_signal_handlers_block_by_func (G_OBJECT (widget->rotatecb),
659 G_CALLBACK (update_text_rotation_model),
660 widget);
662 gschem_rotation_combo_set_angle (widget->rotatecb, angle);
664 g_signal_handlers_unblock_by_func (G_OBJECT (widget->rotatecb),
665 G_CALLBACK (update_text_rotation_model),
666 widget);
668 gtk_widget_set_sensitive (GTK_WIDGET (widget->rotatecb), (angle != NO_SELECTION));