00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "pgwidgetdnd.h"
00030 #include "pgapplication.h"
00031 #include "pgdraw.h"
00032 #include "pgeventsupplier.h"
00033
00034 PG_WidgetDnD* PG_WidgetDnD::dnd_objectlist = NULL;
00035
00036 PG_WidgetDnD::PG_WidgetDnD(PG_Widget* parent, int dndID, const PG_Rect& r) :
00037 PG_Widget(parent, r, false),
00038 CanDrag(true),
00039 CanDrop(true),
00040 Draging(false),
00041 dragimage(NULL),
00042 dragimagecache(NULL) {
00043 SetID(dndID);
00044
00045
00046 dnd_next = dnd_objectlist;
00047 dnd_objectlist = this;
00048 }
00049
00050 PG_WidgetDnD::PG_WidgetDnD(PG_Widget* parent, int dndID, const PG_Rect& r, bool bCreateSurface) :
00051 PG_Widget(parent, r, bCreateSurface),
00052 CanDrag(true),
00053 CanDrop(true),
00054 Draging(false),
00055 dragimage(NULL),
00056 dragimagecache(NULL) {
00057 SetID(dndID);
00058
00059
00060 dnd_next = dnd_objectlist;
00061 dnd_objectlist = this;
00062 }
00063
00064 PG_WidgetDnD::~PG_WidgetDnD() {
00065 RemoveObjectDnD(this);
00066 }
00067
00069 bool PG_WidgetDnD::GetDrag() {
00070 return CanDrag;
00071 }
00072
00074 bool PG_WidgetDnD::GetDrop() {
00075 return CanDrop;
00076 }
00077
00079 void PG_WidgetDnD::RemoveObjectDnD(PG_WidgetDnD* obj) {
00080 PG_WidgetDnD* obj_before = NULL;
00081 PG_WidgetDnD* list = dnd_objectlist;
00082
00083
00084 while((list != NULL) && (list != obj)) {
00085 obj_before = list;
00086 list = list->dnd_next;
00087 }
00088
00089
00090 if(list == NULL)
00091 return;
00092
00093
00094
00095 if(obj_before == NULL)
00096 dnd_objectlist = this->dnd_next;
00097 else {
00098 obj_before->dnd_next = obj->dnd_next;
00099 }
00100 obj->dnd_next = NULL;
00101 }
00102
00104 PG_WidgetDnD* PG_WidgetDnD::FindDropTarget(PG_Point pt) {
00105 PG_WidgetDnD* list = dnd_objectlist;
00106
00107
00108 while(list != NULL) {
00109 if(list->IsInside(pt) && list->IsVisible()) {
00110 break;
00111 }
00112 list = list->dnd_next;
00113 }
00114
00115 if(list == NULL) {
00116 return NULL;
00117 }
00118
00119 if(!list->GetDrop()) {
00120 return NULL;
00121 }
00122
00123 if(list->AcceptDrop(this, GetID())) {
00124 return list;
00125 }
00126
00127 return NULL;
00128 }
00129
00131 bool PG_WidgetDnD::AcceptDrop(PG_WidgetDnD* source, int dndID) {
00132 return CanDrop;
00133 }
00134
00136 void PG_WidgetDnD::SetDrag(bool drag) {
00137 CanDrag = drag;
00138 }
00139
00141 void PG_WidgetDnD::SetDrop(bool drop) {
00142 CanDrop = drop;
00143 }
00144
00146 bool PG_WidgetDnD::eventDragStart() {
00147 return true;
00148 }
00149
00151 bool PG_WidgetDnD::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
00152 int x,y;
00153
00154 PG_Application::GetEventSupplier()->GetMouseState(x, y);
00155 CheckCursorPos(x, y);
00156
00157 if((button->button == 1) && CanDrag) {
00158 SetCapture();
00159
00160 dragPointOld.x = x;
00161 dragPointOld.y = y;
00162
00163 dragPointStart.x = x;
00164 dragPointStart.y = y;
00165
00166 Draging = true;
00167 eventDragStart();
00168 dragimage = eventQueryDragImage();
00169
00170 if(dragimage != NULL) {
00171 dragimagecache = PG_Draw::CreateRGBSurface(dragimage->w, dragimage->h);
00172 }
00173
00174 cacheDragArea(dragPointOld);
00175
00176 return true;
00177 }
00178
00179 return false;
00180 }
00181
00183 bool PG_WidgetDnD::eventMouseMotion(const SDL_MouseMotionEvent* motion) {
00184 PG_WidgetDnD* target = NULL;
00185 SDL_Surface* dropimage = NULL;
00186
00187 int x,y;
00188 PG_Point pt;
00189
00190 PG_Application::GetEventSupplier()->GetMouseState(x, y);
00191 CheckCursorPos(x, y);
00192 pt.x = x;
00193 pt.y = y;
00194
00195
00196 if(Draging) {
00197
00198 if(dragimage == NULL) {
00199 return true;
00200 }
00201
00202 target = FindDropTarget(pt);
00203
00204 if(target != NULL) {
00205 dropimage = target->eventQueryDropImage(dragimage);
00206
00207 if(dropimage != NULL) {
00208 dragimage = dropimage;
00209 }
00210 } else {
00211 dragimage = eventQueryDragImage();
00212 }
00213
00214 dragPointCurrent.x = x;
00215 dragPointCurrent.y = y;
00216
00217
00218 restoreDragArea(dragPointOld);
00219
00220
00221 cacheDragArea(dragPointCurrent);
00222
00223
00224 drawDragArea(dragPointCurrent, dragimage);
00225 updateDragArea(dragPointCurrent, dragimage);
00226
00227
00228 updateDragArea(dragPointOld, dragimagecache);
00229
00230
00231 dragPointOld.x = x;
00232 dragPointOld.y = y;
00233
00234 return true;
00235 }
00236
00237 return PG_Widget::eventMouseMotion(motion);
00238 }
00239
00241 bool PG_WidgetDnD::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
00242 PG_WidgetDnD* target = NULL;
00243 int x,y;
00244 PG_Point pt;
00245
00246 PG_Application::GetEventSupplier()->GetMouseState(x, y);
00247 CheckCursorPos(x, y);
00248
00249 pt.x = x;
00250 pt.y = y;
00251
00252 if((button->button == 1) && Draging) {
00253 target = FindDropTarget(pt);
00254
00255 if(dragimagecache != NULL) {
00256
00257
00258 restoreDragArea(dragPointOld);
00259
00260
00261
00262 drawDragArea(dragPointOld, dragimagecache);
00263 updateDragArea(dragPointOld, dragimagecache);
00264 }
00265
00266 if(target != NULL) {
00267 target->eventDragDrop(this, GetID());
00268 } else {
00269 slideDragImage(pt, dragPointStart, 20, dragimage);
00270 eventDragCancel();
00271 }
00272
00273 if(dragimagecache != NULL) {
00274
00275 PG_Application::UnloadSurface(dragimagecache);
00276
00277 dragimage = NULL;
00278 dragimagecache = NULL;
00279 }
00280
00281 ReleaseCapture();
00282 Draging = false;
00283
00284 return true;
00285 }
00286
00287 return false;
00288 }
00289
00291 bool PG_WidgetDnD::eventDragDrop(PG_WidgetDnD* source, int dndID) {
00292 return true;
00293 }
00294
00296 bool PG_WidgetDnD::eventDragCancel() {
00297 return true;
00298 }
00299
00301 SDL_Surface* PG_WidgetDnD::eventQueryDragImage() {
00302 return NULL;
00303 }
00304
00306 void PG_WidgetDnD::cacheDragArea(PG_Point p) {
00307 SDL_Rect srcrect;
00308 SDL_Rect dstrect;
00309
00310 if(!dragimagecache || !dragimage)
00311 return;
00312
00313 PG_Application::ScreenLocker locker(true);
00314
00315 srcrect.x = p.x;
00316 srcrect.y = p.y;
00317 srcrect.w = dragimagecache->w;
00318 srcrect.h = dragimagecache->h;
00319
00320 dstrect.x = 0;
00321 dstrect.y = 0;
00322 dstrect.w = dragimagecache->w;
00323 dstrect.h = dragimagecache->h;
00324
00325 PG_Draw::BlitSurface(PG_Application::GetScreen(), srcrect, dragimagecache, dstrect);
00326 }
00327
00329 void PG_WidgetDnD::restoreDragArea(PG_Point p) {
00330 SDL_Rect srcrect;
00331 SDL_Rect dstrect;
00332
00333 if((dragimagecache == NULL) || (dragimage == NULL))
00334 return;
00335
00336 PG_Application::ScreenLocker locker(true);
00337
00338 srcrect.x = 0;
00339 srcrect.y = 0;
00340 srcrect.w = dragimagecache->w;
00341 srcrect.h = dragimagecache->h;
00342
00343 dstrect.x = p.x;
00344 dstrect.y = p.y;
00345 dstrect.w = dragimagecache->w;
00346 dstrect.h = dragimagecache->h;
00347
00348 PG_Draw::BlitSurface(dragimagecache, srcrect, PG_Application::GetScreen(), dstrect);
00349 }
00351 void PG_WidgetDnD::CheckCursorPos(int& x, int& y) {
00352
00353 if(dragimage == NULL)
00354 return;
00355
00356 x -= dragimage->w / 2;
00357 y -= dragimage->h / 2;
00358
00359 if(x<0)
00360 x=0;
00361 if(y<0)
00362 y=0;
00363
00364 if(x + dragimage->w > PG_Application::GetScreen()->w)
00365 x = PG_Application::GetScreen()->w - dragimage->w;
00366
00367 if(y + dragimage->h > PG_Application::GetScreen()->h)
00368 y = PG_Application::GetScreen()->h - dragimage->h;
00369 }
00370
00372 SDL_Surface* PG_WidgetDnD::eventQueryDropImage(SDL_Surface* dragimage) {
00373 return NULL;
00374 }
00376 void PG_WidgetDnD::drawDragArea(PG_Point pt, SDL_Surface* image) {
00377 SDL_Rect srcrect;
00378 SDL_Rect dstrect;
00379
00380 srcrect.x = 0;
00381 srcrect.y = 0;
00382 srcrect.w = image->w;
00383 srcrect.h = image->h;
00384
00385 dstrect.x = pt.x;
00386 dstrect.y = pt.y;
00387 dstrect.w = image->w;
00388 dstrect.h = image->h;
00389
00390 PG_Application::ScreenLocker locker(true);
00391 PG_Draw::BlitSurface(image, srcrect, PG_Application::GetScreen(), dstrect);
00392
00393 }
00395 void PG_WidgetDnD::updateDragArea(PG_Point pt, SDL_Surface* image) {
00396 SDL_Rect dstrect;
00397
00398 dstrect.x = pt.x;
00399 dstrect.y = pt.y;
00400 dstrect.w = image->w;
00401 dstrect.h = image->h;
00402
00403 PG_Application::UpdateRects(PG_Application::GetScreen(), 1, &dstrect);
00404 }
00405
00407 void PG_WidgetDnD::slideDragImage(PG_Point start, PG_Point end, int steps, SDL_Surface* image) {
00408 double dx, dy;
00409 PG_Point current,old;
00410
00411 dx = end.x - start.x;
00412 dy = end.y - start.y;
00413
00414 dx /= steps;
00415 dy /= steps;
00416
00417 for(int i=0; i<steps; i++) {
00418 current.x = (int)((double)start.x + (double)i*dx);
00419 current.y = (int)((double)start.y + (double)i*dy);
00420
00421 if(i>0) {
00422 drawDragArea(old, dragimagecache);
00423 }
00424
00425 cacheDragArea(current);
00426 drawDragArea(current, dragimage);
00427 updateDragArea(current, dragimage);
00428
00429 if(i>0) {
00430 updateDragArea(old, dragimagecache);
00431 }
00432
00433 old = current;
00434
00435 SDL_Delay(10);
00436 }
00437
00438 drawDragArea(old, dragimagecache);
00439 updateDragArea(old, dragimagecache);
00440 }