ПРОГРАММИРОВАНИЕ ДЛЯ X Window System С БИБЛИОТЕКОЙ OSF/MOTIF.
Кожекин Н.
Open Software Foundation Motif (эк. OSF/Motif) - это библиотека
виджетов, построенная на базе X Toolkit Intrinsics, менеджер окон и
набор утилит вспомогательных операций. На данный момент этот пакет
стал фактическим стандартом в области программирования для X Window.
Стиль startx из Linux - это и есть стиль Motif. Эта библиотека
является коммерческой разработкой и вместе с Linux не
распространяется. Пользователь Linux может купить эту библиотеку за
цену порядка 200 $ США или заказать при помощи ftp mail ее
некоммерческую замену - библиотеку Lesstif, пока доступную лишь в
версиях для тестирования.
Компиляция Motif программы производится следующей командой cc
sourcefile.c -o outputfile.c -lX11 -lXt -lXm. Программа написанная на
Motif включает #include и заголовки для всех используемых
объектов, причем имя файла включения образуется от имени
соответствующего виджета с изменением слова Window на W, а Button на
B. Например, если вы используете объект Toggle Button, то вы должны в
начале программы написать #include . Все процедуры и
классы объектов Motif начинаются с префикса Xm, ресурсы с префикса
XmN, классы ресурсов с префикса XmC, типы ресурсов с префикса XmR, а
указатели классов объектов с префикса xm. Причем поддерживаемые Xt
ресурсы имеют полные аналоги с префиксом Xm. Иерархия виджетов и
ресурсов Motif показаны на рисунках 1 и 2. Каждый виджет наследует
ресурсы от более высокого класса ресурсов.
Core
_____________:_________
: :
Composite XmPrimitive
___:____ :
: : :
Shell Constraint Primitive Widgets
:
XmManager
:
Manager Widgets
Рис. 1
OBJECT
:
RECTOBJECT
_______________________:________
: :
: gadget
: __________________:______________
: : : :
: arrowbuttongadget labelgadget sepatatorgadget
: __________________:_______________
: : : :
: cascedebuttongadget pushbuttongadget togglebuttongadget
:
:_____________________________CORE
_______________________________:__________________
: :
COMPOSITE primitive
____:___ ________________________________:________________
: : : : : : : : :
SHELL CONSTRAINT arrowbutton label list scrollbar separator text textfield
: : :_________________________________________
: manager : : : :
: : cascedebutton drawnbutton pushbutton togglebutton
: |_______________________________________________________
: | : : : : : :
:bulletinboard drawingarea frame panedwindow rowcolmn scale mainwindow
: :_______________________________________ :
:_____________ : : : scrolledwindow
: : form selectionbox messagebox
WMSHELL OVERRIDESHELL ______:______
: : : :
VENDORSHELL menushell command fileselectionbox
___:______________
: :
TOPLEVELSHELL TRANSIENTSHELL
: :
APLICATIONSHELL dialogshell
Рис. 2. Полная иерархия классов Xt и Motif. Классы Xt написаны
большими буквами, классы Xm маленькими.
Core - вершина иерархии Xt intrinsics. Этот суперкласс задает фон, размер,
и позицию, ресурсы обычные для всех виджетов.
XmPrimitive - суперкласс примитивных виджетов.
XmManager - суперкласс manager виджетов.
XmGadget - суперкласс гаджетов.
Composite - суперкласс контейнеров виджетов. Имеет два подкласса Shell и
Constraint.
Primitive Widgets
Arrow button - кнопка с ориентируемой стрелкой.
Label - имеет четыре подкласса PushButton, DrawnButton, CascedeButton
и ToggleButton.
Scrollbar - позволяет содержание окна смотреть пользователю по частям,
скроллируя их.
Separator - используется для отделения виджетов в окне.
List - допускает выбор из списка текстовых элементов.
Text - полноэкранный текстовый редактор.
TextField - однострочный текстовый редактор.
Gadgets
Есть много случаев в Motif программировании, когда программист хочет
использовать примитивный виджет, но не хочет использовать окно.
Motif предлагает гаджеты - безоконные виджеты. Три гаджета предложены
- ArrowButtonm, Label и Separator, которые ведут как соответствующие
виджеты.
Manager Widgets
Frame - представляет эффект трехмерных бордюров для окон.
ScrolledWindow - позволяет скроллирование окну.
MainWindow - типичный toplevel контейнер для виджетов. Может
содержать много виджетов, как меню, скроллеры и т.п.
DrawingArea - представляет виджет для изображения графики. Motif
здесь не предлагает своих средств, и вы должны использовать XLib
функции.
PanedWindow - виджет для объединения разнородных виджет.
Scale - объект масштабного изменения для пользовательского ввода.
RowColmn - широко используемый виджет для расположения виджет в 2D
стиле.
BulletinBoard - имеет подклассы
Form - похож на RowColmn.
Dialog - имеется два типа диалогов : MessageBox, для выдачи
информации пользователю и SelectionBox, для интерактивной работы
с пользователям. Предлагаются также Comand и FileSelectionBox.
Shell Widgets и Constraint Widgets
Все виджеты содержатся в Shell Widget, работа которого заключается в
интерфейсе к оконному менеджеру. Aplication Shell - это обычная
оболочка для приложений. Override Shell - используется для
всплывающих pop-up меню. Transient Shell используется для диалогов.
Constraint виджеты используются для организации геометрии набора
виджетов.
Все виджеты и их ресурсы подробно описаны в Motif Programming Manual
и Motif Reference Manual. Смотрите их для подробностей.
Программа Xcolor.c, приведенная мной в качестве примера иллюстрирует
использование пользовательского ввода с мыши в DrawingArea и
представляет собой простейший графический редактор. Эта программа
позволяет пользователю выбрать цвет и рисовать им различной толщины
пунктирные и целые линии, а так же закрашенные и пустые
четырехугольники. Пользователю предоставляется так же возможность
загрузить картинку из pixmap-файла и очистить экран.
Как мы собираемся достичь этого?
Для нашего виджета (DrawingArea) мы создадим следующую таблицу
трансляций
: draw_mouse(down) ManagerGadgetArm()
: draw_mouse(up) ManagerGadgetActivate()
: draw_mouse(motion) ManagerGadgetButtonMotion()
Для регистрации нашей процедуры обратного вызова мы используем как
обычно функцию XtAppAddActions() и процедуру
XtParseTranslationTable(String*) для присваивания таблицы трансляций
ресурсу XtNtranslations. Наша процедура обратного вызова (draw_mouse)
должна реагировать на события мыши следующим образом: Mouse Down -
только запоминаем координаты мыши (x,y) Mouse Up - рисуем наш
графический примитив от запомненных координат до полученных сейчас
Mouse Motion - рисуем пунктирный силуэт нашего графического
примитива.
Картинка нарисованная пользователем должна восстанавливаться если окно
было накрыто другим или минимизировано. Для этого мы используем
Pixmap - вне экранный Drawable Area. Pixmap создается функцией
XCreatePixmap, освобождается функцией XFreePixmap. Скопировать Pixmap
в окно или наоборот можно функцией XCopyArea. Каждый раз когда
пользователь рисует что-либо в окне, программа сохраняет рисунок в
Pixmap. При получении события expose программа копирует содержание
Pixmap в свое окно.
Для переключения рисования прямоугольников и прямых, а также
заполненности или пустоты рисуемых объектов я использовал кнопки типа
Toggle, которые можно создать процедурой XtVaCreateManagedWidget() с
указателем xmToggleButtonWidgetClass или XmCreateToggleButton(). Вот
несколько важных toggle ресурсов:
XmNindicatorOn - установите этот ресурс True, если хотите, чтобы
сначала индикатор был нажат (по умолчанию значение этого ресурса
False),
XmNindicatorSize - меняет размер индикатора в пикселях,
XmNlabelType - тип наклейки: XmSTRING (строка) или XmPIXMAP
(рисунок),
XmNlabelString - строка наклейки,
XmNlabelPixmap - рисунок ненажатой наклейки (структура типа Pixmap),
XmNselectPixmap - Pixmap нажатой наклейки,
XmNselectColour - цвет нажатой кнопки (структура типа Pixel).
Для расположения кнопок в форме используется механизм привязок.
Привязки разделены на верхние (top), нижние (bottom), левые (left) и
правые (right). Виджет соответственно имеет четыре ресурса типа
XmN...Attachment. Чтобы привязать виджет к родительской форме
установите этот ресурс значением XmATTACH_FORM. Чтобы привязать
виджет к другому виджет используется значение XmATTACH_WIDGET, а
ресурс XmNwidget установите соответственно выбранному виджету. Для
привязки одного виджета напротив другого установите ресурс привязки
значением XmATTACH_OPOSITE_WIDGET. Чтобы привязать виджет какой-либо
точке установите ресурс XmN...Attachment значением XmATTACH_POSITION,
а ресурс XmN...Position установите соответствующим целым значением.
Для обеспечения пользователем изменения размера линии можно
использовать виджет Scale (реализован в примере в листинге).
Создается этот виджет процедурой XmCreateScale. Некоторые его ресурсы
очень важны:
XmNmaximum - наибольшее значение (int),
XmNminimum -наименьшее значение (int, по-умолчанию 0),
XmNorientation - этот ресурс может иметь значения XmHORISONTAL или
XmVERTICAL (с очевидной интерпретацией),
XmNtitleString - ресурс типа XmString : название,
XmNDecimalPoints - (по умолчанию 0) количество знаков отделяемых для
десятичного представления после целой части,
XmNShowValue - True или False : отображать числом выбранный результат
или нет,
XmNValue - начальное значение (int), XmNprocessingDirection -
XmMAX_ON_TOP, Xm_MAX_ON_BOTTOM, XmMAX_ON_LEFT или XmMAX_ON_RIGHT :
определяет положение максимума (зависит от XmNorintation).
Специальные объекты для диалога с пользователем называются в Motif
Dialogs. Диалоги открывают окно с общением и могут принимать
некоторый пользовательский ввод. Пользователю обычно предоставляется
три кнопки -- Ok, Cancel и Help -- первые две позволяют пользователю
согласиться или нет с предложенным и окончить диалог, а третья может
предоставлять дополнительную информацию. Не забудьте, что для того
чтобы диалог появился в вашей программе вы должны применить операцию
manage к соответствующему виджет, а чтобы диалог исчез операцию
unmanage. Вот предоставляемые Motif диалоги:
BulletinBoardDialog - это диалог полностью задаваемый программистом:
сам по себе он ничего не содержит,
ErrorDialog - извещает пользователя об ошибке в работе программы,
SelectionDialog - предоставляет пользователю выбор из листа опций
(кнопки Aplay, Cancel, Help),
FileSelectionDialog - специальный selectiondialog для выбора файлов
и директорий (кнопки Ok, Filter, Cancel),
InformationDialog - выводит дополнительную информацию о программе,
PromptDialog - позволяет пользователю ввести строку данных для
программы,
QuestionDialog - вопросы типа Yes/No (кнопки соответственно),
WarningDialog - извещает пользователя о проблемах в работе программы,
WorkingDialog - извещает пользователя о работе программы.
Любой диалог можно создать процедурой XmCreate...Dialog(), а
программируются они все почти идентично.
Все нижеизложенные принципы программирования (и некоторые другие) в
системе Motif подробно иллюстрирует программа из листинга 2 (листинг
1 [makefile] собирает программу [xcolor.c] из листинга 2). Для
любой информации по поводу пишите -- (e-mail).
Листинг 1. makefile
#
# Makefile для программы XColor -- пример
# для Motif программистов
CC = gcc
# Если вы хотите компилировать для дебагинга поменяйте
# опции: "-O" на "-g"
CFLAGS = -O2
XM_LIBS = -lX11 -lXt -lXm
XColor : Xcolor.o
${CC} ${LDFLAGS} -o $@ Xcolor.c ${XM_LIBS}
clean:
rm -f core ${OBJS} *.o
# замените в выше представленном тексте восемь
# пробелов на символ табуляции
|
Листинг 2. xcolor.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void ScrubDial(Widget, int);
GC gc;
XGCValues gcv;
Widget draw, top_wid, main_w, widget, menu_bar;
Display *display;
Colormap cmap;
Pixmap pix_map;
Widget
String colours[] = { "Black", "Red", "Green",
"Blue", "Grey", "White"};
String activites[] = { "Rectangle" , "Line" };
/* некоторые начальные установки */
long int actived = 0; /* рисование линий */
Bool ifSolid = 0; /* не заштриховывать квадраты,
а линии рисовать сплошными */
unsigned int line_width = 1;
long int fill_pixel = 1;
/* сохраняет текущий цвет заливки
(по-умолчанию черный)*/
main(int argc, char *argv[])
{ Widget quit, clear, colour, scale, Buttons,
file_select;
XtAppContext app;
XmString clears, colurss, red, green, blue,
black, grey, white;
XtActionsRec actions;
void clear_call(), colour_call(), scale_pop_up(),
restore_pixmap(), draw_mouse(), brush_call(),
activites_call(), quit_pop_up(),
buttons_pop_up(), select_pop_up();
String translations =
": draw_mouse(motion)
ManagerGadgetButtonMotion() \n\
: draw_mouse(down) ManagerGadgetArm() \n\
: draw_mouse(up) ManagerGadgetActivate()";
top_wid = XtVaAppInitialize(&app, "Draw", NULL, 0,
&argc, argv, NULL,
XmNwidth, 500,
XmNheight, 500,
NULL);
main_w = XtVaCreateManagedWidget("main_window",
xmMainWindowWidgetClass, top_wid,
XmNwidth, 500,
XmNheight, 500,
NULL);
/* Создание простейшей панели меню */
clears = XmStringCreateSimple("Clear");
colourss = XmStringCreateSimple("Colour");
menu_bar = XmVaCreateSimpleMenuBar(main_w,
"main_list", XmVaCASCADEBUTTON, clears, 'C',
XmVaCASCADEBUTTON, colourss, 'o',
NULL);
XtManageChild(menu_bar);
/* Первое меню -- clear ; его процедура
обратного вызова clear_call() */
XmVaCreateSimplePulldownMenu(menu_bar,
"clear_menu", 0, clear_call, XmVaPUSHBUTTON,
clears, 'C', NULL, NULL, NULL);
XmStringFree(clears);
/* создание colour pull down menu */
black = XmStringCreateSimple(colours[0]);
red = XmStringCreateSimple(colours[1]);
green = XmStringCreateSimple(colours[2]);
blue = XmStringCreateSimple(colours[3]);
grey = XmStringCreateSimple(colours[4]);
white = XmStringCreateSimple(colours[5]);
colour = XmVaCreateSimplePulldownMenu(menu_bar,
"edit_menu", 1, colour_call,
XmVaRADIOBUTTON, black, 'k', NULL, NULL,
XmVaRADIOBUTTON, red, 'R', NULL, NULL,
XmVaRADIOBUTTON, green, 'G', NULL, NULL,
XmVaRADIOBUTTON, blue, 'B', NULL, NULL,
XmVaRADIOBUTTON, grey, 'e', NULL, NULL,
XmVaRADIOBUTTON, white, 'W', NULL, NULL,
XmNradioBehavior, True,
XmNradioAlwaysOne, True, NULL);
XmStringFree(black);
XmStringFree(red);
XmStringFree(green);
XmStringFree(blue);
XmStringFree(grey);
XmStringFree(white);
/* установить по молчанию выбранным черный цвет */
if ( widget = XtNameToWidget(colour,"button_0"))
XtVaSetValues(widget, XmNset, True, NULL);
/* Создаем DrawingArea виджет. */
/* создаем новые процедуры действия */
actions.string = "draw_mouse";
actions.proc = draw_mouse;
XtAppAddActions(app, &actions, 1);
draw = XtVaCreateWidget("draw",
xmDrawingAreaWidgetClass, main_w,
XmNtranslations,
XtParseTranslationTable(translations),
XmNbackground,
WhitePixelOfScreen(XtScreen(main_w)),
NULL);
XtAddEventHandler( draw, ExposureMask, False,
(XtEventHandler) restore_pixmap, NULL);
cmap = DefaultColormapOfScreen(XtScreen(draw));
display = XtDisplay(draw);
/* устанавливаем DrawingArea как
"work area" главного окна */
XtVaSetValues(main_w,
XmNmenuBar, menu_bar,
XmNworkWindow, draw,
NULL);
/* Создаем графический контекст -- GC. Ассоциируем
его с ресурсом XmNuserData виджета DrawingArea. */
gcv.foreground = BlackPixelOfScreen(XtScreen(draw));
gc = XCreateGC(XtDisplay(draw),
RootWindowOfScreen(XtScreen(draw)),
GCForeground, &gcv);
XtManageChild(draw);
scale =XtVaCreateManagedWidget("Scale",
xmCascadeButtonWidgetClass, menu_bar,
XmNmnemonic, 'S', NULL);
XtAddCallback(scale, XmNactivateCallback,
scale_pop_up,"Select the size of lines you draw.");
quit = XtVaCreateManagedWidget("Quit",
xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic,
'Q', NULL);
XtAddCallback(quit, XmNactivateCallback,
quit_pop_up, "Are you sure you want to quit?");
Buttons = XtVaCreateManagedWidget("Buttons",
xmCascadeButtonWidgetClass, menu_bar, XmNmnemonic,
'B', NULL);
XtAddCallback(Buttons, XmNactivateCallback,
buttons_pop_up, NULL);
file_select = XtVaCreateManagedWidget("File",
xmCascadeButtonWidgetClass, menu_bar,
XmNmnemonic, 'F', NULL);
XtAddCallback(file_select, XmNactivateCallback,
select_pop_up, NULL);
XtRealizeWidget(top_wid);
pix_map = XCreatePixmap(display,
RootWindowOfScreen(XtScreen(draw)), 500, 500, 8);
/* 8 - цветной экран, изменить на 1
если черно-белый*/
clear_call;
XtAppMainLoop(app);
}
/* POP UPS */
void scale_pop_up(Widget cascade_button, char *text,
XmPushButtonCallbackStruct *cbs)
{ Widget dialog, a_scale;
XmString title[2];
void scale_cbk();
Arg args[2];
title[0] = XmStringCreateSimple(text);
XtSetArg(args[0], XmNmessageString, title[0]);
XtSetArg(args[1], XmNdefaultButtonType, XmDIALOG_OK_BUTTON);
dialog = XmCreateInformationDialog(cascade_button, "prompt",
args, 2);
XmStringFree(title[0]);
ScrubDial(dialog, XmDIALOG_HELP_BUTTON);
ScrubDial(dialog, XmDIALOG_CANCEL_BUTTON);
XtManageChild(dialog);
title[1] = XmStringCreateSimple("Size");
a_scale = XtVaCreateManagedWidget("scale",
xmScaleWidgetClass, dialog,
XmNtitleString, title[1],
XmNorientation, XmHORIZONTAL,
XmNvalue, line_width,
XmNmaximum, 11,
XmNminimum, 1,
XmNdecimalPoints, 0,
XmNshowValue, True,
XmNwidth, 200,
XmNheight, 100,
NULL);
XtAddCallback(a_scale, XmNvalueChangedCallback,
scale_cbk, NULL);
XmStringFree(title[1]);
XtPopup(XtParent(dialog), XtGrabNone);
}
void quit_pop_up(Widget cascade_button, char *text,
XmPushButtonCallbackStruct *cbs)
{ Widget dialog;
XmString xm_string;
void quit_call();
Arg args[2];
xm_string = XmStringCreateSimple(text);
XtSetArg(args[0], XmNmessageString, xm_string);
XtSetArg(args[1], XmNdefaultButtonType,
XmDIALOG_CANCEL_BUTTON);
dialog = XmCreateWarningDialog(cascade_button,
"quit", args, 2);
XmStringFree(xm_string);
ScrubDial(dialog, XmDIALOG_HELP_BUTTON);
XtAddCallback(dialog, XmNokCallback,
quit_call, NULL);
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
void buttons_pop_up(Widget cascade_button, char *text,
XmPushButtonCallbackStruct *cbs)
{ Widget dialog, form, brush, action;
XmString xm_string;
void brush_call(), action_call();
dialog = XmCreateBulletinBoardDialog(cascade_button,
"buttons", NULL, 0);
XtManageChild(dialog);
form = XtVaCreateWidget("form", xmFormWidgetClass,
dialog, XmNfractionBase, 3, NULL);
brush = XtVaCreateManagedWidget("Solid/Empty",
xmToggleButtonWidgetClass,
form, XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM, NULL);
XtAddCallback(brush, XmNvalueChangedCallback,
brush_call, NULL);
action = XtVaCreateManagedWidget(
"Lines/Rectangles", xmToggleButtonWidgetClass,
form, XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, brush, XmNleftAttachment,
XmATTACH_FORM, XmNbottomAttachment,
XmATTACH_FORM, NULL);
XtAddCallback(action, XmNvalueChangedCallback,
action_call, NULL);
XtManageChild(form);
XtPopup(XtParent(dialog), XtGrabNone);
}
void select_pop_up(Widget cascade_button, char *text,
XmPushButtonCallbackStruct *cbs)
{ Widget dialog, remove;
void select_activate(), cancel();
XmString mask;
Arg args[1];
/* Create the FileSelectionDialog */
mask = XmStringCreateSimple("*.*");
XtSetArg(args[0], XmNdirMask, mask);
dialog = XmCreateFileSelectionDialog(cascade_button,
"select", args, 1);
XtAddCallback(dialog, XmNokCallback,
select_activate, NULL);
XtAddCallback(dialog, XmNcancelCallback,
cancel, NULL);
remove = XmSelectionBoxGetChild(dialog,
XmDIALOG_HELP_BUTTON);
XtUnmanageChild(remove); /* убираем кнопку HELP*/
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
void select_activate(Widget widget, caddr_t
client_data, XmFileSelectionBoxCallbackStruct
*selection)
{
FILE *fp, *fopen();
char *filename, line[200];
void error();
XmStringGetLtoR(selection->value,
XmSTRING_DEFAULT_CHARSET, &filename);
if ( (fp = fopen(filename,"r")) == NULL)
error(widget, "CANNOT OPEN FILE", filename);
else
{
pix_map = XmGetPixmap(XtScreen(draw), filename,
WhitePixelOfScreen(XtScreen(draw)),
BlackPixelOfScreen(XtScreen(draw)));
fclose(fp); XtUnmanageChild(widget);
}
}
void cancel(Widget widget, caddr_t client_data,
XmFileSelectionBoxCallbackStruct *selection)
{ XtUnmanageChild(widget); /* убираем виджет */ }
void error(Widget widget, char *s1, char * s2)
{
Widget dialog;
XmString xm_string;
void help_cbk();
Arg args[2];
xm_string = XmStringCreateSimple(s2);
XtSetArg(args[0], XmNmessageString, xm_string);
XtSetArg(args[1], XmNdefaultButtonType,
XmDIALOG_OK_BUTTON);
dialog = XmCreateErrorDialog(widget,
"error", args, 2);
XtAddCallback( dialog, XmNhelpCallback,
help_cbk, s1);
XmStringFree(xm_string);
ScrubDial(dialog, XmDIALOG_CANCEL_BUTTON);
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
/* CALL BACKS */
void help_cbk(Widget w, char* S1)
{ Widget dialog;
XmString title;
void scale_cbk();
Arg args[2];
title = XmStringCreateSimple(S1);
XtSetArg(args[0], XmNmessageString, title);
XtSetArg(args[1], XmNdefaultButtonType,
XmDIALOG_OK_BUTTON);
dialog = XmCreateInformationDialog(w, "help",
args, 2);
XmStringFree(title);
ScrubDial(dialog, XmDIALOG_HELP_BUTTON);
ScrubDial(dialog, XmDIALOG_CANCEL_BUTTON);
XtManageChild(dialog);
XtPopup(XtParent(dialog), XtGrabNone);
}
void quit_call()
{
XFreePixmap(display, pix_map);
printf("Quitting program\n");
exit(0);
}
void clear_call() /* очищает work area*/
{ XClearWindow(display, XtWindow(draw));
XCopyArea( display, XtWindow(draw), pix_map, gc,
0, 0, 500, 500, 0, 0);
}
void brush_call(Widget widget, XtPointer client_data,
XmToggleButtonCallbackStruct *state )
{ ifSolid = state->set; }
void scale_cbk(Widget widget, int data,
XmScaleCallbackStruct *scale_struct)
{ line_width = scale_struct->value;}
void action_call(Widget widget, XtPointer client_data,
XmToggleButtonCallbackStruct *state )
{ actived = state->set; }
/* вызывается от любых пунктов меню "Colour". */
void colour_call(w, item_no)
Widget w;
int item_no;
{
int n =0;
Arg args[1];
XColor xcolour, spare;
if (XAllocNamedColor(display, cmap,
colours[item_no], &xcolour, &spare) == 0)
return;
fill_pixel = xcolour.pixel;
}
/* DrawingArea Callback.*/
void draw_mouse(Widget w, XButtonEvent *event,
String *args, int *num_args)
{ static Position x, y, last_x, last_y;
Position width, height;
int line_style;
int cap_style = CapRound;
int join_style = JoinRound;
if (strcmp(args[0], "down") == 0)
{ /* фиксируем начальную точку */
x = event->x;
y = event->y;
}
else
if (strcmp(args[0], "motion") == 0)
{ line_style = LineOnOffDash;
XSetLineAttributes(event->display, gc,
1, line_style, cap_style, join_style);
gcv.foreground
= WhitePixelOfScreen(XtScreen(w));
XSetForeground(event->display, gc,
gcv.foreground);
XSetFunction(event->display,
gc, GXinvert);
if (actived == 1) {
XDrawLine(event->display,
event->window, gc, x, y, last_x, y);
XDrawLine(event->display, event->window,
gc, last_x, y, last_x, last_y);
XDrawLine(event->display, event->window,
gc, last_x, last_y, x, last_y);
XDrawLine(event->display, event->window,
gc, x, last_y, x, y); } else
XDrawLine(event->display, event->window,
gc, x,y, last_x, last_y);
XCopyArea( event->display,
event->window, pix_map, gc,
0, 0, 500, 500, 0, 0);
gcv.foreground
= BlackPixelOfScreen(XtScreen(w));
XSetForeground(event->display, gc,
gcv.foreground);
if (actived == 1)
{XDrawLine(event->display, event->window,
gc, x, y, event->x, y);
XDrawLine(event->display, event->window,
gc, event->x, y, event->x, event->y);
XDrawLine(event->display, event->window,
gc, event->x, event->y, x, event->y);
XDrawLine(event->display, event->window,
gc, x, event->y, x, y);}
else
{XDrawLine(event->display,
event->window, gc,
x, y, event->x, event->y);}}
else
if (strcmp(args[0], "up") == 0)
{ /* рисуем полную линию */
XSetFunction(event->display, gc, GXcopy);
if (ifSolid == 0 ) line_style = LineSolid;
else line_style = LineOnOffDash;
if (actived == 1 ) line_style = LineSolid;
/* устанавливаем атрибуты линии */
XSetLineAttributes(event->display, gc,
line_width, line_style, cap_style, join_style);
XSetForeground(event->display, gc, fill_pixel);
if (actived == 1 ) {
XDrawLine(event->display, event->window, gc,
x, y, event->x, y);
XDrawLine(event->display, event->window, gc,
event->x, y, event->x, event->y);
XDrawLine(event->display, event->window, gc,
event->x, event->y, x, event->y);
XDrawLine(event->display, event->window, gc,
x, event->y, x, y);} else
{XDrawLine(event->display, event->window, gc,
x, y, event->x, event->y); }
if ((event->y) > y) height = event->y - y;
else { height = y; y = event->y -y; }
if ((event->x) > x) width = event->x - x;
else { width = x; x = event->x -x; }
if (actived == 1)
{ if (ifSolid == 0)
{ XFillRectangle(event->display, event->window,
gc, x, y, width, height); } else
{ XDrawRectangle(event->display, event->window,
gc, x, y, width, height); }
}
XCopyArea( event->display, event->window, pix_map, gc,
0, 0, 500, 500, 0, 0);
}
last_x = event->x;
last_y = event->y;
}
/* восстановление содержания drawingarea */
void restore_pixmap(Widget drawidget,
XtPointer pUserData, XEvent *userEvent,
Boolean *pbContinue)
{
XCopyArea(XtDisplay(drawidget), pix_map,
(XtWindow(drawidget)), gc, 0, 0, 500, 500, 0, 0);
}
/* исключение DialButton из диалога */
void ScrubDial(Widget wid, int dial)
{ Widget remove;
remove = XmMessageBoxGetChild(wid, dial);
XtUnmanageChild(remove);
}
|
|