GDS-Render v1.2.1
layer-selector.c
Go to the documentation of this file.
1/*
2 * GDSII-Converter
3 * Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
4 *
5 * This file is part of GDSII-Converter.
6 *
7 * GDSII-Converter is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * GDSII-Converter 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 GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
18 */
19
31#include <glib.h>
32#include <string.h>
33#include <stdio.h>
34#include <stdlib.h>
35
39
41 /* Parent */
42 GObject parent;
43 /* Own fields */
48 GtkListBox *list_box;
49
50 GtkTargetEntry dnd_target;
51
52 gpointer dummy[4];
53};
54
55G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT)
56
57/*
58 * Drag and drop code
59 * Original code from https://blog.gtk.org/2017/06/01/drag-and-drop-in-lists-revisited/
60 */
61
62static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
63{
64 GtkWidget *row;
65 GtkAllocation alloc;
66 cairo_surface_t *surface;
67 cairo_t *cr;
68 int x, y;
69 (void)data;
70
71 row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
72 gtk_widget_get_allocation(row, &alloc);
73 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
74 cr = cairo_create(surface);
75
76 gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-icon");
77 gtk_widget_draw(row, cr);
78 gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-icon");
79
80 gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y);
81 cairo_surface_set_device_offset(surface, -x, -y);
82 gtk_drag_set_icon_surface(context, surface);
83
84 cairo_destroy(cr);
85 cairo_surface_destroy(surface);
86
87 g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", row);
88 gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-row");
89}
90
91static void sel_layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
92{
93 GtkWidget *row;
94 (void)context;
95 (void)data;
96
97 row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
98 g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", NULL);
99 gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-row");
100 gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-hover");
101}
102
103static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context,
104 GtkSelectionData *selection_data,
105 guint info, guint time, gpointer data)
106{
107 (void)context;
108 (void)info;
109 (void)time;
110 (void)data;
111 GdkAtom atom;
112
113 atom = gdk_atom_intern_static_string("GTK_LIST_BOX_ROW");
114
115 gtk_selection_data_set(selection_data, atom,
116 32, (const guchar *)&widget, sizeof(gpointer));
117}
118
119static GtkListBoxRow *layer_selector_get_last_row(GtkListBox *list)
120{
121 int i;
122 GtkListBoxRow *row;
123 GtkListBoxRow *tmp;
124
125 row = NULL;
126 for (i = 0; ; i++) {
127 tmp = gtk_list_box_get_row_at_index(list, i);
128 if (tmp == NULL)
129 break;
130 row = tmp;
131 }
132
133 return row;
134}
135
136static GtkListBoxRow *layer_selector_get_row_before(GtkListBox *list, GtkListBoxRow *row)
137{
138 int pos;
139
140 pos = gtk_list_box_row_get_index(row);
141 return gtk_list_box_get_row_at_index(list, pos - 1);
142}
143
144static GtkListBoxRow *layer_selector_get_row_after(GtkListBox *list, GtkListBoxRow *row)
145{
146 int pos;
147
148 pos = gtk_list_box_row_get_index(row);
149 return gtk_list_box_get_row_at_index(list, pos + 1);
150}
151
152static void layer_selector_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
153 GtkSelectionData *selection_data, guint info, guint32 time,
154 gpointer data)
155{
156 GtkWidget *row_before, *row_after;
157 GtkWidget *row;
158 GtkWidget *source;
159 int pos;
160
161 /* Handle unused parameters */
162 (void)context;
163 (void)x;
164 (void)y;
165 (void)info;
166 (void)time;
167 (void)data;
168
169 row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
170 row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
171
172 g_object_set_data(G_OBJECT(widget), "row-before", NULL);
173 g_object_set_data(G_OBJECT(widget), "row-after", NULL);
174
175 if (row_before)
176 gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
177 if (row_after)
178 gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
179
180 row = (gpointer) *((gpointer *)gtk_selection_data_get_data(selection_data));
181 source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
182
183 if (source == row_after)
184 return;
185
186 g_object_ref(source);
187 gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(source)), source);
188
189 if (row_after)
190 pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_after));
191 else
192 pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_before)) + 1;
193
194 gtk_list_box_insert(GTK_LIST_BOX(widget), source, pos);
195 g_object_unref(source);
196}
197
198static gboolean layer_selector_drag_motion(GtkWidget *widget, GdkDragContext *context, int x, int y, guint time)
199{
200 GtkAllocation alloc;
201 GtkWidget *row;
202 int hover_row_y;
203 int hover_row_height;
204 GtkWidget *drag_row;
205 GtkWidget *row_before;
206 GtkWidget *row_after;
207 (void)context;
208 (void)x;
209 (void)y;
210 (void)time;
211
212 row = GTK_WIDGET(gtk_list_box_get_row_at_y(GTK_LIST_BOX(widget), y));
213
214 drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
215 row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
216 row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
217
218 gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
219 if (row_before)
220 gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
221 if (row_after)
222 gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
223
224 if (row) {
225 gtk_widget_get_allocation(row, &alloc);
226 hover_row_y = alloc.y;
227 hover_row_height = alloc.height;
228
229 if (y < hover_row_y + hover_row_height/2) {
230 row_after = row;
231 row_before = GTK_WIDGET(layer_selector_get_row_before(GTK_LIST_BOX(widget),
232 GTK_LIST_BOX_ROW(row)));
233 } else {
234 row_before = row;
235 row_after = GTK_WIDGET(layer_selector_get_row_after(GTK_LIST_BOX(widget),
236 GTK_LIST_BOX_ROW(row)));
237 }
238 } else {
239 row_before = GTK_WIDGET(layer_selector_get_last_row(GTK_LIST_BOX(widget)));
240 row_after = NULL;
241 }
242
243 g_object_set_data(G_OBJECT(widget), "row-before", row_before);
244 g_object_set_data(G_OBJECT(widget), "row-after", row_after);
245
246 if (drag_row == row_before || drag_row == row_after) {
247 gtk_style_context_add_class(gtk_widget_get_style_context(drag_row), "drag-hover");
248 return FALSE;
249 }
250
251 if (row_before)
252 gtk_style_context_add_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
253 if (row_after)
254 gtk_style_context_add_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
255
256 return TRUE;
257}
258
259static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time)
260{
261 GtkWidget *drag_row;
262 GtkWidget *row_before;
263 GtkWidget *row_after;
264 (void)context;
265 (void)time;
266
267 drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
268 row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
269 row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
270
271 gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
272 if (row_before)
273 gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
274 if (row_after)
275 gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
276
277}
278
279static const char *dnd_additional_css =
280 ".row:not(:first-child) { "
281 " border-top: 1px solid alpha(gray,0.5); "
282 " border-bottom: 1px solid transparent; "
283 "}"
284 ".row:first-child { "
285 " border-top: 1px solid transparent; "
286 " border-bottom: 1px solid transparent; "
287 "}"
288 ".row:last-child { "
289 " border-top: 1px solid alpha(gray,0.5); "
290 " border-bottom: 1px solid alpha(gray,0.5); "
291 "}"
292 ".row.drag-icon { "
293 " background: #282828; "
294 " border: 1px solid blue; "
295 "}"
296 ".row.drag-row { "
297 " color: gray; "
298 " background: alpha(gray,0.2); "
299 "}"
300 ".row.drag-row.drag-hover { "
301 " border-top: 1px solid #4e9a06; "
302 " border-bottom: 1px solid #4e9a06; "
303 "}"
304 ".row.drag-hover image, "
305 ".row.drag-hover label { "
306 " color: #4e9a06; "
307 "}"
308 ".row.drag-hover-top {"
309 " border-top: 1px solid #4e9a06; "
310 "}"
311 ".row.drag-hover-bottom {"
312 " border-bottom: 1px solid #4e9a06; "
313 "}";
314
315static void layer_selector_dispose(GObject *self)
316{
317 LayerSelector *sel = LAYER_SELECTOR(self);
318
319 g_clear_object(&sel->list_box);
320 g_clear_object(&sel->load_parent_window);
321 g_clear_object(&sel->save_parent_window);
322 g_clear_object(&sel->associated_load_button);
323 g_clear_object(&sel->associated_save_button);
324
325 if (sel->dnd_target.target) {
326 g_free(sel->dnd_target.target);
327 sel->dnd_target.target = NULL;
328 }
329
330 /* Chain up to parent's dispose function */
331 G_OBJECT_CLASS(layer_selector_parent_class)->dispose(self);
332}
333
334static void layer_selector_class_init(LayerSelectorClass *klass)
335{
336 GObjectClass *object_class = G_OBJECT_CLASS(klass);
337 GtkCssProvider *provider;
338
339 /* Implement handles to virtual functions */
340 object_class->dispose = layer_selector_dispose;
341
342 /* Setup the CSS provider for the drag and drop animations once */
343 provider = gtk_css_provider_new();
344 gtk_css_provider_load_from_data(provider, dnd_additional_css, -1, NULL);
345 gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), 800);
346
347 g_object_unref(provider);
348}
349
350static void layer_selector_setup_dnd(LayerSelector *self)
351{
352 gtk_drag_dest_set(GTK_WIDGET(self->list_box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
353 &self->dnd_target, 1, GDK_ACTION_MOVE);
354 g_signal_connect(self->list_box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
355 g_signal_connect(self->list_box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
356 g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
357}
358
359/* Drag and drop end */
360
361static void layer_selector_init(LayerSelector *self)
362{
363 self->load_parent_window = NULL;
364 self->save_parent_window = NULL;
365 self->associated_load_button = NULL;
366 self->associated_save_button = NULL;
367
368 self->dnd_target.target = g_strdup_printf("LAYER_SELECTOR_DND_%p", self);
369 self->dnd_target.info = 0;
370 self->dnd_target.flags = GTK_TARGET_SAME_APP;
371}
372
373LayerSelector *layer_selector_new(GtkListBox *list_box)
374{
375 LayerSelector *selector;
376
377 if (GTK_IS_LIST_BOX(list_box) == FALSE)
378 return NULL;
379
380 selector = LAYER_SELECTOR(g_object_new(TYPE_LAYER_SELECTOR, NULL));
381 selector->list_box = list_box;
382 layer_selector_setup_dnd(selector);
383 g_object_ref(G_OBJECT(list_box));
384
385 return selector;
386}
387
388LayerSettings *layer_selector_export_rendered_layer_info(LayerSelector *selector)
389{
390 LayerSettings *layer_settings;
391 struct layer_info linfo;
392 GList *row_list;
393 GList *iterator;
394 LayerElement *le;
395 int i;
396
397 layer_settings = layer_settings_new();
398 if (!layer_settings)
399 return NULL;
400
401 row_list = gtk_container_get_children(GTK_CONTAINER(selector->list_box));
402
403 for (i = 0, iterator = row_list; iterator != NULL; iterator = g_list_next(iterator), i++) {
404 le = LAYER_ELEMENT(iterator->data);
405
406 /* Get name from layer element. This must not be freed */
407 linfo.name = (char *)layer_element_get_name(le);
408
409 layer_element_get_color(le, &linfo.color);
410 linfo.render = (layer_element_get_export(le) ? 1 : 0);
411 linfo.stacked_position = i;
412 linfo.layer = layer_element_get_layer(le);
413
414 /* This function copies the entire layer info struct including the name string.
415 * Therefore, using the same layer_info struct over and over is safe.
416 */
417 layer_settings_append_layer_info(layer_settings, &linfo);
418 }
419
420 return layer_settings;
421}
422
423static void layer_selector_clear_widgets(LayerSelector *self)
424{
425 GList *list;
426 GList *temp;
427
428 list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
429 for (temp = list; temp != NULL; temp = temp->next)
430 gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data));
431
432 /* Widgets are already destroyed when removed from box because they are only referenced inside the container */
433
434 g_list_free(list);
435
436 /* Deactivate buttons */
437 if (self->associated_load_button)
438 gtk_widget_set_sensitive(self->associated_load_button, FALSE);
439 if (self->associated_save_button)
440 gtk_widget_set_sensitive(self->associated_save_button, FALSE);
441}
442
449static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer)
450{
451 GList *list;
452 GList *temp;
453 LayerElement *widget;
454 gboolean ret = FALSE;
455
456 list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
457
458 for (temp = list; temp != NULL; temp = temp->next) {
459 widget = LAYER_ELEMENT(temp->data);
460 if (layer_element_get_layer(widget) == layer) {
461 ret = TRUE;
462 break;
463 }
464 }
465
466 g_list_free(list);
467
468 return ret;
469}
470
476static void sel_layer_element_setup_dnd_callbacks(LayerSelector *self, LayerElement *element)
477{
478 struct layer_element_dnd_data dnd_data;
479
480 if (!self || !element)
481 return;
482
483 dnd_data.entries = &self->dnd_target;
484 dnd_data.entry_count = 1;
488
489 layer_element_set_dnd_callbacks(element, &dnd_data);
490}
491
497static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
498{
499 GList *graphics;
500 struct gds_graphics *gfx;
501 int layer;
502 GtkWidget *le;
503
504 for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
505 gfx = (struct gds_graphics *)graphics->data;
506 layer = (int)gfx->layer;
508 le = layer_element_new();
509 sel_layer_element_setup_dnd_callbacks(self, LAYER_ELEMENT(le));
510 layer_element_set_layer(LAYER_ELEMENT(le), layer);
511 gtk_list_box_insert(self->list_box, le, -1);
512 gtk_widget_show(le);
513 }
514 }
515}
516
525static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
526{
527 LayerElement *le1, *le2;
528 gint ret;
529 static const enum layer_selector_sort_algo default_sort = LAYER_SELECTOR_SORT_DOWN;
530 const enum layer_selector_sort_algo *algo = (const enum layer_selector_sort_algo *)unused;
531
532 /* Assume downward sorting */
533 /* TODO: This is nasty. Find a better way */
534 if (!algo)
535 algo = &default_sort;
536
537 le1 = LAYER_ELEMENT(row1);
538 le2 = LAYER_ELEMENT(row2);
539
540 /* Determine sort fow downward sort */
542
543 /* Change order if upward sort is requested */
544 ret *= (*algo == LAYER_SELECTOR_SORT_DOWN ? 1 : -1);
545
546 return ret;
547}
548
549void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
550{
551 GList *cell_list = NULL;
552 struct gds_library *lib;
553
555
556 for (; libs != NULL; libs = libs->next) {
557 lib = (struct gds_library *)libs->data;
558 for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next)
559 layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
560 } /* For libs */
561
562 /* Sort the layers */
564
565 /* Activate Buttons */
566 if (selector->associated_load_button)
567 gtk_widget_set_sensitive(selector->associated_load_button, TRUE);
568 if (selector->associated_save_button)
569 gtk_widget_set_sensitive(selector->associated_save_button, TRUE);
570}
571
578static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
579{
580 LayerElement *ret = NULL;
581
582 for (; el_list != NULL; el_list = el_list->next) {
583 if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
584 ret = LAYER_ELEMENT(el_list->data);
585 break;
586 }
587 }
588 return ret;
589}
590
602static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name)
603{
604 GFile *file;
605 GFileInputStream *stream;
606 GDataInputStream *dstream;
607 LayerElement *le;
608 GList *rows;
609 GList *temp;
610 GList *layer_infos;
611 int status;
612 LayerSettings *layer_settings;
613 struct layer_info *linfo;
614
615 file = g_file_new_for_path(file_name);
616 stream = g_file_read(file, NULL, NULL);
617
618 if (!stream)
619 goto destroy_file;
620
621 dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
622
623 rows = gtk_container_get_children(GTK_CONTAINER(self->list_box));
624
625 /* Reference and remove all rows from box */
626 for (temp = rows; temp != NULL; temp = temp->next) {
627 le = LAYER_ELEMENT(temp->data);
628 /* Referencing protects the widget from being deleted when removed */
629 g_object_ref(G_OBJECT(le));
630 gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
631 }
632
633 /* Load Layer settings. No need to check pointer, will be checked by load csv func. */
634 layer_settings = layer_settings_new();
635
636 status = layer_settings_load_from_csv(layer_settings, file_name);
637 if (status)
638 goto abort_layer_settings;
639
640 layer_infos = layer_settings_get_layer_info_list(layer_settings);
641 if (!layer_infos)
642 goto abort_layer_settings;
643
644 /* Loop over all layer infos read from the CSV file */
645 for (; layer_infos; layer_infos = g_list_next(layer_infos)) {
646 linfo = (struct layer_info *)layer_infos->data;
648 if (!le)
649 continue;
650
651 layer_element_set_name(le, linfo->name);
652 layer_element_set_export(le, (linfo->render ? TRUE : FALSE));
653 layer_element_set_color(le, &linfo->color);
654 gtk_container_add(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
655 rows = g_list_remove(rows, le);
656 }
657
658abort_layer_settings:
659 /* Destroy layer settings. Not needed for adding remaining elements */
660 g_object_unref(layer_settings);
661
662 /* Add remaining elements */
663 for (temp = rows; temp != NULL; temp = temp->next) {
664 le = LAYER_ELEMENT(temp->data);
665 /* Referencing protets the widget from being deleted when removed */
666 gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
667 g_object_unref(G_OBJECT(le));
668 }
669
670 /* Delete list */
671 g_list_free(rows);
672
673 /* read line */
674 g_object_unref(dstream);
675 g_object_unref(stream);
676destroy_file:
677 g_object_unref(file);
678}
679
685static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
686{
687 LayerSelector *sel;
688 GtkWidget *dialog;
689 gint res;
690 gchar *file_name;
691 (void)button;
692
693 sel = LAYER_SELECTOR(user_data);
694
695 dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(sel->load_parent_window),
696 GTK_FILE_CHOOSER_ACTION_OPEN,
697 "Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
698 res = gtk_dialog_run(GTK_DIALOG(dialog));
699 if (res == GTK_RESPONSE_ACCEPT) {
700 file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
702 g_free(file_name);
703 }
704 gtk_widget_destroy(dialog);
705}
706
707
708
714static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
715{
716 LayerSettings *layer_settings;
717
718 g_return_if_fail(LAYER_IS_SELECTOR(self));
719 g_return_if_fail(file_name);
720
721 /* Get layer settings. No need to check return value. to_csv func is safe */
722 layer_settings = layer_selector_export_rendered_layer_info(self);
723 (void)layer_settings_to_csv(layer_settings, file_name);
724}
725
731static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
732{
733 GtkWidget *dialog;
734 gint res;
735 gchar *file_name;
736 LayerSelector *sel;
737 (void)button;
738
739 sel = LAYER_SELECTOR(user_data);
740
741 dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(sel->save_parent_window),
742 GTK_FILE_CHOOSER_ACTION_SAVE,
743 "Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
744 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
745
746 res = gtk_dialog_run(GTK_DIALOG(dialog));
747 if (res == GTK_RESPONSE_ACCEPT) {
748 file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
750 g_free(file_name);
751 }
752 gtk_widget_destroy(dialog);
753}
754
755void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
756{
757 g_clear_object(&selector->load_parent_window);
758 g_clear_object(&selector->associated_load_button);
759
760 g_object_ref(G_OBJECT(button));
761 g_object_ref(G_OBJECT(main_window));
762 selector->associated_load_button = button;
763 selector->load_parent_window = main_window;
764 g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_load_mapping_clicked), selector);
765}
766
767void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
768{
769 g_clear_object(&selector->save_parent_window);
770 g_clear_object(&selector->associated_save_button);
771
772 g_object_ref(G_OBJECT(button));
773 g_object_ref(G_OBJECT(main_window));
774 selector->associated_save_button = button;
775 selector->save_parent_window = main_window;
776 g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_save_mapping_clicked), selector);
777}
778
779void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
780{
781 GtkListBox *box;
782
783 if (!selector)
784 return;
785
786 box = selector->list_box;
787 if (!box)
788 return;
789
790 /* Set sorting function, sort, and disable sorting function */
791 gtk_list_box_set_sort_func(box, layer_selector_sort_func, (gpointer)&sort_function, NULL);
792 gtk_list_box_invalidate_sort(box);
793 gtk_list_box_set_sort_func(box, NULL, NULL, NULL);
794}
795
796void layer_selector_select_all_layers(LayerSelector *layer_selector, gboolean select)
797{
798 GList *le_list;
799 GList *iter;
800 LayerElement *le;
801
802 g_return_if_fail(LAYER_IS_SELECTOR(layer_selector));
803 g_return_if_fail(GTK_IS_LIST_BOX(layer_selector->list_box));
804
805 le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
806
807 for (iter = le_list; iter != NULL; iter = g_list_next(iter)) {
808 le = LAYER_ELEMENT(iter->data);
809 if (LAYER_IS_ELEMENT(le))
810 layer_element_set_export(le, select);
811 }
812
813 g_list_free(le_list);
814}
815
816void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha)
817{
818 GList *le_list;
819 GList *le_list_ptr;
820 LayerElement *le;
821 unsigned int color_index = 0;
822 unsigned int color_count;
823 GdkRGBA color;
824
825 g_return_if_fail(GDS_RENDER_IS_COLOR_PALETTE(palette));
826 g_return_if_fail(LAYER_IS_SELECTOR(layer_selector));
827 g_return_if_fail(global_alpha > 0);
828 g_return_if_fail(GTK_IS_LIST_BOX(layer_selector->list_box));
829
830 le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
831
832 /* iterate over layer elements and fill colors */
833 color_index = 0;
834 color_count = color_palette_get_color_count(palette);
835 if (color_count == 0)
836 goto ret_free_le_list;
837
838 for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = le_list_ptr->next) {
839 le = LAYER_ELEMENT(le_list_ptr->data);
840 if (le) {
841 color_palette_get_color(palette, &color, color_index++);
842 color.alpha *= global_alpha;
844
845 if (color_index >= color_count)
846 color_index = 0;
847 }
848 }
849
850ret_free_le_list:
851 g_list_free(le_list);
852}
853
854void layer_selector_auto_name_layers(LayerSelector *layer_selector, gboolean overwrite)
855{
856 GList *le_list;
857 GList *le_list_ptr;
858 LayerElement *le;
859 const char *old_layer_name;
860 GString *new_layer_name;
861
862 g_return_if_fail(LAYER_IS_SELECTOR(layer_selector));
863
864 new_layer_name = g_string_new_len(NULL, 10);
865 le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
866
867 for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = g_list_next(le_list_ptr)) {
868 le = LAYER_ELEMENT(le_list_ptr->data);
869 if (!le)
870 continue;
871 old_layer_name = layer_element_get_name(le);
872
873 /* Check if layer name is empty or may be overwritten */
874 if (!old_layer_name || *old_layer_name == '\0' || overwrite) {
875 g_string_printf(new_layer_name, "Layer %d", layer_element_get_layer(le));
876 layer_element_set_name(le, new_layer_name->str);
877 }
878 }
879
880 g_string_free(new_layer_name, TRUE);
881 g_list_free(le_list);
882}
883
884gboolean layer_selector_contains_elements(LayerSelector *layer_selector)
885{
886 GList *layer_element_list;
887
888 /* Check objects */
889 g_return_val_if_fail(LAYER_IS_SELECTOR(layer_selector), FALSE);
890 g_return_val_if_fail(GTK_IS_LIST_BOX(layer_selector->list_box), FALSE);
891
892 /* Get a list of the child elements inside the list boy associated with this selector */
893 layer_element_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
894
895 /* Return TRUE if there is an element in the list, else return FALSE */
896 return (layer_element_list ? TRUE : FALSE);
897}
898
899size_t layer_selector_num_of_named_elements(LayerSelector *layer_selector)
900{
901 GList *le_list;
902 GList *le_list_ptr;
903 LayerElement *le;
904 const char *layer_name;
905 size_t count = 0U;
906
907 g_return_val_if_fail(LAYER_IS_SELECTOR(layer_selector), 0U);
908
909 le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
910
911 for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = g_list_next(le_list_ptr)) {
912 le = LAYER_ELEMENT(le_list_ptr->data);
913 if (!le)
914 continue;
915 layer_name = layer_element_get_name(le);
916
917 if (layer_name && *layer_name) {
918 /* Layer name is not empty. Count it */
919 count++;
920 }
921 }
922
923 return count;
924}
925
unsigned int color_palette_get_color_count(ColorPalette *palette)
Return amount of stored colors in palette.
GdkRGBA * color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index)
Get the n-th color in the palette identified by the index.
Header file for the GDS-Parser.
const char * layer_element_get_name(LayerElement *elem)
get name of the layer
Definition: layer-element.c:87
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba)
Set color of layer.
int layer_element_get_layer(LayerElement *elem)
Get layer number.
void layer_element_set_layer(LayerElement *elem, int layer)
Set layer number for this layer.
Definition: layer-element.c:97
void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba)
Get color of layer.
void layer_element_set_name(LayerElement *elem, const char *name)
layer_element_set_name
Definition: layer-element.c:92
void layer_element_set_dnd_callbacks(LayerElement *elem, struct layer_element_dnd_data *data)
Setup drag and drop of elem for use in the LayerSelector.
void layer_element_set_export(LayerElement *elem, gboolean export)
Set export flag for this layer.
gboolean layer_element_get_export(LayerElement *elem)
Get export flag of layer.
GtkWidget * layer_element_new(void)
Create new layer element object.
Definition: layer-element.c:82
static void layer_selector_dispose(GObject *self)
static const char * dnd_additional_css
static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
Callback for Load Mapping Button.
static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
Analyze cell layers and append detected layers to layer selector self.
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
Force the layer selector list to be sorted according to sort_function.
static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
sort_func Sort callback for list box
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
Generate layer widgets in in the LayerSelector instance.
static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
#define TYPE_LAYER_SELECTOR
static gboolean layer_selector_drag_motion(GtkWidget *widget, GdkDragContext *context, int x, int y, guint time)
static void layer_selector_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint32 time, gpointer data)
static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time)
static void sel_layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
static void layer_selector_init(LayerSelector *self)
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
Supply button for loading the layer mapping.
void layer_selector_select_all_layers(LayerSelector *layer_selector, gboolean select)
Set 'export' value of all layers in the LayerSelector to the supplied select value.
LayerSettings * layer_selector_export_rendered_layer_info(LayerSelector *selector)
Get a list of all layers that shall be exported when rendering the cells.
static void layer_selector_clear_widgets(LayerSelector *self)
void layer_selector_auto_name_layers(LayerSelector *layer_selector, gboolean overwrite)
Auto name all layers in the layer selector.
static GtkListBoxRow * layer_selector_get_row_before(GtkListBox *list, GtkListBoxRow *row)
static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name)
Load the layer mapping from a CSV formatted file.
static void layer_selector_setup_dnd(LayerSelector *self)
layer_selector_sort_algo
Defines how to sort the layer selector list box.
static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
Callback for Save Layer Mapping Button.
static GtkListBoxRow * layer_selector_get_last_row(GtkListBox *list)
static void sel_layer_element_setup_dnd_callbacks(LayerSelector *self, LayerElement *element)
Setup the necessary drag and drop callbacks of layer elements.
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
Supply button for saving the layer mapping.
static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
Save layer mapping of selector self to a file.
static void layer_selector_class_init(LayerSelectorClass *klass)
static LayerElement * layer_selector_find_layer_element_in_list(GList *el_list, int layer)
Find LayerElement in list with specified layer number.
static GtkListBoxRow * layer_selector_get_row_after(GtkListBox *list, GtkListBoxRow *row)
LayerSelector * layer_selector_new(GtkListBox *list_box)
layer_selector_new
static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer)
Check if a specific layer element with the given layer number is present in the layer selector.
static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data)
gboolean layer_selector_contains_elements(LayerSelector *layer_selector)
Check if the given layer selector contains layer elements.
size_t layer_selector_num_of_named_elements(LayerSelector *layer_selector)
Get number of layer elements that are named.
void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha)
Apply colors from palette to all layers. Aditionally set alpha.
@ LAYER_SELECTOR_SORT_DOWN
Implementation of the layer element used for configuring layer colors etc.
Implementation of the Layer selection list.
int layer_settings_to_csv(LayerSettings *settings, const char *path)
Write layer settings to a CSV file.
LayerSettings * layer_settings_new()
New LayerSettings object.
GList * layer_settings_get_layer_info_list(LayerSettings *settings)
Get a GList with layer_info structs.
int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
Load new layer Settings from CSV.
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
layer_settings_append_layer_info
GtkWidget * associated_save_button
GtkWidget * associated_load_button
GtkTargetEntry dnd_target
GtkWindow * load_parent_window
GtkListBox * list_box
gpointer dummy[4]
GtkWindow * save_parent_window
A Cell inside a gds_library.
Definition: gds-types.h:122
GList * graphic_objs
List of gds_graphics.
Definition: gds-types.h:127
A GDS graphics object.
Definition: gds-types.h:98
int16_t layer
Layer the graphic object is on.
Definition: gds-types.h:103
GDS Toplevel library.
Definition: gds-types.h:135
GList * cells
Definition: gds-types.h:140
This structure holds the necessary data to set up a LayerElement for Drag'n'Drop.
Definition: layer-element.h:63
void(* drag_data_get)(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer)
Callback fucktion for data_get event.
Definition: layer-element.h:71
GtkTargetEntry * entries
Array of target entries for the DnD operation.
Definition: layer-element.h:65
void(* drag_begin)(GtkWidget *, GdkDragContext *, gpointer)
Callback function for drag_begin event.
Definition: layer-element.h:69
void(* drag_end)(GtkWidget *, GdkDragContext *, gpointer)
Callback function for drag_end event.
Definition: layer-element.h:73
int entry_count
Count of elements in layer_element_dnd_data::entries array.
Definition: layer-element.h:67
Layer information.
int render
true: Render to output
char * name
Layer name.
int stacked_position
Position of layer in output.
GdkRGBA color
RGBA color used to render this layer.
int layer
Layer number.