Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока, изображающего двухкоординатную рукоятку, которую пользователь может перемещать мышью.
// Реакция на перемещение курсора мыши (п.2.12.2) #include <windows.h> #include <RdsDef.h> // Подготовка описаний сервисных функций #define RDS_SERV_FUNC_BODY GetInterfaceFunctions #include <RdsFunc.h> //========== Главная функция DLL ========== int WINAPI DllMain(HINSTANCE /*hinst*/, unsigned long reason, void* /*lpReserved*/) { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL { // Получение доступа к функциям RDS if(!GetInterfaceFunctions()) RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS } return 1; } //========= Конец главной функции ========= //====== Класс личной области данных ====== class TSimpleJoystick { private: // Центр круга (рукоятки) до начала перетаскивания int OldHandleX,OldHandleY; // Координаты курсора на момент начала перетаскивания int OldMouseX,OldMouseY; public: // Настроечные параметры блока COLORREF BorderColor; // Цвет рамки блока COLORREF FieldColor; // Цвет прямоугольника COLORREF HandleColor; // Цвет круга в покое COLORREF MovingHandleColor; // Цвет круга при таскании int HandleSize; // Диаметр круга // Реакция на нажатие кнопки мыши int MouseDown(RDS_PMOUSEDATA mouse,double x,double y,DWORD *pFlags); // Реакция на перемещение курсора мыши void MouseMove(RDS_PMOUSEDATA mouse,double *px,double *py); // Рисование изображения блока void Draw(RDS_PDRAWDATA draw,double x,double y,BOOL moving); // Конструктор класса TSimpleJoystick(void) { BorderColor=0; // Черная рамка FieldColor=0xffffff; // Белое поле HandleColor=0xff0000; // Синий круг MovingHandleColor=0xff; // Красный при таскании HandleSize=20; // Диаметр круга }; }; //========================================= // Рисование изображения блока void TSimpleJoystick::Draw(RDS_PDRAWDATA draw, double x,double y,BOOL moving) { int hx,hy,cx,cy; RECT r; int hR=HandleSize*draw->DoubleZoom/2; // Радиус круга-рукоятки // Если размер блока - нулевой, рисовать негде if(draw->Height==0 || draw->Width==0) return; // Рисование поля блока rdsXGSetPenStyle(0,PS_SOLID,1,BorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,FieldColor); rdsXGRectangle(draw->Left,draw->Top, draw->Left+draw->Width,draw->Top+draw->Height); // Вычисление центра прямоугольника блока cx=draw->Left+draw->Width/2; cy=draw->Top+draw->Height/2; // Вычисление координат центра круга-рукоятки hx=cx+x*draw->Width/2; hy=cy-y*draw->Height/2; // Установка области отсечения r.left=draw->Left+1; r.top=draw->Top+1; r.right=draw->Left+draw->Width-1; r.bottom=draw->Top+draw->Height-1; rdsXGSetClipRect(&r); // Линии перекрестия rdsXGMoveTo(cx,draw->Top); rdsXGLineTo(cx,draw->Top+draw->Height); rdsXGMoveTo(draw->Left,cy); rdsXGLineTo(draw->Left+draw->Width,cy); // Рисование круга (цвет зависит от параметра moving) rdsXGSetPenStyle(RDS_GFSTYLE,PS_NULL,0,0,0); rdsXGSetBrushStyle(0,RDS_GFS_SOLID, moving?MovingHandleColor:HandleColor); rdsXGEllipse(hx-hR,hy-hR,hx+hR+1,hy+hR+1); // Отмена отсечения rdsXGSetClipRect(NULL); } //========================================= // Реакция на нажатие кнопки мыши int TSimpleJoystick::MouseDown(RDS_PMOUSEDATA mouse, double x,double y,DWORD *pFlags) { int hx,hy,cx,cy, hR=HandleSize*mouse->DoubleZoom/2; // Радиус круга // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) return RDS_BFR_DONE; // Если нажата не левая кнопка, перетаскивать не надо // Разрешаем в этом случае вызов контекстного меню блока if(mouse->Button!=RDS_MLEFTBUTTON) return RDS_BFR_SHOWMENU; // Координаты цента блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // Координаты центра круга-рукоятки hx=cx+x*mouse->Width/2; hy=cy-y*mouse->Height/2; // Проверка попадания курсора в круг if(abs(mouse->x-hx)<=hR && abs(mouse->y-hy)<=hR) { // Курсор попал в круг // Запоминаем координаты центр круга на момент // начала перетаскивания OldHandleX=hx; OldHandleY=hy; // Координаты курсора на начало перетаскивания OldMouseX=mouse->x; OldMouseY=mouse->y; // Взводим флаг захвата мыши *pFlags|=RDS_MOUSECAPTURE; } // Курсор не попал в рукоятку - захватывать мышь // и подготавливать перетаскивание не нужно return RDS_BFR_DONE; } //========================================= // Реакция на перемещение курсора мыши void TSimpleJoystick::MouseMove(RDS_PMOUSEDATA mouse, double *px,double *py) { int hx,hy,cx,cy; // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) { *px=*py=0.0; return; } // Новые координаты центра рукоятки hx=OldHandleX+(mouse->x-OldMouseX); hy=OldHandleY+(mouse->y-OldMouseY); // Координаты центра блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // По новым координатам центра рукоятки вычисляем соответствующие // им вещественные значения выходов, ограничивая их // диапазоном [-1...1] *px=2.0*(hx-cx)/mouse->Width; if(*px>1.0) *px=1.0; else if(*px<-1.0) *px=-1.0; *py=-2.0*(hy-cy)/mouse->Height; if(*py>1.0) *py=1.0; else if(*py<-1.0) *py=-1.0; } //========================================= // Функция модели блока extern "C" __declspec(dllexport) int RDSCALL SimpleJoystick(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define x (*((double *)(pStart+2*RDS_VSZ_S))) #define y (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) // Вспомогательная переменная - указатель на личную область, //приведенный к правильному типу TSimpleJoystick *data=(TSimpleJoystick*)(BlockData->BlockData); switch(CallMode) { // Инициализация case RDS_BFM_INIT: BlockData->BlockData=new TSimpleJoystick(); break; // Очистка case RDS_BFM_CLEANUP: delete data; break; // Проверка допустимости типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDD}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Нажатие кнопки мыши case RDS_BFM_MOUSEDOWN: return data->MouseDown((RDS_PMOUSEDATA)ExtParam,x,y, &(BlockData->Flags)); // Отпускание кнопки мыши case RDS_BFM_MOUSEUP: // Снятие захвата мыши RDS_SETFLAG(BlockData->Flags,RDS_MOUSECAPTURE,FALSE); break; // Перемещение курсора мыши case RDS_BFM_MOUSEMOVE: // Проверка: включен ли захват мыши if(BlockData->Flags & RDS_MOUSECAPTURE) // Включен { // Вызываем функцию реакции data->MouseMove((RDS_PMOUSEDATA)ExtParam,&x,&y); Ready=1; // Взводим сигнал готовности } break; // Рисование case RDS_BFM_DRAW: data->Draw((RDS_PDRAWDATA)ExtParam,x,y, BlockData->Flags & RDS_MOUSECAPTURE); break; } return RDS_BFR_DONE; // Отмена макроопределений #undef y #undef x #undef Ready #undef Start #undef pStart } //=========================================