30 Commits

Author SHA1 Message Date
3882f3944e Change selction filter function. Now only cells without major errors are selectable. Warnings are okay because the renderers can handle these (unresolved references etc...) 2019-03-05 21:03:27 +01:00
00b47d7ded Add lib cell renderer to main window. It is needed for the Error level defines of the cells 2019-03-05 20:55:04 +01:00
e9b67fe1bc Implement error level indicator for cells 2019-03-05 20:52:00 +01:00
976bdd9854 Fix function description 2019-03-05 20:21:49 +01:00
73e4806e65 Implenment child cell resolve checker 2019-03-05 20:14:07 +01:00
0b17c25ecc Add defualt value for check results 2019-03-05 20:08:10 +01:00
0ef6d2f40f update trigonometric library doxygen 2019-03-05 19:50:01 +01:00
58bb74b905 Add checks to cell structure 2019-03-05 19:48:03 +01:00
cd9030a24e Create GDS Tree checking functions. Renamed doxygen section of GDS Parser to GDS-Utilities so the cheking function fit into this section 2019-03-05 19:38:07 +01:00
68e7d52cd8 Changed settings dialog api to use database units. Implement render output size preview 2019-03-04 20:14:21 +01:00
91a3e8f983 Fix style 2019-03-04 19:35:25 +01:00
f74e2d5cf5 Fix bug 2019-03-04 19:35:04 +01:00
845da756b7 Fix bug of wrong bounding box calculation: Replace DBL_MIN with -DBL_MAX 2019-02-28 21:17:54 +01:00
531634b55a Fix bug in bounding box 2d translation 2019-02-27 21:42:54 +01:00
2e1cf456c7 Add pointer to parent library to cells, implement first draft of cell size/shape preview 2019-02-27 21:33:12 +01:00
bce47f11fc Fix formatting 2019-02-27 20:28:53 +01:00
5573ceb46b Fix formatting in GDS-Parser 2019-02-27 20:28:06 +01:00
7124c9a5cc Add fallthrough mark, correct Typo 2019-02-27 20:27:01 +01:00
d5997ab5f2 Merge branch 'master' into dev 2019-02-22 20:04:27 +01:00
e692129477 fix minor code style stuff 2019-02-22 19:54:08 +01:00
af031acc38 Merge branch 'master' into dev 2019-02-03 22:56:47 +01:00
199833d603 Updated code for cell size calculation 2018-12-29 01:13:33 +01:00
b0acbda6e3 Temporarily re-enabled SVG output (from GUI only)
* Cairo version: 1.16.0-1
* SVG output doens't seem as broken as before with the current cairo version
* Transparency doesn't work. Transparent layers aren't rendered at all.
2018-12-22 21:30:16 +01:00
7e4b915961 Remove useless empty lines 2018-12-22 21:06:52 +01:00
1fe70422db Update size labels when size is set 2018-12-22 21:04:34 +01:00
b5087769ee Add cell size preview to dialog 2018-12-22 20:54:02 +01:00
4f9e5ca0b4 Add drawing area for size demonstartion 2018-12-22 19:37:57 +01:00
a2b83c37a9 Edit trigonometric functions 2018-12-22 19:31:36 +01:00
15ff68ea74 Fix invalid conversion 2018-12-22 19:13:33 +01:00
6bb05890b9 Add database unit parsing 2018-12-22 19:11:09 +01:00
21 changed files with 793 additions and 84 deletions

View File

@@ -2,7 +2,7 @@
/**
* @defgroup trigonometric Trigonometric Helper Functions
* @description The trigonometric helper function will be used in future releases to pcalculate bounding boxes
* @note Currently not in use!
* @warning Code is incomplete. DO NOT USE!
*
* The trigonometric helper function are used to calculate bounding boxes
* @warning Code is incomplete. Please double check the functionality!
*/

View File

@@ -17,11 +17,6 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/*
*/
/**
* @file gds-parser.c
* @brief Implementation of the GDS-Parser
@@ -35,7 +30,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
@@ -48,11 +43,17 @@
#include <math.h>
#include <cairo.h>
/**
* @brief Default units assumed for library.
* @note This value is usually overwritten with the value defined in the library.
*/
#define GDS_DEFAULT_UNITS (10E-9)
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS error*/
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS warning */
#if GDS_PRINT_DEBUG_INFOS
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__) /**< @brief standard printf. But cna be disabled in code */
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__) /**< @brief standard printf. But can be disabled in code */
#else
#define GDS_INF(fmt, ...)
#endif
@@ -221,7 +222,7 @@ static GList *append_library(GList *curr_list, struct gds_library **library_ptr)
if (lib) {
lib->cells = NULL;
lib->name[0] = 0;
lib->unit_to_meters = 1; // Default. Will be overwritten
lib->unit_in_meters = GDS_DEFAULT_UNITS; // Default. Will be overwritten
lib->cell_names = NULL;
} else
return NULL;
@@ -297,6 +298,9 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
cell->child_cells = NULL;
cell->graphic_objs = NULL;
cell->name[0] = 0;
cell->parent_library = NULL;
cell->checks.unresolved_child_count = GDS_CELL_CHECK_NOT_RUN;
cell->checks.affected_by_reference_loop = GDS_CELL_CHECK_NOT_RUN;
} else
return NULL;
/* return cell */
@@ -383,7 +387,7 @@ static int name_cell(struct gds_cell *cell, unsigned int bytes,
return -1;
}
data[bytes] = 0; // Append '0'
len = strlen(data);
len = (int)strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
return -1;
@@ -458,6 +462,7 @@ static void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
static void scan_library_references(gpointer library_list_item, gpointer user)
{
struct gds_library *lib = (struct gds_library *)library_list_item;
(void)user;
GDS_INF("Scanning Library: %s\n", lib->name);
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
@@ -607,12 +612,20 @@ int parse_gds_from_file(const char *filename, GList **library_list)
GDS_INF("Leaving Library\n");
break;
case BGNSTR:
if (current_lib == NULL) {
GDS_ERROR("Defining Cell outside of library!\n");
run = -4;
break;
}
current_lib->cells = append_cell(current_lib->cells, &current_cell);
if (current_lib->cells == NULL) {
GDS_ERROR("Allocating memory failed");
run = -3;
break;
}
current_cell->parent_library = current_lib;
GDS_INF("Entering Cell\n");
break;
case ENDSTR:
@@ -710,6 +723,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
case PATHTYPE:
break;
case UNITS:
break;
default:
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
break;
@@ -717,7 +732,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
/* No Data -> No Processing, go back to top */
if (!rec_data_length) continue;
if (!rec_data_length || run != 1) continue;
read = fread(workbuff, sizeof(char), rec_data_length, gds_file);
@@ -731,7 +746,6 @@ int parse_gds_from_file(const char *filename, GList **library_list)
switch (rec_type) {
case HEADER:
case UNITS:
case ENDLIB:
case ENDSTR:
case BOUNDARY:
@@ -742,6 +756,20 @@ int parse_gds_from_file(const char *filename, GList **library_list)
case INVALID:
break;
case UNITS:
if (!current_lib) {
GDS_WARN("Units defined outside of library!\n");
break;
}
if (rec_data_length != 16) {
GDS_WARN("Unit define incomplete. Will assume database unit of %E meters\n", current_lib->unit_in_meters);
break;
}
current_lib->unit_in_meters = gds_convert_double(&workbuff[8]);
GDS_INF("Length of database unit: %E meters\n", current_lib->unit_in_meters);
break;
case BGNLIB:
/* Parse date record */
gds_parse_date(workbuff, read, &current_lib->mod_time, &current_lib->access_time);
@@ -848,15 +876,11 @@ int parse_gds_from_file(const char *filename, GList **library_list)
fclose(gds_file);
if (!run) {
/* Iterate and find references to cells */
g_list_foreach(lib_list, scan_library_references, NULL);
}
*library_list = lib_list;
free(workbuff);

View File

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/

View File

@@ -0,0 +1,91 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-tree-checker.c
* @brief Checking functions of a cell tree
*
* This file contains cehcking functions for the GDS cell tree.
* These functions include checks if all child references could be resolved,
* and if the cell tree contains loops.
*
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#include "gds-tree-checker.h"
#include <stdio.h>
int gds_tree_check_cell_references(struct gds_library *lib)
{
GList *cell_iter;
struct gds_cell *cell;
GList *instance_iter;
struct gds_cell_instance *cell_inst;
int total_unresolved_count = 0;
if (!lib)
return -1;
/* Iterate over all cells in library */
for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) {
cell = (struct gds_cell *)cell_iter->data;
/* Check if this list element is broken. This should never happen */
if (!cell) {
fprintf(stderr, "Broken cell list item found. Will continue.\n");
continue;
}
/* Reset the unresolved cell reference counter to 0 */
cell->checks.unresolved_child_count = 0;
/* Iterate through all child cell references and check if the references are set */
for (instance_iter = cell->child_cells; instance_iter != NULL;
instance_iter = g_list_next(instance_iter)) {
cell_inst = (struct gds_cell_instance *)instance_iter->data;
/* Check if broken. This should also not happen */
if (!cell_inst) {
fprintf(stderr, "Broken cell list item found in cell %s. Will continue.\n",
cell->name);
continue;
}
/* Check if instance is valid; else increment "error" counter of cell */
if (!cell_inst->cell_ref) {
total_unresolved_count++;
cell->checks.unresolved_child_count++;
}
}
}
return total_unresolved_count;
}
int gds_tree_check_reference_loops(struct gds_library *lib)
{
return 0;
}
/** @} */

View File

@@ -0,0 +1,61 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-tree-checker.h
* @brief Checking functions of a cell tree (Header)
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#ifndef _GDS_TREE_CHECKER_H_
#define _GDS_TREE_CHECKER_H_
#include "gds-types.h"
/**
* @brief gds_tree_check_cell_references checks if all child cell references can be resolved in the given library
*
* This function will only mark cells that
* directly contain unresolved references.
*
* If a cell contains a reference to a cell with unresolved references, it is not flagged.
*
* @param lib The GDS library to check
* @return less than 0 if an error occured during processing; 0 if all child cells could be resolved;
* greater than zero if the processing was successful but not all cell references could be resolved.
* In this case the number of unresolved references is returned
*/
int gds_tree_check_cell_references(struct gds_library *lib);
/**
* @brief gds_tree_check_reference_loops checks if the given library contains reference loops
* @param lib GDS library
* @return negative if an error occured, zero if there are no reference loops, else a positive number representing the number
* of affected cells
*/
int gds_tree_check_reference_loops(struct gds_library *lib);
#endif /* _GDS_TREE_CHECKER_H_ */
/** @} */

View File

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
@@ -35,9 +35,15 @@
#include <glib.h>
#define CELL_NAME_MAX (100) /**< @brief Maximum length of a gds_cell::name or a gds_library::name */
/* Maybe use the macros that ship with the compiler? */
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
/** @brief Defintion of check counter default value
* that indicates that the corresponding check has not yet been executed */
enum {GDS_CELL_CHECK_NOT_RUN = -1};
/** @brief Types of graphic objects */
enum graphics_type
{
@@ -59,6 +65,21 @@ struct gds_point {
int y;
};
/**
* @brief Stores the result of the cell checks.
*/
struct gds_cell_checks {
int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell. Default: GDS_CELL_CHECK_NOT_RUN */
int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable. Default: GDS_CELL_CHECK_NOT_RUN*/
/**
* @brief For the internal use of the checker.
* @warning Do not use this structure and its contents!
*/
struct _check_internals {
int marker;
} _internal;
};
/**
* @brief Date information for cells and libraries
*/
@@ -104,6 +125,8 @@ struct gds_cell {
struct gds_time_field access_time;
GList *child_cells; /**< @brief List of #gds_cell_instance elements */
GList *graphic_objs; /**< @brief List of #gds_graphics */
struct gds_library *parent_library; /**< @brief Pointer to parent library */
struct gds_cell_checks checks; /**< @brief Checking results */
};
/**
@@ -113,7 +136,7 @@ struct gds_library {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
double unit_to_meters; /**< @warning not yet implemented */
double unit_in_meters; /**< Length of a database unit in meters */
GList *cells; /**< List of #gds_cell that contains all cells in this library*/
GList *cell_names /**< List of strings that contains all cell names */;
};

View File

@@ -4,7 +4,7 @@
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">1</property>
<property name="upper">3000</property>
<property name="upper">4000</property>
<property name="value">1000</property>
<property name="step_increment">10</property>
<property name="page_increment">1000</property>
@@ -51,7 +51,6 @@
<property name="label" translatable="yes">Render SVG using Cairographics (too buggy at the moment)</property>
<property name="use_action_appearance">True</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
@@ -69,6 +68,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment1</property>
<property name="fill_level">4000</property>
<property name="round_digits">0</property>
<property name="digits">0</property>
</object>
@@ -106,5 +106,83 @@
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="shape-drawer">
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="x-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="y-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="x-output-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="y-output-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
</interface>

View File

@@ -36,6 +36,8 @@
#include "latex-output/latex-output.h"
#include "widgets/conv-settings-dialog.h"
#include "cairo-output/cairo-output.h"
#include "trigonometric/cell-trigonometrics.h"
#include "tree-renderer/lib-cell-renderer.h"
/**
* @brief User data supplied to callback function of the open button
@@ -113,7 +115,6 @@ static void on_load_gds(gpointer button, gpointer user)
char *filename;
GString *mod_date;
GString *acc_date;
GdkRGBA cell_text_color;
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL);
@@ -174,11 +175,6 @@ static void on_load_gds(gpointer button, gpointer user)
mod_date = generate_string_from_date(&gds_c->mod_time);
acc_date = generate_string_from_date(&gds_c->access_time);
cell_text_color.alpha = 1;
cell_text_color.red = (double)61.0/(double)255.0;
cell_text_color.green = (double)152.0/(double)255.0;
cell_text_color.blue = 0.0;
/* Add cell to tree store model
* CELL_SEL_CELL_COLOR will always be green,
* because no cell cehcker is implemented, yet.
@@ -187,7 +183,7 @@ static void on_load_gds(gpointer button, gpointer user)
CELL_SEL_CELL, gds_c,
CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str,
CELL_SEL_CELL_COLOR, &cell_text_color, // TODO: implement cell checker
CELL_SEL_CELL_ERROR_STATE, 0, // TODO: implement cell checker
-1);
/* Delete GStrings including string data. */
@@ -214,8 +210,8 @@ end_destroy:
static void on_convert_clicked(gpointer button, gpointer user)
{
static struct render_settings sett = {
.scale = 1000.0f,
.renderer = RENDERER_LATEX_TIKZ,
.scale = 1000.0,
.renderer = RENDERER_LATEX_TIKZ,
};
struct convert_button_data *data = (struct convert_button_data *)user;
GtkTreeSelection *selection;
@@ -229,6 +225,8 @@ static void on_convert_clicked(gpointer button, gpointer user)
GtkFileFilter *filter;
gint res;
char *file_name;
union bounding_box cell_box;
double height, width;
/* Get selected cell */
selection = gtk_tree_view_get_selection(data->tree_view);
@@ -243,8 +241,21 @@ static void on_convert_clicked(gpointer button, gpointer user)
/* Get layers that are rendered */
layer_list = export_rendered_layer_info();
/* Calculate cell size in DB units */
bounding_box_prepare_empty(&cell_box);
calculate_cell_bounding_box(&cell_box, cell_to_render);
/* Calculate size in meters database units */
height = (cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y);
width = (cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x);
/* Show settings dialog */
settings = renderer_settings_dialog_new(GTK_WINDOW(data->main_window));
renderer_settings_dialog_set_settings(settings, &sett);
renderer_settings_dialog_set_database_unit_scale(settings, cell_to_render->parent_library->unit_in_meters);
renderer_settings_dialog_set_cell_height(settings, height);
renderer_settings_dialog_set_cell_width(settings, width);
res = gtk_dialog_run(GTK_DIALOG(settings));
if (res == GTK_RESPONSE_OK) {
renderer_settings_dialog_get_settings(settings, &sett);
@@ -254,8 +265,6 @@ static void on_convert_clicked(gpointer button, gpointer user)
goto ret_layer_destroy;
}
/* save file dialog */
dialog = gtk_file_chooser_dialog_new((sett.renderer == RENDERER_LATEX_TIKZ
? "Save LaTeX File" : "Save PDF"),

6
main.c
View File

@@ -56,8 +56,8 @@ static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_
}
const static GActionEntry app_actions[] = {
{ "quit", app_quit },
{ "about", app_about }
{"quit", app_quit},
{"about", app_about}
};
static void gapp_activate(GApplication *app, gpointer user_data)
@@ -100,7 +100,6 @@ static int start_gui(int argc, char **argv)
g_object_unref(m_about);
g_object_unref(menu);
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
g_object_unref(gapp);
@@ -189,6 +188,5 @@ int main(int argc, char **argv)
app_status = start_gui(argc, argv);
}
return app_status;
}

View File

@@ -25,6 +25,7 @@ G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
enum {
PROP_LIB = 1,
PROP_CELL,
PROP_ERROR_LEVEL,
PROP_COUNT
};
@@ -38,24 +39,56 @@ static void lib_cell_renderer_constructed(GObject *obj)
G_OBJECT_CLASS(lib_cell_renderer_parent_class)->constructed(obj);
}
static void convert_error_level_to_color(GdkRGBA *color, unsigned int error_level)
{
/* Always use no transparency */
color->alpha = 1.0;
if (error_level & LIB_CELL_RENDERER_ERROR_ERR) {
/* Error set. Color cell red */
color->red = 1.0;
color->blue = 0.0;
color->green = 0.0;
} else if (error_level & LIB_CELL_RENDERER_ERROR_WARN) {
/* Only warning set; orange color */
color->red = 0.6;
color->blue = 0.0;
color->green = 0.4;
} else {
/* Everything okay; green color */
color->red = (double)61.0/(double)255.0;
color->green = (double)152.0/(double)255.0;
color->blue = 0.0;
}
}
static void lib_cell_renderer_set_property(GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GValue val = G_VALUE_INIT;
g_value_init(&val, G_TYPE_STRING);
GdkRGBA color;
switch (param_id) {
case PROP_LIB:
g_value_init(&val, G_TYPE_STRING);
g_value_set_string(&val, ((struct gds_library *)g_value_get_pointer(value))->name);
g_object_set_property(object, "text", &val);
break;
case PROP_CELL:
g_value_init(&val, G_TYPE_STRING);
g_value_set_string(&val, ((struct gds_cell *)g_value_get_pointer(value))->name);
g_object_set_property(object, "text", &val);
break;
case PROP_ERROR_LEVEL:
/* Set cell color according to error level */
g_value_init(&val, GDK_TYPE_RGBA);
convert_error_level_to_color(&color, g_value_get_uint(value));
g_value_set_boxed(&val, &color);
g_object_set_property(object, "foreground-rgba", &val);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
@@ -89,6 +122,8 @@ void lib_cell_renderer_class_init(LibCellRendererClass *klass)
properties[PROP_CELL] = g_param_spec_pointer("gds-cell", "gds-cell",
"Cell reference to be displayed",
G_PARAM_WRITABLE);
properties[PROP_ERROR_LEVEL] = g_param_spec_uint("error-level", "error-level",
"Error level of this cell", 0, 255, 0, G_PARAM_WRITABLE);
g_object_class_install_properties(oclass, PROP_COUNT, properties);
}

View File

@@ -27,6 +27,9 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0)
#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1)
typedef struct _LibCellRenderer {
/* Inheritance */
GtkCellRendererText super;

View File

@@ -49,15 +49,20 @@ static gboolean tree_sel_func(GtkTreeSelection *selection,
{
GtkTreeIter iter;
struct gds_cell *cell;
unsigned int error_level;
gboolean ret = FALSE;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, -1);
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1);
/* Allow only rows with valid cell to be selected */
if (cell)
return TRUE;
else
return FALSE;
/* Allow only rows with _valid_ cell to be selected */
if (cell) {
/* Cell available. Check if it passed the critical checks */
if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR))
ret = TRUE;
}
return ret;
}
/**
@@ -127,7 +132,7 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr
stores.base_tree_view = view;
stores.search_entry = search_entry;
stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, GDK_TYPE_RGBA, G_TYPE_STRING, G_TYPE_STRING);
stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
/* Searching */
if (search_entry) {
@@ -147,8 +152,8 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
gtk_tree_view_append_column(view, column);
/* Cell color: #3D9801 */
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, "foreground-rgba", CELL_SEL_CELL_COLOR, NULL);
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL,
"error-level", CELL_SEL_CELL_ERROR_STATE, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);

View File

@@ -37,7 +37,7 @@
enum cell_store_columns {
CELL_SEL_LIBRARY = 0,
CELL_SEL_CELL,
CELL_SEL_CELL_COLOR, /**< Cell column color */
CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */
CELL_SEL_MODDATE,
CELL_SEL_ACCESSDATE,
CELL_SEL_COLUMN_COUNT /**< Not a column. Used to determine count of coumns **/

View File

@@ -38,7 +38,7 @@
void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
{
double xmin = DBL_MAX, xmax = DBL_MIN, ymin = DBL_MAX, ymax = DBL_MIN;
double xmin = DBL_MAX, xmax = -DBL_MAX, ymin = DBL_MAX, ymax = -DBL_MAX;
struct vector_2d temp_vec;
GList *list_item;
@@ -86,8 +86,8 @@ void bounding_box_prepare_empty(union bounding_box *box)
{
box->vectors.lower_left.x = DBL_MAX;
box->vectors.lower_left.y = DBL_MAX;
box->vectors.upper_right.x = DBL_MIN;
box->vectors.upper_right.y = DBL_MIN;
box->vectors.upper_right.x = -DBL_MAX;
box->vectors.upper_right.y = -DBL_MAX;
}
static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b, struct vector_2d *c,
@@ -133,14 +133,70 @@ static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b
vector_2d_subtract(m2, m2, &v_vec);
}
void bounding_box_calculate_path_box(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
void bounding_box_calculate_path_box(GList *vertices, double thickness,
conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
{
GList *vertex_iterator;
struct vector_2d pt;
printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n");
if (!vertices || !box)
return;
for (vertex_iterator = vertices; vertex_iterator != NULL; vertex_iterator = g_list_next(vertex_iterator)) {
if (conv_func != NULL)
conv_func(vertex_iterator->data, &pt);
else
(void)vector_2d_copy(&pt, (struct vector_2d *)vertex_iterator->data);
/* These are approximations.
* Used as long as miter point calculation is not fully implemented
*/
box->vectors.lower_left.x = MIN(box->vectors.lower_left.x, pt.x - thickness/2);
box->vectors.lower_left.y = MIN(box->vectors.lower_left.y, pt.y - thickness/2);
box->vectors.upper_right.x = MAX(box->vectors.upper_right.x, pt.x + thickness/2);
box->vectors.upper_right.y = MAX(box->vectors.upper_right.y, pt.y + thickness/2);
}
}
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt)
{
struct vector_2d point;
if (!destination || !pt)
return;
if (conv_func)
conv_func(pt, &point);
else
(void)vector_2d_copy(&point, (struct vector_2d *)pt);
destination->vectors.lower_left.x = MIN(destination->vectors.lower_left.x, point.x);
destination->vectors.lower_left.y = MIN(destination->vectors.lower_left.y, point.y);
destination->vectors.upper_right.x = MAX(destination->vectors.upper_right.x, point.x);
destination->vectors.upper_right.y = MAX(destination->vectors.upper_right.y, point.y);
}
/**
* @brief bounding_box_apply_transform
* @param scale scaling factor
* @param rotation roation of bounding box around the origin in degrees (counterclockwise)
* @param box bounding box the operations should be applied to
*/
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box)
{
int i;
/* Due to linearity, the order of the operations does not matter.
* flip must be applied before rotation as defined by the GDS format
*/
for (i = 0; i < 2; i++) {
box->vector_array[i].y *= (flip_at_x ? -1 : 1);
vector_2d_rotate(&box->vector_array[i], rotation_deg * M_PI / 180);
vector_2d_scale(&box->vector_array[i], scale);
}
}
/** @} */

View File

@@ -32,6 +32,7 @@
#define _BOUNDING_BOX_H_
#include <glib.h>
#include "vector-operations.h"
#include <stdbool.h>
union bounding_box {
/** Coordinate System is (y up | x right) */
@@ -48,6 +49,8 @@ void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t
void bounding_box_update_box(union bounding_box *destination, union bounding_box *update);
void bounding_box_prepare_empty(union bounding_box *box);
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt);
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box);
void bounding_box_calculate_path_box(GList *vertices, double thickness, conv_generic_to_vector_2d_t conv_func, union bounding_box *box);
#endif /* _BOUNDING_BOX_H_ */

View File

@@ -0,0 +1,119 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file cell-trigonometrics.c
* @brief Calculation of gds_cell trigonometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include "cell-trigonometrics.h"
#include <math.h>
/**
* @addtogroup trigonometric
* @{
*/
static void convert_gds_point_to_2d_vector(struct gds_point *pt, struct vector_2d *vector)
{
vector->x = pt->x;
vector->y = pt->y;
}
/**
* @brief update_box_with_gfx
* @param box
* @param gfx_list
*/
static void update_box_with_gfx(union bounding_box *box, struct gds_graphics *gfx)
{
union bounding_box current_box;
bounding_box_prepare_empty(&current_box);
switch (gfx->gfx_type) {
case GRAPHIC_BOX:
/* Expected fallthrough */
case GRAPHIC_POLYGON:
bounding_box_calculate_polygon(gfx->vertices,
(conv_generic_to_vector_2d_t)&convert_gds_point_to_2d_vector,
&current_box);
break;
case GRAPHIC_PATH:
/*
* This is not implemented correctly.
* Please be aware if paths are the outmost elements of your cell.
* You might end up with a completely wrong calculated cell size.
*/
bounding_box_calculate_path_box(gfx->vertices, gfx->width_absolute,
(conv_generic_to_vector_2d_t)&convert_gds_point_to_2d_vector,
&current_box);
break;
default:
/* Unknown graphics object. */
/* Print error? Nah.. */
break;
}
/* Update box with results */
bounding_box_update_box(box, &current_box);
}
void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell)
{
GList *gfx_list;
struct gds_graphics *gfx;
GList *sub_cell_list;
struct gds_cell_instance *sub_cell;
union bounding_box temp_box;
if (!box || !cell)
return;
/* Update box with graphic elements */
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
gfx = (struct gds_graphics *)gfx_list->data;
update_box_with_gfx(box, gfx);
}
/* Update bounding box with boxes of subcells */
for (sub_cell_list = cell->child_cells; sub_cell_list != NULL;
sub_cell_list = sub_cell_list->next) {
sub_cell = (struct gds_cell_instance *)sub_cell_list->data;
bounding_box_prepare_empty(&temp_box);
/* Recursion Woohoo!! This dies if your GDS is faulty and contains a reference loop */
calculate_cell_bounding_box(&temp_box, sub_cell->cell_ref);
/* Apply transformations */
bounding_box_apply_transform(ABS(sub_cell->magnification), sub_cell->angle,
sub_cell->flipped, &temp_box);
/* Move bounding box to origin */
temp_box.vectors.lower_left.x += sub_cell->origin.x;
temp_box.vectors.upper_right.x += sub_cell->origin.x;
temp_box.vectors.lower_left.y += sub_cell->origin.y;
temp_box.vectors.upper_right.y += sub_cell->origin.y;
/* update the parent's box */
bounding_box_update_box(box, &temp_box);
}
}
/** @} */

View File

@@ -0,0 +1,47 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file cell-trigonometrics.h
* @brief Calculation of gds_cell trigonometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#ifndef _CELL_TRIGONOMETRICS_H_
#define _CELL_TRIGONOMETRICS_H_
#include "bounding-box.h"
#include "../gds-parser/gds-types.h"
/**
* @brief calculate_cell_bounding_box Calculate bounding box of gds cell
* @param box Resulting boundig box. Will be uüdated and not overwritten
* @param cell toplevel cell
* @warning Path handling not yet implemented correctly
*/
void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell);
#endif /* _CELL_TRIGONOMETRICS_H_ */
/** @} */

View File

@@ -76,18 +76,17 @@ struct vector_2d *vector_2d_copy(struct vector_2d *opt_res, struct vector_2d *ve
if (!vec)
return NULL;
if (opt_res) {
opt_res->x = vec->x;
opt_res->y = vec->y;
return opt_res;
} else {
if (opt_res)
res = opt_res;
else
res = vector_2d_alloc();
if (res) {
res->x = vec->x;
res->y = vec->y;
}
return res;
if (res) {
res->x = vec->x;
res->y = vec->y;
}
return res;
}
struct vector_2d *vector_2d_alloc(void)

View File

@@ -39,12 +39,20 @@ struct _RendererSettingsDialog {
GtkWidget *scale;
GtkWidget *layer_check;
GtkWidget *standalone_check;
GtkDrawingArea *shape_drawing;
GtkLabel *x_label;
GtkLabel *y_label;
GtkLabel *x_output_label;
GtkLabel *y_output_label;
unsigned int cell_height;
unsigned int cell_width;
double unit_in_meters;
};
G_DEFINE_TYPE(RendererSettingsDialog, renderer_settings_dialog, GTK_TYPE_DIALOG)
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
{
/* No special code needed. Child cells are destroyed automatically due to reference counter */
@@ -72,13 +80,89 @@ static void latex_render_callback(GtkToggleButton *radio, RendererSettingsDialog
hide_tex_options(dialog);
}
static gboolean shape_drawer_drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
{
int width;
int height;
GtkStyleContext *style_context;
GdkRGBA foreground_color;
RendererSettingsDialog *dialog = (RendererSettingsDialog *)data;
double usable_width;
double usable_height;
double height_scale;
double width_scale;
double final_scale_value;
style_context = gtk_widget_get_style_context(widget);
width = gtk_widget_get_allocated_width(widget);
height = gtk_widget_get_allocated_height(widget);
gtk_render_background(style_context, cr, 0, 0, width, height);
gtk_style_context_get_color(style_context, gtk_style_context_get_state(style_context),
&foreground_color);
gdk_cairo_set_source_rgba(cr, &foreground_color);
cairo_save(cr);
/* Tranform coordiante system */
cairo_scale(cr, 1, -1);
cairo_translate(cr, (double)width/2.0, -(double)height/2.0);
/* Define usable drawing area */
usable_width = (0.95*(double)width) - 15.0;
usable_height = (0.95*(double)height) - 15.0;
width_scale = usable_width/(double)dialog->cell_width;
height_scale = usable_height/(double)dialog->cell_height;
final_scale_value = (width_scale < height_scale ? width_scale : height_scale);
cairo_rectangle(cr, -(double)dialog->cell_width*final_scale_value/2.0, -(double)dialog->cell_height*final_scale_value/2.0,
(double)dialog->cell_width*final_scale_value, (double)dialog->cell_height*final_scale_value);
cairo_stroke(cr);
cairo_restore(cr);
return FALSE;
}
static void renderer_settings_dialog_update_labels(RendererSettingsDialog *self)
{
char default_buff[100];
double scale;
if (!self)
return;
snprintf(default_buff, sizeof(default_buff), "Width: %E", self->cell_width * self->unit_in_meters);
gtk_label_set_text(self->x_label, default_buff);
snprintf(default_buff, sizeof(default_buff), "Height: %E", self->cell_height * self->unit_in_meters);
gtk_label_set_text(self->y_label, default_buff);
scale = gtk_range_get_value(GTK_RANGE(self->scale));
snprintf(default_buff, sizeof(default_buff), "Output Width: %u px", (unsigned int)((double)self->cell_width / scale));
gtk_label_set_text(self->x_output_label, default_buff);
snprintf(default_buff, sizeof(default_buff), "Output Height: %u px", (unsigned int)((double)self->cell_height / scale));
gtk_label_set_text(self->y_output_label, default_buff);
}
static void scale_value_changed(GtkRange *range, gpointer user_data)
{
(void)range;
RendererSettingsDialog *dialog;
dialog = RENDERER_SETTINGS_DIALOG(user_data);
renderer_settings_dialog_update_labels(dialog);
}
static void renderer_settings_dialog_init(RendererSettingsDialog *self)
{
GtkBuilder *builder;
GtkWidget *box;
GtkDialog *dialog;
dialog = &(self->parent);
builder = gtk_builder_new_from_resource("/dialog.glade");
@@ -89,12 +173,27 @@ static void renderer_settings_dialog_init(RendererSettingsDialog *self)
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
self->shape_drawing = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "shape-drawer"));
self->x_label = GTK_LABEL(gtk_builder_get_object(builder, "x-label"));
self->y_label = GTK_LABEL(gtk_builder_get_object(builder, "y-label"));
self->x_output_label = GTK_LABEL(gtk_builder_get_object(builder, "x-output-label"));
self->y_output_label = GTK_LABEL(gtk_builder_get_object(builder, "y-output-label"));
gtk_dialog_add_buttons(dialog, "Cancel", GTK_RESPONSE_CANCEL, "OK", GTK_RESPONSE_OK, NULL);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), box);
gtk_window_set_title(GTK_WINDOW(self), "Renderer Settings");
g_signal_connect(self->radio_latex, "toggled", G_CALLBACK(latex_render_callback), (gpointer)self);
g_signal_connect(G_OBJECT(self->shape_drawing),
"draw", G_CALLBACK(shape_drawer_drawing_callback), (gpointer)self);
g_signal_connect(self->scale, "value-changed", G_CALLBACK(scale_value_changed), (gpointer)self);
/* Default values */
self->cell_width = 1;
self->cell_height = 1;
self->unit_in_meters = 1E-6;
renderer_settings_dialog_update_labels(self);
g_object_unref(builder);
}
@@ -155,9 +254,44 @@ void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struc
hide_tex_options(dialog);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg), TRUE);
break;
}
}
void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, unsigned int width)
{
if (!dialog)
return;
if (width == 0)
width = 1;
dialog->cell_width = width;
renderer_settings_dialog_update_labels(dialog);
}
void renderer_settings_dialog_set_cell_height(RendererSettingsDialog *dialog, unsigned int height)
{
if (!dialog)
return;
if (height == 0)
height = 1;
dialog->cell_height = height;
renderer_settings_dialog_update_labels(dialog);
}
void renderer_settings_dialog_set_database_unit_scale(RendererSettingsDialog *dialog, double unit_in_meters)
{
if (!dialog)
return;
if (unit_in_meters < 0)
unit_in_meters *= -1;
dialog->unit_in_meters = unit_in_meters;
renderer_settings_dialog_update_labels(dialog);
}
/** @} */

View File

@@ -75,6 +75,27 @@ void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struc
*/
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
/**
* @brief renderer_settings_dialog_set_cell_width Set width for rendered cell
* @param dialog
* @param width Width in database units
*/
void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, unsigned int width);
/**
* @brief renderer_settings_dialog_set_cell_height Set height for rendered cell
* @param dialog
* @param height Height in database units
*/
void renderer_settings_dialog_set_cell_height(RendererSettingsDialog *dialog, unsigned int height);
/**
* @brief renderer_settings_dialog_set_database_unit_scale Set database scale
* @param dialog dialog element
* @param unit_in_meters Database unit in meters
*/
void renderer_settings_dialog_set_database_unit_scale(RendererSettingsDialog *dialog, double unit_in_meters);
#endif /* __CONV_SETTINGS_DIALOG_H__ */
/** @} */

View File

@@ -63,6 +63,7 @@ static void layer_element_drag_begin(GtkWidget *widget,
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
(void)data;
row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_get_allocation (row, &alloc);
@@ -81,35 +82,37 @@ static void layer_element_drag_begin(GtkWidget *widget,
cairo_surface_destroy (surface);
}
static void layer_element_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
static void layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data,
guint info, guint time, gpointer data)
{
(void)context;
(void)info;
(void)time;
(void)data;
gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"),
32, (const guchar *)&widget, sizeof(gpointer));
}
static void layer_element_drag_data_received(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint32 time,
gpointer data)
static void layer_element_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
GtkSelectionData *selection_data, guint info, guint32 time,
gpointer data)
{
GtkWidget *target;
GtkWidget *row;
GtkWidget *source;
int pos;
(void)context;
(void)x;
(void)y;
(void)info;
(void)time;
(void)data;
target = widget;
pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
row = (gpointer) *(gpointer *)gtk_selection_data_get_data (selection_data);
row = (gpointer)(*(gpointer *)gtk_selection_data_get_data(selection_data));
source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
if (source == target)