Внутри gaf схема представляется набором двунаправленно-связанных списков. Центральным типом связи в списках является OBJECT. Он может быть представлением какого-нибудь символа, строки текста, графического примитива, соединения или атрибута.
Обзор структуры данных схемы можно найти здесь. Этот набросок сделан Стюартом Брорсоном (Stuart Brorson) в 2005 году.
Doxygen представляет собой утилиту для извлечения документации по API из комментариев в исходном коде. В комментариях может указываться разметка, которая впоследствии может быть преобразована программой Doxygen в код HTML или LaTeX. Это позволяет, к примеру, одной функции сослаться на другую, связанную с ней, а также даёт возможность приводить документацию об аргументах и возвращаемых значениях.
Некоторые части исходных текстов gaf уже подготовлены для работы с
doxygen. Сейчас сюда входят libgeda, gschem, gnetlist, gsymcheck и gattrib.
Файлы Makefile этих утилит в каталоге docs
содержат цель “doxygen”.
Или же вывод doxygen можно посмотреть
на этой странице, подготовленной
Бертом Тиммерманом (Bert Timmerman).
Если вы хотите узнать заложенные в Doxygen идеи о том, как надо форматировать документацию, см. веб-сайт Doxygen. Отдельные команды документированы здесь. По Doxygen есть также несколько очень удобных кратких справочных страниц.
В следующих разделах предлагается вводная информация о том, как обычно документируются gschem и libgeda. Обратите внимание, что для комментариев, разрешённых в Doxygen, предпочтительным является стиль QT вида /*! здесь идут комментарии */.
При создании нового файла в нём, очевидно, должен быть обычный текст лицензии GNU. После лицензии нужно включить комментарий о файле с описанием того, для чего этот файл, и с любым другим текстом, относящимся ко всему файлу как целому1).
/*! \file <filename.ext>
\brief Здесь краткое изложение того, для чего этот файл...
\par Описание
Более длинное описание того, для чего этот файл (необязательно).
*/
Глобальные переменные в файле можно документировать с помощью команды \var или просто написав комментарий с помощью команды \brief прямо перед определением.
/*! \brief fill style of objects like cirle, rect, path */ typedef enum {FILLING_HOLLOW, FILLING_FILL, FILLING_MESH, FILLING_HATCH, FILLING_VOID} OBJECT_FILLING;
Функции можно документировать точно так же, как и переменные и т. д. Достаточно вставить блок комментария выше документируемой им функции и начать его командой \brief.
Обычно для длинного описания назначения функции используется дополнительный параграф Function Description. Также, для определения того, будут ли параметры функции изменяться в ней самой, в командах \param используются атрибуты [in] или [out].
/*! \brief "Save" a file into a string buffer
* \par Function Description
* This function saves a whole schematic into a buffer in libgeda
* format. The buffer should be freed when no longer needed.
*
* \param [in] toplevel The current TOPLEVEL.
* \param [in] object_list The head of a GList of OBJECTs to save.
* \return a buffer containing schematic data or NULL on failure.
*/
Структуры документируются так же, как указано в предыдущих разделах. Учтите, что комментарии для членов структур могут как быть встроенными в их собственные строки, так и указываться с помощью того же синтаксиса \brief, что и для переменных. Для встраивания документации в строку в её конце должен помещаться комментарий особого вида, начинающийся с /*!<.
/*! \brief Structure for connections between OBJECTs * * The st_conn structure contains a single connection * to another object. * The connection system in s_conn.c uses this struct */ struct st_conn { OBJECT *other_object; /*!< The "other" object connected to this one */ /*! \brief type of connection. Always in reference to how the "other" object is connected to the current one */ int type; int x; /*!< x coord of the connection position */ int y; /*!< y coord of the connection position */ int whichone; /*!< which endpoint of the current object caused this connection */ int other_whichone; /*!< which endpoint of the "other" object caused this connection */ };
\bug и \todo полезны для отметки мест с недостатками или отсутствующими возможностями в коде. Эти команды могут быть вставлены в любое место внутри комментариев Doxygen, и служат они для создания записей на специальных страницах в документации, позволяющих легко найти соответствующее место.
Есть прекрасный документ от ребят из gnome под названием Gnome HIG. Насчёт дизайна диалоговых окон и насчёт того, как они должны себя вести, предложений несколько.
Дизайн диалоговых окон — это, в общем-то, дело вкуса:
Модальное окно диалога требуется во всех тех случаях, когда данные для окна обеспечиваются основным приложением.
Пример: Окно диалога вызывается со списком выбора и должно работать только с данными этого списка.
Модальное окно подходит также тогда, когда диалог вызывается очень редко. Диалоговое окно открытия файла могло бы быть немодальным, так как для него не требуется ввод никаких данных из приложения.
Модальное окно не подходит, если пользователь много взаимодействует с этим окном. Хороший пример — выбор компонентов.
Диалоговое окно можно поместить в различные места экрана. Список возможных мест можно найти в GtkReference
В настоящее время диалоги помещаются или в позиции мыши (GTK_WIN_POS_MOUSE) или ни в какой предустановленной позиции (GTK_WIN_POS_NONE). В Gnome HID по этой теме ничего не сказано.
Настройкой по умолчанию для GtkWindow является GTK_WIN_POS_NONE, см. GtkWindow. Настройкой по умолчанию для GtkDialog является GTK_WIN_POS_CENTER_ON_PARENT ( taken from the GtkDialog source).
Большинство диалоговых окон размещается перед их родительскими окнами с помощью свойства transient_for (см. GtkReference). Это свойство должно быть установлено для всех модальных диалоговых окон.
Для немодальных диалоговых окон установка свойства transient_for не очевидна. В то время как, например, в gschem диалоговое окно координат должно находиться над родительским окном, окно журнала вешать перед ним нужды нет.
Примечание: Существует более старый механизм, удерживающий эти окна перед gschem. Если переменная raise-dialog-boxes-on-expose устанавливается в enabled в одном из файлов настроек gschem, она может вызвать проблемы с некоторыми оконными менеджерами. Если диалоговые окна мерцают при 100%-ной загрузке CPU, запретите эту настройку.
; raise-dialog-boxes-on-expose string ; ; Должны ли диалоговые окна подниматься всякий раз, когда появится ; событие expose ; По умолчанию включено (enabled) ; ;(raise-dialog-boxes-on-expose "enabled") (raise-dialog-boxes-on-expose "disabled")
Порядок кнопок внизу диалогового окна зависит от используемой операционной системы. GTK обрабатывает это автоматически, но требует, чтобы разработчики установили альтернативный порядок кнопок. Более подробно об этом написано в документации по GTK здесь.
Альтернативный порядок кнопок задаётся только с помощью одного вызова GTK-функции:
/* Настройка альтернативного порядка кнопок (ok, no, cancel, help) для других систем */ gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, GTK_RESPONSE_HELP, -1);
Это должно быть сделано перед запуском каждого нового создаваемого диалогового окна.
Этот шаблон не предназначен для компиляции, но отсюда легко скопировать нужный вам блок кода.
void dialog (TOPLEVEL *w_current) { GtkWidget *vbox, *label, *alignment, *table; GtkWidget *dialog; /* Создавать диалоговое окно только тогда, когда его ещё нет. Обычно это указатель на виджет в структуре w_current: dialog = w_current->tewindow */ if (!dialog) { dialog = gtk_dialog_new_with_buttons(_("Dialog title"), /* родительское окно или NULL */ GTK_WINDOW(w_current->main_window), /* свойства диалога */ GTK_DIALOG_MODAL, /* 0 для немодальных диалоговых окон */ /* кнопки окна и сигналы ответа */ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); /* Настройка альтернативного порядка кнопок (ok, no, cancel, help) для других систем */ gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, GTK_RESPONSE_HELP, -1); /* Установить сигнал ответа по умолчанию. Он обычно вызывается по нажатию "Return" */ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); /* Задать функцию для обработки ответов кнопок и закрытия диалогового окна, для немодальных окон можно также использовать dialog_run().*/ gtk_signal_connect(GTK_OBJECT(dialog), "response", GTK_SIGNAL_FUNC(dialog_response), w_current); /* Где размещать диалоговое окно: GTK_WIN_POS_MOUSE или GTK_WIN_POS_NONE */ gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); /* Задать расстояние от границы окна и расстояние между элементами по вертикали */ vbox = GTK_DIALOG(dialog)->vbox; gtk_container_set_border_width(GTK_CONTAINER(dialog),DIALOG_BORDER_SPACING); gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING); /* Создать метку (со спецразметкой) и упаковать её в диалоговое окно */ label = gtk_label_new(_("<b>Section label</b>")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label),0,0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); /* Создать контейнер выравнивания с DIALOG_INDENTATION слева */ alignment = gtk_alignment_new(0,0,1,1); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, DIALOG_INDENTATION, 0); gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); /* Таблица может содержать несколько записей. Она сохраняется в контейнере выравнивания. Примечание: расстояния между ячейками по вертикали и горизонтали */ table = gtk_table_new (3, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING); gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING); gtk_container_add(GTK_CONTAINER(alignment), table); /* Простая текстовая метка в одной ячейке таблицы с левым выравниванием. Примечание: GTK_FILL в третьей строке обязательно */ label = gtk_label_new(_("Text:")); gtk_misc_set_alignment(GTK_MISC(label),0,0); gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0); /* Простое поле ввода текста завершает ряд опций */ textentry = gtk_entry_new_with_max_length (10); gtk_table_attach_defaults(GTK_TABLE(table), textentry, 1,2,0,1); gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE); /* ..... ещё строки таблицы с опциями или новые разделы */ /* Создать ссылки на все виджеты, которые потребуются в дальнейшем */ GLADE_HOOKUP_OBJECT(dialog, sizeentry,"textentry"); /* Показывать все значения рекурсивно */ gtk_widget_show_all(dialog); } else { /* Окно уже здесь. Показать его пользователю. Это необходимо только для немодального диалогового окна */ gtk_window_present(GTK_WINDOW(dialog)); } /* Всегда задавать в диалоговом окне текущие значения Если поместить эту часть в конец функции диалогового окна, это позволит легко создавать диалоги, которые можно будет вызывать, даже если они уже открыты */ textentry = g_object_get_data(G_OBJECT(dialog), "textentry"); gtk_entry_set_text(GTK_ENTRY(textentry), string); /* Выделение области текста, которую пользовать обычно любит заменять */ gtk_entry_select_region(GTK_ENTRY(textentry), 0, strlen(string)); }
Функция ответа для такого диалогового окна может выглядеть так:
void dialog_response(GtkWidget *widget, gint response, TOPLEVEL *w_current) { switch (response) { case GTK_RESPONSE_ACCEPT: /* Применить установки диалогового окна: просто вставьте свой код здесь, если он короткий; или вызовите внешнюю функцию применения, если требуемый код длинный */ break; case GTK_RESPONSE_REJECT: case GTK_RESPONSE_DELETE_EVENT: /* Для модальных окон просто ничего не делаем, для немодальных окон, уничтожаем диалог и прибираемся */ break; default: /* Ловим ошибочные сигналы (параноидальная проверка ошибок ;-)) */ printf("dialog_response(): strange signal %d\n", response); } /* Для немодальных окон просто ничего не делаем, для модальных окон всегда уничтожаем диалог и прибираемся */ }
Здесь список вещей, которые могли бы быть улучшены: