GuiBitmapCtrl 을 드래그 가능하게 수정하는 소스코드다.
TGEA 1.7.1 기반.

1. guiBitmapCtrl.h
 - 아래코드 추가

protected:
..
..
.. 생략 ..
..
..
// The mouse down offset from the upper left of the control.
Point2I mOffset;
bool mDeleteOnMouseUp;
bool mDrag;

// Controls may want to react when they are dragged over, entered or exited.
GuiControl* mLastTarget;

// Convenience methods for sending events
void sendDragEvent(GuiControl* target, const char* event);
GuiControl* findDragTarget(Point2I mousePoint, const char* method);


public:
..
..
.. 생략 ..
..
..
void startDragging(Point2I offset = Point2I(0, 0));

virtual void onMouseDown(const GuiEvent& event);
virtual void onMouseDragged(const GuiEvent& event);
virtual void onMouseUp(const GuiEvent& event);


2. guiBitmapCtrl.cpp
 - 헤더파일 추가 후 아래와 같은 코드를 각 함수에 추가

#include "gui/core/guiCanvas.h"

GuiBitmapCtrl::GuiBitmapCtrl(void)
{
..
..
..
DeleteOnMouseUp = false;
mDrag = false;
}

void GuiBitmapCtrl::initPersistFields()
{
..
..
..
addField("deleteOnMouseUp", TypeBool, Offset(mDeleteOnMouseUp, GuiBitmapCtrl));
addField("drag", TypeBool, Offset(mDrag, GuiBitmapCtrl));
}

// 아래부분은 통째로 붙여넣는다
ConsoleMethod(GuiBitmapCtrl, startDragging, void, 2, 4, "startDragging(%offset)")
{
Point2I offset = Point2I(0, 0);
if (argc > 3)
{
offset.x = dAtoi(argv[2]);
offset.y = dAtoi(argv[3]);
}
object->startDragging(offset);
}

void GuiBitmapCtrl::startDragging(Point2I offset)
{
GuiCanvas* canvas = getRoot();
AssertFatal(canvas, "DragAndDropControl wasn't added to the gui before the drag started.");
if (canvas->getMouseLockedControl())
{
GuiEvent event;
canvas->getMouseLockedControl()->onMouseLeave(event);
canvas->mouseUnlock(canvas->getMouseLockedControl());
}
canvas->mouseLock(this);
canvas->setFirstResponder(this);
mOffset = offset;
mLastTarget=NULL;
}

void GuiBitmapCtrl::onMouseDown(const GuiEvent& event)
{
if ( !mDrag )
return;

startDragging(event.mousePoint - getPosition());
}

void GuiBitmapCtrl::onMouseDragged(const GuiEvent& event)
{
if ( !mDrag )
return;

setPosition(event.mousePoint - mOffset);

// Allow the control under the drag to react to a potential drop
GuiControl* enterTarget = findDragTarget(event.mousePoint, "onControlDragEnter");
if(mLastTarget != enterTarget)
{
sendDragEvent(mLastTarget, "onControlDragExit");
sendDragEvent(enterTarget, "onControlDragEnter");
mLastTarget = enterTarget;
}

GuiControl* dragTarget = findDragTarget(event.mousePoint, "onControlDragged");
sendDragEvent(dragTarget, "onControlDragged");

if ( isMethod("onMouseDragged") )
Con::executef( this, "onMouseDragged" );
}

void GuiBitmapCtrl::onMouseUp(const GuiEvent& event)
{
if ( !mDrag )
return;

mouseUnlock();

GuiControl* target = findDragTarget(event.mousePoint, "onControlDropped");
sendDragEvent(target, "onControlDropped");

if (mDeleteOnMouseUp)
deleteObject();
}

void GuiBitmapCtrl::sendDragEvent(GuiControl* target, const char* event)
{
if(!target || !target->isMethod(event) || !mDrag)
return;

char position[32];
Point2I dropPoint = getPosition() + (getExtent() / 2);
dSprintf(position, 32, "%d %d", dropPoint.x, dropPoint.y);
Con::executef(target, event, Con::getIntArg(at(0)->getId()), position);
}

GuiControl* GuiBitmapCtrl::findDragTarget(Point2I mousePoint, const char* method)
{
if ( !mDrag )
return false;

// If there are any children and we have a parent.
GuiControl* parent = getParent();
if (size() && parent)
{
mVisible = false;
GuiControl* dropControl = parent->findHitControl(mousePoint);
mVisible = true;
while( dropControl )
{      
if (dropControl->isMethod(method))
return dropControl;
else
dropControl = dropControl->getParent();
}
}
return NULL;
}


이제 엔진 소스를 다시 컴파일 후 스크립트에서 사용하면된다.

사용방법은

new GuiBitmapCtrl(TestImage)
{
         canSaveDynamicFields = "0";
         Enabled = "1";
         isContainer = "0";
         Profile = "GuiDefaultProfile";
         HorizSizing = "right";
         VertSizing = "bottom";
         position = "173 216";
         Extent = "19 19";
         MinExtent = "8 2";
         canSave = "1";
         Visible = "1";
         hovertime = "1000";
         bitmap = "./TestImage ";
         wrap = "0";
         drag = "1";
};

drag 필드는 엔진에서 디폴트 false 로 설정되어있으므로 드래그앤드롭을 적용하지 않아도 될경우에는 속성에 기술할 필요가 없다.

deleteOnMouseUp 필드도 사용할 수 있는데 "1" 로 설정할 경우 마우스 드래그 후 드랍할 때, 즉 onMouseUp 이벤트에서 해당 이미지 오브젝트를 삭제하는 필드이다. 나 같은 경우는 별 필요가 없다.

그 다음 이미지를 드래그 할 때 스크립트에서 실행되는 onMouseDragged 콜백함수를 등록해주어야 한다.
이런식으로..

function TestImage::onMouseDragged(%this)
{
   %pos = TestImage.getPosition();
   %posX = getWord(%pos,0);
   %posY = getWord(%pos,1);
   
   TestImage.setPosition(%posX, %posY);
   
   //
   // 이미지가 드래그 될 때 일어나는 기타 동작은 여기에서 구현.
   //
}



사실 위 코드는 GuiDragAndDropControl 의 일부를 뜯어와서 적용시킨 건데 드래그되는 컨트롤이 있으면 그걸 그대로 쓰면되지 왜 엔진을 고치느냐라고 물어볼수 도 있다. GuiDragAndDropControl은 GuiEditor 의 팔레트에서 사용하는데 cs 파일을 살펴본 결과 내가 원하는 방식대로 사용할 수 있는 구조가 아닌 것 같았다.

예제가 팔레트에서 사용한 것 밖에 없어서 정확하게 알아본 것은 아니지만
아무튼... 특이한 방법이었다 =_=.......
tools\guiEditor\gui\guiEditor.ed.cs 를 찾아보면 나와있다.

다행히 GuiDragAndDropControl 의 엔진 소스 자체가 잘 구현되어 있어서 한번에 가져와서 붙였고 제대로 동작하는 것 까지 확인했다.









2009/06/02 20:06 2009/06/02 20:06
Posted by ddiamo

트랙백 보낼 주소 : http://ddiamo.net/trackback/54

댓글을 달아주세요

[로그인][오픈아이디란?]

<< PREV : [1] : ... [53] : [54] : [55] : [56] : [57] : [58] : [59] : [60] : [61] : ... [74] : NEXT >>

카테고리

전체 (74)
일기 (37)
감상 (8)
수영 (9)
여행 (11)
IT (9)

달력

«   2010/09   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Total : 54337
Today : 121 Yesterday : 31