1 /* Lepton EDA Schematic Capture
2 * Copyright (C) 2013 Ales Hvezda
3 * Copyright (C) 2013-2015 gEDA Contributors
4 * Copyright (C) 2017-2021 Lepton EDA Contributors
5 *
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.
10 *
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.
15 *
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
19 */
20 /*!
21 * \file x_newtext.c
22 *
23 * \brief A dialog box for adding new text to a schematic.
24 */
25
26 #include <config.h>
27
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
35
36 #include "gschem.h"
37 #include <gdk/gdkkeysyms.h>
38
39
40
41 #define TYPE_NEWTEXT (newtext_get_type())
42 #define NEWTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NEWTEXT, NewText))
43 #define NEWTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NEWTEXT, NewTextClass))
44 #define IS_NEWTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NEWTEXT))
45
46 typedef struct _NewTextClass NewTextClass;
47 typedef struct _NewText NewText;
48
49 struct _NewTextClass {
50 GschemDialogClass parent_class;
51 };
52
53 struct _NewText {
54 GschemDialog parent;
55
56 GtkWidget *aligncb;
57 GtkWidget *colorcb;
58 GtkWidget *rotatecb;
59 GtkWidget *textsizecb;
60 GtkWidget *text_view;
61 };
62
63
64
65 /*! \brief Handles the user response when apply is selected
66 *
67 * \par Function Description
68 * This function applies the text from the text entry dialog.
69 *
70 * \param [in] dialog The new text dialog
71 */
72 static void
dialog_response_apply(NewText * dialog)73 dialog_response_apply (NewText *dialog)
74 {
75 g_return_if_fail (dialog != NULL);
76
77 GschemToplevel *w_current = NULL;
78 g_object_get (GSCHEM_DIALOG (dialog), "gschem-toplevel", &w_current, NULL);
79 g_return_if_fail (w_current != NULL);
80
81 int size = w_current->text_size;
82
83 int align = LOWER_LEFT;
84 int color = TEXT_COLOR;
85 int rotate = 0;
86 gchar *string = NULL;
87 gchar *tmp = NULL;
88 GtkTextBuffer *textbuffer;
89 GtkTextIter start, end;
90 int value;
91
92 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(dialog->text_view));
93 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
94 string = gtk_text_iter_get_text (&start, &end);
95
96 if (string[0] == '\0' )
97 return;
98
99 switch(dialog->parent.w_current->text_caps) {
100 case(LOWER):
101 tmp = g_utf8_strdown (string, -1);
102 break;
103
104 case(UPPER):
105 tmp = g_utf8_strup (string, -1);
106 break;
107
108 case(BOTH):
109 default:
110 /* do nothing */
111 break;
112 }
113
114 value = x_colorcb_get_index (dialog->colorcb);
115 if (value >= 0) {
116 color = value;
117 }
118
119 value = gschem_alignment_combo_get_align (dialog->aligncb);
120 if (value >= 0) {
121 align = value;
122 }
123
124 value = gschem_integer_combo_box_get_value (dialog->textsizecb);
125 if (value > 0) {
126 size = value;
127 }
128
129 value = gschem_rotation_combo_get_angle (dialog->rotatecb);
130 if (value >= 0) {
131 rotate = value;
132 }
133
134 /* select the text, so you can continue immediatly writing the next text */
135 select_all_text_in_textview(GTK_TEXT_VIEW(dialog->text_view));
136 gtk_widget_grab_focus(dialog->text_view);
137
138 o_text_prepare_place (dialog->parent.w_current,
139 tmp == NULL ? string : tmp,
140 color,
141 align,
142 rotate,
143 size);
144
145 g_free (string);
146 g_free (tmp);
147 }
148
149
150
151 /*! \brief Handles the user response when cancel is selected
152 *
153 *
154 *
155 * \param [in,out] dialog The new text dialog
156 */
dialog_response_cancel(NewText * dialog)157 static void dialog_response_cancel(NewText *dialog)
158 {
159 i_callback_cancel (NULL, dialog->parent.w_current);
160 gtk_widget_destroy(dialog->parent.w_current->tiwindow);
161 dialog->parent.w_current->tiwindow=NULL;
162 }
163
164
165
166 /*! \brief Handles user responses from the new text dialog box
167
168 * \par Function Description
169 * Callback function for the text entry dialog.
170 *
171 * \param [in,out] widget The new text dialog
172 * \param [na] unused Unused parameter
173 */
text_input_dialog_response(NewText * dialog,gint response,gpointer unused)174 static void text_input_dialog_response(NewText *dialog, gint response, gpointer unused)
175 {
176 switch(response) {
177 case GTK_RESPONSE_APPLY:
178 dialog_response_apply(dialog);
179 break;
180 case GTK_RESPONSE_CLOSE:
181 case GTK_RESPONSE_DELETE_EVENT:
182 dialog_response_cancel(dialog);
183 break;
184 default:
185 printf("text_edit_dialog_response(): strange signal %d\n", response);
186 }
187 }
188
189
190 /*! \brief Initialize NewText class
191 *
192 * \par Function Description
193 *
194 * GType class initialiser for Multiattrib. We override our parent
195 * virtual class methods as needed and register our GObject properties.
196 *
197 * \param [in] klass
198 */
newtext_class_init(NewTextClass * klass)199 static void newtext_class_init(NewTextClass *klass)
200 {
201 }
202
203
204
205 /*! \brief Initialize NewText instance
206 *
207 * \param [in,out] dialog The new text dialog
208 */
newtext_init(NewText * dialog)209 static void newtext_init(NewText *dialog)
210 {
211 GtkWidget *alignment;
212 GtkWidget *vbox;
213 GtkWidget *label = NULL;
214 GtkWidget *viewport1 = NULL;
215 GtkWidget *scrolled_window = NULL;
216 PangoTabArray *tab_array;
217 int real_tab_width;
218 #ifdef ENABLE_GTK3
219 GtkWidget *grid;
220 #else
221 GtkWidget *table;
222 #endif
223
224 gtk_dialog_add_button (GTK_DIALOG (dialog),
225 GTK_STOCK_CLOSE,
226 GTK_RESPONSE_CLOSE);
227
228 gtk_dialog_add_button (GTK_DIALOG (dialog),
229 GTK_STOCK_APPLY,
230 GTK_RESPONSE_APPLY);
231
232 /* Set the alternative button order (ok, cancel, help) for other systems */
233 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
234 GTK_RESPONSE_APPLY,
235 GTK_RESPONSE_CLOSE,
236 -1);
237
238 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_NONE);
239
240 g_signal_connect (G_OBJECT (dialog), "response",
241 G_CALLBACK (text_input_dialog_response),
242 NULL);
243
244 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
245 GTK_RESPONSE_ACCEPT);
246
247 vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
248 gtk_box_set_spacing(GTK_BOX(vbox),DIALOG_V_SPACING);
249
250 #ifdef ENABLE_GTK3
251 grid = gtk_grid_new ();
252 gtk_grid_set_row_spacing (GTK_GRID (grid), DIALOG_V_SPACING);
253 gtk_grid_set_column_spacing (GTK_GRID (grid), DIALOG_H_SPACING);
254 #else
255 table = gtk_table_new(4, 2, FALSE);
256 gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING);
257 gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING);
258 #endif
259
260 label = gtk_label_new(_("<b>Text Properties</b>"));
261 gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
262 gtk_misc_set_alignment(GTK_MISC(label),0,0);
263 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
264
265 alignment = gtk_alignment_new(0,0,1,1);
266 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
267 DIALOG_INDENTATION, 0);
268 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
269
270 #ifdef ENABLE_GTK3
271 gtk_container_add (GTK_CONTAINER (alignment), grid);
272 #else
273 gtk_container_add(GTK_CONTAINER(alignment), table);
274 #endif
275
276 label = gtk_label_new (_("<b>Text Content</b>"));
277 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
278 gtk_misc_set_alignment(GTK_MISC(label),0,0);
279 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
280
281
282 label = gtk_label_new_with_mnemonic (_("Colo_r:"));
283 gtk_misc_set_alignment(GTK_MISC(label),0,0);
284 #ifdef ENABLE_GTK3
285 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
286 #else
287 gtk_table_attach (GTK_TABLE(table),
288 label,
289 0,
290 1,
291 0,
292 1,
293 GTK_FILL,
294 (GtkAttachOptions) 0,
295 0,
296 0);
297 #endif
298
299 dialog->colorcb = x_colorcb_new ();
300 x_colorcb_set_index(dialog->colorcb, TEXT_COLOR);
301
302 gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->colorcb);
303
304 #ifdef ENABLE_GTK3
305 gtk_grid_attach (GTK_GRID (grid), dialog->colorcb, 1, 0, 1, 1);
306 #else
307 gtk_table_attach_defaults(GTK_TABLE(table), dialog->colorcb, 1,2,0,1);
308 #endif
309
310 label = gtk_label_new_with_mnemonic (_("_Size:"));
311 gtk_misc_set_alignment(GTK_MISC(label),0,0);
312 #ifdef ENABLE_GTK3
313 gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
314 #else
315 gtk_table_attach (GTK_TABLE(table),
316 label,
317 0,
318 1,
319 1,
320 2,
321 GTK_FILL,
322 (GtkAttachOptions) 0,
323 0,
324 0);
325 #endif
326
327 dialog->textsizecb = gschem_integer_combo_box_new();
328
329 gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->textsizecb);
330
331 #ifdef ENABLE_GTK3
332 gtk_grid_attach (GTK_GRID (grid), dialog->textsizecb, 1, 1, 1, 1);
333 #else
334 gtk_table_attach_defaults(GTK_TABLE(table), dialog->textsizecb, 1,2,1,2);
335 #endif
336
337 label = gtk_label_new_with_mnemonic (_("Ali_gnment:"));
338 gtk_misc_set_alignment(GTK_MISC(label),0,0);
339 #ifdef ENABLE_GTK3
340 gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
341 #else
342 gtk_table_attach (GTK_TABLE(table),
343 label,
344 0,
345 1,
346 2,
347 3,
348 GTK_FILL,
349 (GtkAttachOptions) 0,
350 0,
351 0);
352 #endif
353
354 dialog->aligncb = gschem_alignment_combo_new ();
355 gschem_alignment_combo_set_align(dialog->aligncb, LOWER_LEFT);
356
357 gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->aligncb);
358
359 #ifdef ENABLE_GTK3
360 gtk_grid_attach (GTK_GRID (grid), dialog->aligncb, 1, 2, 1, 1);
361 #else
362 gtk_table_attach_defaults(GTK_TABLE(table), dialog->aligncb, 1,2,2,3);
363 #endif
364
365 label = gtk_label_new_with_mnemonic (_("Ro_tation:"));
366 gtk_misc_set_alignment(GTK_MISC(label),0,0);
367 #ifdef ENABLE_GTK3
368 gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
369 #else
370 gtk_table_attach (GTK_TABLE(table),
371 label,
372 0,
373 1,
374 3,
375 4,
376 GTK_FILL,
377 (GtkAttachOptions) 0,
378 0,
379 0);
380 #endif
381
382 dialog->rotatecb = gschem_rotation_combo_new ();
383 gschem_rotation_combo_set_angle(dialog->rotatecb, 0);
384
385 gtk_label_set_mnemonic_widget (GTK_LABEL (label), dialog->rotatecb);
386
387 #ifdef ENABLE_GTK3
388 gtk_grid_attach (GTK_GRID (grid), dialog->rotatecb, 1, 3, 1, 1);
389 #else
390 gtk_table_attach_defaults(GTK_TABLE(table), dialog->rotatecb, 1,2,3,4);
391 #endif
392
393 viewport1 = gtk_viewport_new (NULL, NULL);
394 gtk_widget_show (viewport1);
395
396 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
397 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
398 GTK_POLICY_AUTOMATIC,
399 GTK_POLICY_AUTOMATIC);
400 gtk_container_add (GTK_CONTAINER (viewport1), scrolled_window);
401 gtk_box_pack_start( GTK_BOX(vbox), viewport1, TRUE, TRUE, 0);
402
403 dialog->text_view = gtk_text_view_new();
404 gtk_text_view_set_editable(GTK_TEXT_VIEW(dialog->text_view), TRUE);
405 select_all_text_in_textview(GTK_TEXT_VIEW(dialog->text_view));
406
407 /* Set the tab width, using pango tab array */
408 /*! \bug FIXME: This doesn't work. Why? */
409 tab_array = pango_tab_array_new (1, TRUE);
410 real_tab_width = text_view_calculate_real_tab_width(GTK_TEXT_VIEW(dialog->text_view),
411 tab_in_chars);
412 if (real_tab_width >= 0) {
413 pango_tab_array_set_tab (tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
414 /* printf("Real tab width: %i\n", real_tab_width);*/
415 gtk_text_view_set_tabs (GTK_TEXT_VIEW (dialog->text_view),
416 tab_array);
417 }
418 else {
419 g_warning ("text_input_dialog: Impossible to set tab width.\n");
420 }
421
422 pango_tab_array_free (tab_array);
423 gtk_container_add(GTK_CONTAINER(scrolled_window), dialog->text_view);
424 }
425
426
427
428 /*! \brief Get/register NewText type.
429 */
newtext_get_type()430 GType newtext_get_type()
431 {
432 static GType type = 0;
433
434 if (type == 0) {
435 static const GTypeInfo info = {
436 sizeof(NewTextClass),
437 NULL, /* base_init */
438 NULL, /* base_finalize */
439 (GClassInitFunc) newtext_class_init,
440 NULL, /* class_finalize */
441 NULL, /* class_data */
442 sizeof(NewText),
443 0, /* n_preallocs */
444 (GInstanceInitFunc) newtext_init,
445 };
446
447 type = g_type_register_static (GSCHEM_TYPE_DIALOG,
448 "NewText",
449 &info,
450 (GTypeFlags) 0);
451 }
452
453 return type;
454 }
455
456
457
458 /*! \brief Open the dialog box to add new text
459 *
460 * \par Function Description
461 * This function creates or raises the modal text entry dialog
462 *
463 * \param [in] w_current The gschem toplevel
464 */
465 void
text_input_dialog(GschemToplevel * w_current)466 text_input_dialog (GschemToplevel *w_current)
467 {
468 if (w_current->tiwindow == NULL) {
469 /* dialog not created yet */
470 w_current->tiwindow =
471 GTK_WIDGET (g_object_new (TYPE_NEWTEXT,
472 /* GtkContainer */
473 "border-width", DIALOG_BORDER_SPACING,
474 /* GtkWindow */
475 "title", _("Add Text"),
476 "default-width", 320,
477 "default-height", 350,
478 "window-position", GTK_WIN_POS_MOUSE,
479 "modal", FALSE,
480 #ifndef ENABLE_GTK3
481 "allow-grow", TRUE,
482 "allow-shrink", FALSE,
483 /* GtkDialog */
484 "has-separator", TRUE,
485 #endif
486 /* GschemDialog */
487 "settings-name", "text-entry",
488 "gschem-toplevel", w_current,
489 NULL));
490
491 gtk_window_set_transient_for (GTK_WINDOW (w_current->tiwindow),
492 GTK_WINDOW (w_current->main_window));
493
494 gschem_integer_combo_box_set_model (NEWTEXT (w_current->tiwindow)->textsizecb,
495 gschem_toplevel_get_text_size_list_store (w_current));
496
497 gschem_integer_combo_box_set_value (NEWTEXT (w_current->tiwindow)->textsizecb,
498 w_current->text_size);
499
500 gtk_widget_show_all (w_current->tiwindow);
501 }
502 else {
503 /* dialog already created */
504 gtk_window_present (GTK_WINDOW(w_current->tiwindow));
505 }
506
507 /* always select the text in the entry */
508 select_all_text_in_textview (GTK_TEXT_VIEW (NEWTEXT (w_current->tiwindow)->text_view));
509 gtk_widget_grab_focus (NEWTEXT (w_current->tiwindow)->text_view);
510 }
511