1 /* Copyright (C) 1993 Nathan Sidwell */ 2 /* RCS $Id: PixmapList.c,v 4.9 1995/12/14 13:53:27 nathan Exp $ */ 3 /* Holds a list of pixmaps which can be selected or dragged like 4 * individual Icon widgets. 5 * I tried using a box widget with an insertPosition function 6 * but that didn't seem to work properly 7 * you can also attach a scroll bar to this widget 8 */ 9 /*{{{ includes*/ 10 #include "ansiknr.h" 11 #include <X11/X.h> 12 #include <X11/Xlib.h> 13 #include <X11/IntrinsicP.h> 14 #include <X11/StringDefs.h> 15 #include <X11/Xaw/SimpleP.h> 16 #include <X11/Xaw/Scrollbar.h> 17 #include <X11/Xmu/Drawing.h> 18 #include "PixmapList.h" 19 #include "Drag.h" 20 #include <math.h> 21 /*}}}*/ 22 /*{{{ structs*/ 23 /*{{{ typedef struct _PixmapListClass*/ 24 typedef struct _PixmapListClass 25 { 26 int ansi_compliance; /* not used */ 27 } PixmapListClassPart; 28 /*}}}*/ 29 /*{{{ typedef struct _PixmapListClassRec*/ 30 typedef struct _PixmapListClassRec 31 { 32 CoreClassPart core_class; 33 SimpleClassPart simple_class; 34 PixmapListClassPart pixmap_list_class; 35 } PixmapListClassRec; 36 /*}}}*/ 37 /*{{{ typedef _PixmapInfo*/ 38 typedef struct _PixmapInfo 39 { 40 Pixmap pixmap; /* the pixmap */ 41 int width; /* its width */ 42 int height; /* its height */ 43 Position x; /* its position */ 44 Position y; /* its position */ 45 } PixmapInfo; 46 /*}}}*/ 47 /*{{{ typedef struct _PixmapListPart*/ 48 typedef struct 49 { 50 /* resources */ 51 XtCallbackList callbacks; /* callbacks to notify */ 52 Dimension drag_sensitivity; /* sensitivity of drag callback */ 53 Dimension highlight_thickness; /* thickness of highlight bar */ 54 Pixel foreground; /* foreground pixel color */ 55 int flash_delay; /* time to flash */ 56 String drag_name; /* name of drag */ 57 Dimension distance; /* separation of pixmaps */ 58 XtOrientation orient; /* orientation */ 59 Dimension border_width; /* border width */ 60 Pixel border_color; /* border color */ 61 62 /* private state */ 63 PixmapInfo *pixmap_info; /* list of pixmaps */ 64 Cardinal num_pixmaps; /* their number */ 65 Cardinal limit; /* malloc limit of pi */ 66 GC gc; /* GC to draw foreground */ 67 GC border_gc; /* GC to draw border */ 68 Position drag_x; /* drag start x */ 69 Position drag_y; /* drag start y */ 70 int drag_set; /* drag selected */ 71 Boolean highlit; /* is it highlit? */ 72 int selected; /* selected pixmap */ 73 int was; /* selected pixmap */ 74 Position x; /* offset of start of list */ 75 Position y; /* offset of start of list */ 76 int width; /* pixmaps' widths or -1 for different */ 77 int height; /* pixmaps' heights or -1 for different */ 78 Dimension length; /* length of list */ 79 XtIntervalId timeout; /* timout id */ 80 Widget scroll; /* scrollbar widget */ 81 } PixmapListPart; 82 /*}}}*/ 83 /*{{{ typedef struct _PixmapListRec*/ 84 typedef struct _PixmapListRec 85 { 86 CorePart core; 87 SimplePart simple; 88 PixmapListPart pixmap_list; 89 } PixmapListRec; 90 /*}}}*/ 91 /*}}}*/ 92 /*{{{ resources*/ 93 static XtResource resources[] = 94 { 95 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 96 XtOffsetOf(PixmapListRec, pixmap_list.foreground), 97 XtRString, (XtPointer)XtDefaultForeground}, 98 {MredNhighlightThickness, XtCThickness, XtRDimension, sizeof(Dimension), 99 XtOffsetOf(PixmapListRec, pixmap_list.highlight_thickness), 100 XtRImmediate, (XtPointer)1}, 101 {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), 102 XtOffsetOf(PixmapListRec, pixmap_list.callbacks), 103 XtRCallback, (XtPointer)NULL}, 104 {MredNdistance, XtCThickness, XtRDimension, sizeof(Dimension), 105 XtOffsetOf(PixmapListRec, pixmap_list.distance), 106 XtRImmediate, (XtPointer)4}, 107 {MredNdragSensitivity, XtCThickness, XtRDimension, sizeof(Dimension), 108 XtOffsetOf(PixmapListRec, pixmap_list.drag_sensitivity), 109 XtRImmediate, (XtPointer)4}, 110 {MredNflashDelay, XtCInterval, XtRInt, sizeof(int), 111 XtOffsetOf(PixmapListRec, pixmap_list.flash_delay), 112 XtRImmediate, (XtPointer)100}, 113 {MredNdragName, XtCLabel, XtRString, sizeof(String), 114 XtOffsetOf(PixmapListRec, pixmap_list.drag_name), 115 XtRImmediate, (XtPointer)"drag"}, 116 {XtNinternalBorderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), 117 XtOffsetOf(PixmapListRec, pixmap_list.border_width), 118 XtRImmediate, (XtPointer)1}, 119 {XtNinternalBorderColor, XtCBorderColor, XtRPixel, sizeof(Pixel), 120 XtOffsetOf(PixmapListRec, pixmap_list.border_color), 121 XtRString, (XtPointer)XtDefaultForeground}, 122 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation), 123 XtOffsetOf(PixmapListRec, pixmap_list.orient), 124 XtRImmediate, (XtPointer)XtorientVertical}, 125 }; 126 /*}}}*/ 127 /*{{{ prototypes*/ 128 static VOIDFUNC Drag PROTOARG((Widget, XEvent *, String *, Cardinal *)); 129 static VOIDFUNC Highlight PROTOARG((Widget, XEvent *, String *, Cardinal *)); 130 static VOIDFUNC Notify PROTOARG((Widget, XEvent *, String *, Cardinal *)); 131 static VOIDFUNC Set PROTOARG((Widget, XEvent *, String *, Cardinal *)); 132 static VOIDFUNC Unhighlight PROTOARG((Widget, XEvent *, String *, Cardinal *)); 133 134 static VOIDFUNC ClassInitialize PROTOARG((VOIDARG)); 135 static VOIDFUNC Destroy PROTOARG((Widget)); 136 static VOIDFUNC Initialize PROTOARG((Widget, Widget, ArgList, Cardinal *)); 137 static XtGeometryResult QueryGeometry 138 PROTOARG((Widget, XtWidgetGeometry *, XtWidgetGeometry *)); 139 static VOIDFUNC Redisplay PROTOARG((Widget, XEvent *, Region)); 140 static VOIDFUNC Resize PROTOARG((Widget)); 141 static Boolean SetValues 142 PROTOARG((Widget, Widget, Widget, ArgList, Cardinal *)); 143 144 static VOIDFUNC PaintPixmap 145 PROTOARG((PixmapListWidget, PixmapInfo *, unsigned)); 146 static VOIDFUNC PaintRect PROTOARG((PixmapListWidget, Position, Position)); 147 static VOIDFUNC GetGC PROTOARG((PixmapListWidget)); 148 static VOIDFUNC GetPixmapSize PROTOARG((PixmapListWidget, PixmapInfo *)); 149 static int GetPointerPosition 150 PROTOARG((PixmapListWidget, XEvent *, Position *, Position *)); 151 static VOIDFUNC RemoveTimeOut PROTOARG((PixmapListWidget)); 152 static VOIDFUNC ScrollJump PROTOARG((Widget, XtPointer, XtPointer)); 153 static VOIDFUNC ScrollScroll PROTOARG((Widget, XtPointer, XtPointer)); 154 static VOIDFUNC SetScrollbar PROTOARG((PixmapListWidget)); 155 static VOIDFUNC TimeOut PROTOARG((XtPointer, XtIntervalId *)); 156 /*}}}*/ 157 /*{{{ translations*/ 158 static char translations[] = "\ 159 <BtnDown>:set()\n\ 160 <BtnUp>:notify()\n\ 161 <Motion>:highlight() drag()\n\ 162 <LeaveNotify>:unhighlight()\n\ 163 "; 164 /*}}}*/ 165 /*{{{ actions*/ 166 static XtActionsRec actions[] = 167 { 168 {"drag", Drag}, 169 {"highlight", Highlight}, 170 {"notify", Notify}, 171 {"set", Set}, 172 {"unhighlight", Unhighlight}, 173 }; 174 /*}}}*/ 175 #define SuperClass (WidgetClass)&simpleClassRec 176 /*{{{ PixmapListClassRec pixmapListClassRec =*/ 177 PixmapListClassRec pixmapListClassRec = 178 { 179 /*{{{ core class part*/ 180 { 181 SuperClass, /* superclass */ 182 "PixmapList", /* class_name */ 183 sizeof(PixmapListRec), /* size */ 184 ClassInitialize, /* class_initialize */ 185 NULL, /* class_part_initialize */ 186 False, /* class_inited */ 187 Initialize, /* initialize */ 188 NULL, /* initialize_hook */ 189 XtInheritRealize, /* realize */ 190 actions, /* actions */ 191 XtNumber(actions), /* num_actions */ 192 resources, /* resources */ 193 XtNumber(resources), /* num_resources */ 194 NULLQUARK, /* xrm_class */ 195 True, /* compress_motion */ 196 XtExposeCompressMultiple, /* compress_exposure */ 197 True, /* compress_enterleave */ 198 False, /* visible_interest */ 199 Destroy, /* destroy */ 200 Resize, /* resize */ 201 Redisplay, /* expose */ 202 SetValues, /* set_values */ 203 NULL, /* set_values_hook */ 204 XtInheritSetValuesAlmost, /* set_values_almost */ 205 NULL, /* get_values_hook */ 206 NULL, /* accept_focus */ 207 XtVersion, /* version */ 208 NULL, /* callback_private */ 209 translations, /* default_translations */ 210 QueryGeometry, /* query_geometry */ 211 XtInheritDisplayAccelerator, /* display_accelerator */ 212 NULL, /* extension */ 213 }, 214 /*}}}*/ 215 /*{{{ simple class part*/ 216 { 217 XtInheritChangeSensitive /* change_sensitive */ 218 }, 219 /*}}}*/ 220 /*{{{ pixmap list class part*/ 221 { 222 0, /* dummy */ 223 }, 224 /*}}}*/ 225 }; 226 /*}}}*/ 227 WidgetClass pixmapListWidgetClass = (WidgetClass)&pixmapListClassRec; 228 /* actions */ 229 /*{{{ void Drag(widget, event, params, num_params)*/ 230 static VOIDFUNC Drag 231 FUNCARG((widget, event, params, num_params), 232 Widget widget 233 ARGSEP XEvent *event 234 ARGSEP String *params 235 ARGSEP Cardinal *num_params 236 ) 237 /* determines if a drag sould start on the currently selected pixmap 238 * the drag widget is invoked the same as Icon does. 239 */ 240 { 241 PixmapListWidget plw; 242 243 plw = (PixmapListWidget)widget; 244 if(event->type != MotionNotify && event->type != ButtonPress) 245 /* EMPTY */; 246 else if(event->type == MotionNotify && !(event->xmotion.state & 247 (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask))) 248 /* EMPTY */; 249 else 250 { 251 Position x, y; 252 int selected; 253 254 selected = GetPointerPosition(plw, event, &x, &y); 255 if(selected != plw->pixmap_list.drag_set) 256 { 257 plw->pixmap_list.drag_set = selected; 258 plw->pixmap_list.drag_x = x; 259 plw->pixmap_list.drag_y = y; 260 } 261 else if(selected < 0) 262 /* EMPTY */; 263 else if(!plw->pixmap_list.drag_sensitivity) 264 /* EMPTY */; 265 else if(!plw->pixmap_list.drag_name) 266 /* EMPTY */; 267 else if(plw->pixmap_list.drag_sensitivity * 268 plw->pixmap_list.drag_sensitivity <= 269 (x - plw->pixmap_list.drag_x) * (x - plw->pixmap_list.drag_x) + 270 (y - plw->pixmap_list.drag_y) * (y - plw->pixmap_list.drag_y)) 271 /*{{{ pop up drag*/ 272 { 273 Widget drag; 274 Widget parent; 275 276 drag = NULL; 277 for(parent = (Widget)plw; parent; 278 parent = XtParent(parent)) 279 { 280 drag = XtNameToWidget(parent, plw->pixmap_list.drag_name); 281 if(drag) 282 break; 283 } 284 if(drag) 285 { 286 Position rx, ry; 287 288 plw->pixmap_list.highlit = False; 289 PaintPixmap(plw, NULL, selected); 290 XtTranslateCoords((Widget)plw, 291 plw->pixmap_list.pixmap_info[selected].x + 292 plw->pixmap_list.x, 293 plw->pixmap_list.pixmap_info[selected].y + 294 plw->pixmap_list.y, &rx, &ry); 295 DragPopup((Widget)plw, (Widget)drag, 296 plw->pixmap_list.pixmap_info[selected].pixmap, 297 plw->pixmap_list.drag_x, plw->pixmap_list.drag_y, 298 rx + x, ry + y, event->xmotion.time); 299 } 300 } 301 /*}}}*/ 302 } 303 return; 304 } 305 /*}}}*/ 306 /*{{{ void Highlight(widget, event, params, num_params)*/ 307 static VOIDFUNC Highlight 308 FUNCARG((widget, event, params, num_params), 309 Widget widget 310 ARGSEP XEvent *event 311 ARGSEP String *params 312 ARGSEP Cardinal *num_params 313 ) 314 /* highlight the pixmap we're on 315 */ 316 { 317 PixmapListWidget plw; 318 Position x, y; 319 int selected; 320 321 plw = (PixmapListWidget)widget; 322 selected = plw->pixmap_list.highlight_thickness ? 323 GetPointerPosition(plw, event, &x, &y) : -1; 324 if(selected != plw->pixmap_list.selected || 325 (plw->pixmap_list.highlit == False && selected >= 0)) 326 { 327 int old; 328 329 plw->pixmap_list.drag_x = x; 330 plw->pixmap_list.drag_y = y; 331 plw->pixmap_list.drag_set = selected + 1; 332 old = plw->pixmap_list.selected; 333 plw->pixmap_list.selected = selected; 334 plw->pixmap_list.highlit = selected < 0 ? False : True; 335 if(selected >= 0) 336 { 337 int was; 338 339 RemoveTimeOut(plw); 340 was = plw->pixmap_list.was; 341 plw->pixmap_list.was = -1; 342 if(was >= 0 && was != old && was != selected) 343 PaintPixmap(plw, NULL, was); 344 PaintPixmap(plw, NULL, selected); 345 } 346 if(old >= 0) 347 PaintPixmap(plw, NULL, old); 348 } 349 return; 350 } 351 /*}}}*/ 352 /*{{{ void Notify(widget, event, params, num_params)*/ 353 static VOIDFUNC Notify 354 FUNCARG((widget, event, params, num_params), 355 Widget widget 356 ARGSEP XEvent *event 357 ARGSEP String *params 358 ARGSEP Cardinal *num_params 359 ) 360 /* notify the callback of the currently selected pixmap 361 * flashes the pixmap too 362 * normally invoked on button release. 363 */ 364 { 365 PixmapListWidget plw; 366 367 plw = (PixmapListWidget)widget; 368 plw->pixmap_list.drag_set = -1; 369 if(plw->pixmap_list.selected >= 0) 370 { 371 PixmapListCallback data; 372 373 if(plw->pixmap_list.flash_delay) 374 { 375 plw->pixmap_list.was = plw->pixmap_list.selected; 376 PaintPixmap(plw, NULL, plw->pixmap_list.was); 377 plw->pixmap_list.timeout = XtAppAddTimeOut( 378 XtWidgetToApplicationContext((Widget)plw), 379 (unsigned long)plw->pixmap_list.flash_delay, 380 TimeOut, (XtPointer)plw); 381 } 382 data.selection = plw->pixmap_list.selected; 383 if(event->type == ButtonPress || event->type == ButtonRelease) 384 data.button = event->xbutton.button; 385 else 386 data.button = -1; 387 XtCallCallbackList((Widget)plw, plw->pixmap_list.callbacks, 388 (XtPointer)&data); 389 } 390 return; 391 } 392 /*}}}*/ 393 /*{{{ void Set(widget, event, params, num_params)*/ 394 static VOIDFUNC Set 395 FUNCARG((widget, event, params, num_params), 396 Widget widget 397 ARGSEP XEvent *event 398 ARGSEP String *params 399 ARGSEP Cardinal *num_params 400 ) 401 /* initialize the drag start point 402 */ 403 { 404 PixmapListWidget plw; 405 406 plw = (PixmapListWidget)widget; 407 plw->pixmap_list.drag_set = GetPointerPosition(plw, event, 408 &plw->pixmap_list.drag_x, &plw->pixmap_list.drag_y) + 1; 409 return; 410 } 411 /*}}}*/ 412 /*{{{ void Unhighlight(widget, event, params, num_params)*/ 413 static VOIDFUNC Unhighlight 414 FUNCARG((widget, event, params, num_params), 415 Widget widget 416 ARGSEP XEvent *event 417 ARGSEP String *params 418 ARGSEP Cardinal *num_params 419 ) 420 /* deselect any selected widget 421 */ 422 { 423 PixmapListWidget plw; 424 425 plw = (PixmapListWidget)widget; 426 if(plw->pixmap_list.highlit != False) 427 { 428 plw->pixmap_list.highlit = False; 429 PaintPixmap(plw, NULL, plw->pixmap_list.selected); 430 } 431 return; 432 } 433 /*}}}*/ 434 /* methods */ 435 /*{{{ void ClassInitialize()*/ 436 static VOIDFUNC ClassInitialize FUNCARGVOID 437 /* add the orientation type converter 438 */ 439 { 440 XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation, 441 NULL, 0); 442 return; 443 } 444 /*}}}*/ 445 /*{{{ void Destroy(widget)*/ 446 static VOIDFUNC Destroy 447 FUNCARG((widget), 448 Widget widget 449 ) 450 /* release our GCs and remove the flash timeout */ 451 { 452 PixmapListWidget plw; 453 454 plw = (PixmapListWidget)widget; 455 XtReleaseGC((Widget)plw, plw->pixmap_list.gc); 456 XtReleaseGC((Widget)plw, plw->pixmap_list.border_gc); 457 RemoveTimeOut(plw); 458 return; 459 } 460 /*}}}*/ 461 /*{{{ void Initialize(treq, tnew, args, num_args)*/ 462 static VOIDFUNC Initialize 463 FUNCARG((treq, tnew, args, num_args), 464 Widget treq 465 ARGSEP Widget tnew 466 ARGSEP ArgList args 467 ARGSEP Cardinal *num_args 468 ) 469 /* initialize ourselves 470 */ 471 { 472 PixmapListWidget nplw; 473 474 nplw = (PixmapListWidget)tnew; 475 nplw->pixmap_list.selected = -1; 476 nplw->pixmap_list.was = -1; 477 nplw->pixmap_list.highlit = False; 478 nplw->pixmap_list.drag_set = -1; 479 nplw->pixmap_list.timeout = (XtIntervalId)0; 480 nplw->pixmap_list.pixmap_info = NULL; 481 nplw->pixmap_list.scroll = NULL; 482 nplw->pixmap_list.limit = 0; 483 nplw->pixmap_list.length = nplw->pixmap_list.distance; 484 nplw->pixmap_list.width = nplw->pixmap_list.height = 0; 485 nplw->pixmap_list.x = nplw->pixmap_list.y = 0; 486 nplw->pixmap_list.num_pixmaps = 0; 487 if(!nplw->core.width) 488 nplw->core.width = 16; 489 if(!nplw->core.height) 490 nplw->core.height = 16; 491 GetGC(nplw); 492 return; 493 } 494 /*}}}*/ 495 /*{{{ XtGeometryResult QueryGeometry(widget, proposed, answer)*/ 496 static XtGeometryResult QueryGeometry 497 FUNCARG((widget, proposed, answer), 498 Widget widget 499 ARGSEP XtWidgetGeometry *proposed 500 ARGSEP XtWidgetGeometry *answer 501 ) 502 /* tell our parent how big we'd like to be. 503 * This is big enough to hold all the pixmaps, 504 * but we don't mind being bigger or smaller 505 */ 506 { 507 PixmapListWidget plw; 508 unsigned ix; 509 PixmapInfo *pi; 510 unsigned max_width; 511 unsigned max_height; 512 513 plw = (PixmapListWidget)widget; 514 answer->request_mode = CWWidth | CWHeight; 515 max_width = max_height = 0; 516 for(ix = plw->pixmap_list.num_pixmaps, 517 pi = plw->pixmap_list.pixmap_info; ix--; pi++) 518 { 519 if(max_width < pi->width) 520 max_width = pi->width; 521 if(max_height < pi->height) 522 max_height = pi->height; 523 } 524 pi--; 525 if(plw->pixmap_list.orient == XtorientVertical) 526 { 527 answer->width = max_width + plw->pixmap_list.distance * 2 + 528 plw->pixmap_list.border_width * 2; 529 answer->height = plw->pixmap_list.length; 530 } 531 else 532 { 533 answer->width = plw->pixmap_list.length; 534 answer->height = max_height + plw->pixmap_list.distance * 2 + 535 plw->pixmap_list.border_width * 2; 536 } 537 if(!answer->width) 538 answer->width = 16; 539 if(!answer->height) 540 answer->height = 16; 541 if((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight) && 542 proposed->width == answer->width && proposed->height == answer->height) 543 return XtGeometryYes; 544 else if(answer->width == plw->core.width && 545 answer->height == plw->core.height) 546 return XtGeometryNo; 547 else 548 return XtGeometryAlmost; 549 } 550 /*}}}*/ 551 /*{{{ void Redisplay(widget, event, region)*/ 552 static VOIDFUNC Redisplay 553 FUNCARG((widget, event, region), 554 Widget widget 555 ARGSEP XEvent *event 556 ARGSEP Region region 557 ) 558 /* repaint all the pixmaps. 559 * We use the expose region to only repaint those 560 * pixmaps falling partially or whole within it 561 */ 562 { 563 PixmapListWidget plw; 564 unsigned ix; 565 PixmapInfo *pi; 566 567 if(!XtIsRealized(widget)) 568 return; 569 plw = (PixmapListWidget)widget; 570 for(ix = 0, pi = plw->pixmap_list.pixmap_info; 571 ix != plw->pixmap_list.num_pixmaps; ix++, pi++) 572 if(XRectInRegion(region, pi->x + plw->pixmap_list.x - 573 (plw->pixmap_list.border_width + 1) / 2, 574 pi->y + plw->pixmap_list.y - 575 (plw->pixmap_list.border_width + 1) / 2, 576 pi->width + 2 * plw->pixmap_list.border_width, 577 pi->height + 2 * plw->pixmap_list.border_width) != RectangleOut) 578 PaintPixmap(plw, pi, ix); 579 return; 580 } 581 /*}}}*/ 582 /*{{{ void Resize(widget)*/ 583 static VOIDFUNC Resize 584 FUNCARG((widget), 585 Widget widget 586 ) 587 /* reset the starting point and reset the scrollbar scale */ 588 { 589 PixmapListWidget plw; 590 591 plw = (PixmapListWidget)widget; 592 if(plw->pixmap_list.orient == XtorientVertical) 593 plw->pixmap_list.x = 0; 594 else 595 plw->pixmap_list.y = 0; 596 SetScrollbar(plw); 597 return; 598 } 599 /*}}}*/ 600 /*{{{ Boolean SetValues(cw, rw, nw, args, num_args)*/ 601 static Boolean SetValues 602 FUNCARG((cw, rw, nw, args, num_args), 603 Widget cw 604 ARGSEP Widget rw 605 ARGSEP Widget nw 606 ARGSEP ArgList args 607 ARGSEP Cardinal *num_args 608 ) 609 /* realloc the GCs if things change 610 * This generally involes a complete repaint 611 */ 612 { 613 Boolean redraw; 614 PixmapListWidget cplw; 615 PixmapListWidget nplw; 616 617 redraw = False; 618 cplw = (PixmapListWidget)cw; 619 nplw = (PixmapListWidget)nw; 620 if(cplw->pixmap_list.foreground != nplw->pixmap_list.foreground || 621 cplw->pixmap_list.highlight_thickness != 622 nplw->pixmap_list.highlight_thickness || 623 cplw->pixmap_list.border_color != nplw->pixmap_list.border_color || 624 cplw->pixmap_list.border_width != nplw->pixmap_list.border_width) 625 { 626 redraw = True; 627 XtReleaseGC((Widget)cplw, cplw->pixmap_list.gc); 628 XtReleaseGC((Widget)cplw, cplw->pixmap_list.border_gc); 629 GetGC(nplw); 630 } 631 if(nplw->pixmap_list.border_width != 632 cplw->pixmap_list.border_width || 633 nplw->pixmap_list.distance != cplw->pixmap_list.distance || 634 nplw->pixmap_list.orient != cplw->pixmap_list.orient) 635 { 636 PixmapInfo *pi; 637 unsigned count; 638 unsigned spot; 639 640 spot = nplw->pixmap_list.distance; 641 for(count = nplw->pixmap_list.num_pixmaps, 642 pi = nplw->pixmap_list.pixmap_info; count--; pi++) 643 { 644 spot += nplw->pixmap_list.border_width; 645 if(nplw->pixmap_list.orient == XtorientVertical) 646 pi->x = spot; 647 else 648 pi->y = spot; 649 spot += nplw->pixmap_list.border_width + 650 nplw->pixmap_list.distance; 651 } 652 nplw->pixmap_list.length = spot; 653 redraw = True; 654 SetScrollbar(nplw); 655 } 656 if(cplw->core.width != nplw->core.width || 657 cplw->core.height != nplw->core.height) 658 redraw = False; 659 return redraw; 660 } 661 /*}}}*/ 662 /* public routines */ 663 /*{{{ void PixmapListRepaint(widget)*/ 664 extern VOIDFUNC PixmapListRepaint 665 FUNCARG((widget, ix), 666 Widget widget 667 ARGSEP Cardinal ix /* pixmap to repaint */ 668 ) 669 /* repaint a single pixmap, avoiding the annoying expose event flicker 670 */ 671 { 672 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 673 /* EMPTY */; 674 else if(!XtIsRealized(widget)) 675 /* EMPTY */; 676 else if(ix >= ((PixmapListWidget)widget)->pixmap_list.num_pixmaps) 677 /* EMPTY */; 678 else 679 PaintPixmap((PixmapListWidget)widget, NULL, ix); 680 return; 681 } 682 /*}}}*/ 683 /*{{{ void PixmapListInsert(widget, ix, pixmap)*/ 684 extern VOIDFUNC PixmapListInsert 685 FUNCARG((widget, ix, pixmap), 686 Widget widget 687 ARGSEP Cardinal ix /* insert at this position */ 688 ARGSEP Pixmap pixmap /* pixmap to insert */ 689 ) 690 /* insert a pixmap at a given position in the list 691 */ 692 { 693 PixmapListWidget plw; 694 PixmapInfo *pi; 695 Position start; 696 697 plw = (PixmapListWidget)widget; 698 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 699 return; 700 if(ix > plw->pixmap_list.num_pixmaps) 701 ix = plw->pixmap_list.num_pixmaps; 702 if(plw->pixmap_list.drag_set >= (int)ix) 703 plw->pixmap_list.drag_set++; 704 if(plw->pixmap_list.selected >= (int)ix) 705 plw->pixmap_list.selected++; 706 if(plw->pixmap_list.was >= (int)ix) 707 plw->pixmap_list.was++; 708 /*{{{ insert it*/ 709 { 710 unsigned count; 711 unsigned width, height; 712 713 plw->pixmap_list.num_pixmaps++; 714 if(plw->pixmap_list.num_pixmaps > plw->pixmap_list.limit) 715 { 716 plw->pixmap_list.limit += 128; 717 plw->pixmap_list.pixmap_info = 718 (PixmapInfo *)XtRealloc((VOID *)plw-> pixmap_list.pixmap_info, 719 plw->pixmap_list.limit * sizeof(PixmapInfo)); 720 } 721 for(pi = &plw->pixmap_list.pixmap_info[plw->pixmap_list.num_pixmaps - 1], 722 count = plw->pixmap_list.num_pixmaps - ix - 1; count--; pi--) 723 memcpy(&pi[0], &pi[-1], sizeof(PixmapInfo)); 724 pi->pixmap = pixmap; 725 GetPixmapSize(plw, pi); 726 if(!plw->pixmap_list.width) 727 plw->pixmap_list.width = pi->width; 728 else if(plw->pixmap_list.width != pi->width) 729 plw->pixmap_list.width = -1; 730 if(!plw->pixmap_list.height) 731 plw->pixmap_list.height = pi->height; 732 else if(plw->pixmap_list.height != pi->height) 733 plw->pixmap_list.height = -1; 734 if(ix == plw->pixmap_list.num_pixmaps - 1) 735 pi->x = pi->y = plw->pixmap_list.length + 736 plw->pixmap_list.border_width; 737 if(plw->pixmap_list.orient == XtorientVertical) 738 { 739 pi->x = plw->pixmap_list.distance + plw->pixmap_list.border_width; 740 width = 0; 741 height = pi->height + plw->pixmap_list.distance + 742 plw->pixmap_list.border_width * 2; 743 } 744 else 745 { 746 pi->y = plw->pixmap_list.distance + plw->pixmap_list.border_width; 747 height = 0; 748 width = pi->width + plw->pixmap_list.distance + 749 plw->pixmap_list.border_width * 2; 750 } 751 for(count = plw->pixmap_list.num_pixmaps - ix - 1; pi++, count--;) 752 { 753 pi->x += width; 754 pi->y += height; 755 } 756 plw->pixmap_list.length += width + height; 757 } 758 /*}}}*/ 759 pi = &plw->pixmap_list.pixmap_info[ix]; 760 start = plw->pixmap_list.orient == XtorientVertical ? pi->y : pi->x; 761 start -= plw->pixmap_list.border_width; 762 if(plw->pixmap_list.orient == XtorientVertical) 763 { 764 if(plw->core.height <= plw->pixmap_list.length) 765 { 766 plw->pixmap_list.y -= plw->pixmap_list.border_width + 767 ((pi->height + plw->pixmap_list.distance + 1) >> 1); 768 start = -plw->pixmap_list.y; 769 } 770 } 771 else 772 { 773 if(plw->core.width <= plw->pixmap_list.length) 774 { 775 plw->pixmap_list.x -= plw->pixmap_list.border_width + 776 ((pi->width + plw->pixmap_list.distance + 1) >> 1); 777 start = -plw->pixmap_list.x; 778 } 779 } 780 PaintRect(plw, start, plw->pixmap_list.length - start); 781 SetScrollbar(plw); 782 return; 783 } 784 /*}}}*/ 785 /*{{{ void PixmapListRemove(widget, ix)*/ 786 extern VOIDFUNC PixmapListRemove 787 FUNCARG((widget, ix), 788 Widget widget 789 ARGSEP Cardinal ix /* pixmap to remove */ 790 ) 791 /* remove a pixmap from the list 792 * note that we don't free the pixmap, they belong to the widget operator 793 */ 794 { 795 PixmapListWidget plw; 796 PixmapInfo *pi; 797 Position start; 798 unsigned count; 799 unsigned delta; 800 801 plw = (PixmapListWidget)widget; 802 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 803 return; 804 if(!plw->pixmap_list.num_pixmaps) 805 return; 806 if(ix >= plw->pixmap_list.num_pixmaps) 807 ix = plw->pixmap_list.num_pixmaps - 1; 808 if(plw->pixmap_list.drag_set == ix) 809 plw->pixmap_list.drag_set = -1; 810 if(plw->pixmap_list.selected == ix) 811 plw->pixmap_list.selected = -1; 812 if(plw->pixmap_list.selected == ix) 813 RemoveTimeOut(plw); 814 pi = &plw->pixmap_list.pixmap_info[ix]; 815 plw->pixmap_list.num_pixmaps--; 816 if(plw->pixmap_list.orient == XtorientVertical) 817 { 818 delta = pi->height; 819 start = pi->y; 820 } 821 else 822 { 823 delta = pi->width; 824 start = pi->x; 825 } 826 delta += plw->pixmap_list.distance + plw->pixmap_list.border_width * 2; 827 plw->pixmap_list.length -= delta; 828 for(count = plw->pixmap_list.num_pixmaps - ix; count--; pi++) 829 { 830 memcpy(pi, pi + 1, sizeof(PixmapInfo)); 831 if(plw->pixmap_list.orient == XtorientVertical) 832 pi->y -= delta; 833 else 834 pi->x -= delta; 835 } 836 /*{{{ set scroll point*/ 837 if(plw->pixmap_list.orient == XtorientVertical) 838 { 839 if(plw->pixmap_list.length < plw->core.height) 840 { 841 if(plw->pixmap_list.y) 842 { 843 plw->pixmap_list.y = 0; 844 start = 0; 845 } 846 } 847 else 848 { 849 plw->pixmap_list.y += delta / 2; 850 if(plw->pixmap_list.y > 0) 851 plw->pixmap_list.y = 0; 852 start = -plw->pixmap_list.y; 853 } 854 } 855 else 856 { 857 if(plw->pixmap_list.length < plw->core.width) 858 { 859 if(plw->pixmap_list.x) 860 { 861 plw->pixmap_list.x = 0; 862 start = 0; 863 } 864 } 865 else 866 { 867 plw->pixmap_list.x += delta / 2; 868 if(plw->pixmap_list.x > 0) 869 plw->pixmap_list.x = 0; 870 start = -plw->pixmap_list.x; 871 } 872 } 873 /*}}}*/ 874 PaintRect(plw, start - plw->pixmap_list.border_width, 875 plw->pixmap_list.length + delta - start); 876 SetScrollbar(plw); 877 /*{{{ check if width & height can be rechecked*/ 878 if(!plw->pixmap_list.num_pixmaps) 879 plw->pixmap_list.width = plw->pixmap_list.height = 0; 880 else if(plw->pixmap_list.width < 0 || plw->pixmap_list.height < 0) 881 { 882 pi = plw->pixmap_list.pixmap_info; 883 plw->pixmap_list.width = pi->width; 884 plw->pixmap_list.height = pi->height; 885 for(count = plw->pixmap_list.num_pixmaps; count--; pi++) 886 { 887 if(pi->width != plw->pixmap_list.width) 888 plw->pixmap_list.width = -1; 889 if(pi->height != plw->pixmap_list.height) 890 plw->pixmap_list.height = -1; 891 } 892 } 893 /*}}}*/ 894 return; 895 } 896 /*}}}*/ 897 /*{{{ void PixmapListSetScroll(widget, scroll)*/ 898 extern VOIDFUNC PixmapListSetScroll 899 FUNCARG((widget, scroll), 900 Widget widget /* this widget */ 901 ARGSEP Widget scroll /* scrollbar widget */ 902 ) 903 /* inform of the scroll bar widget 904 * add callbacks to the scrollbar, so we can do the 905 * right thing 906 */ 907 { 908 PixmapListWidget plw; 909 910 plw = (PixmapListWidget)widget; 911 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 912 return; 913 if(plw->pixmap_list.scroll) 914 return; 915 plw->pixmap_list.scroll = scroll; 916 SetScrollbar(plw); 917 XtAddCallback(scroll, XtNjumpProc, ScrollJump, (XtPointer)plw); 918 XtAddCallback(scroll, XtNscrollProc, ScrollScroll, (XtPointer)plw); 919 return; 920 } 921 /*}}}*/ 922 /*{{{ int PixmapListQueryOffset(widget, x, y, flag)*/ 923 extern int PixmapListQueryOffset 924 FUNCARG((widget, x, y, flag), 925 Widget widget 926 ARGSEP Position x /* x position */ 927 ARGSEP Position y /* y position */ 928 ARGSEP Boolean flag /* center mode False:on pixmaps, True:on gaps */ 929 ) 930 /* find out which pixmap is at this position 931 * The pixmaps can either be selected by centering on 932 * the pixmaps, or on the gaps. 933 * For selecting an insert position you probably want to center 934 * on the gaps. For selecting a delete position, you 935 * probably want to center on the pixmaps. 936 */ 937 { 938 PixmapListWidget plw; 939 PixmapInfo *pi; 940 int ix; 941 int point; 942 int count; 943 int gap; 944 945 plw = (PixmapListWidget)widget; 946 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 947 return -1; 948 if(plw->pixmap_list.orient == XtorientVertical) 949 point = y - plw->pixmap_list.y; 950 else 951 point = x - plw->pixmap_list.x; 952 gap = plw->pixmap_list.border_width + ((plw->pixmap_list.distance + 1) >> 1); 953 for(ix = 0, pi = plw->pixmap_list.pixmap_info, 954 count = plw->pixmap_list.num_pixmaps; count; count--, ix++, pi++) 955 if(point < (flag != False ? (plw->pixmap_list.orient == XtorientVertical ? 956 pi->y + (pi->height >> 1) : pi->x + (pi->width >> 1)) : 957 (plw->pixmap_list.orient == XtorientVertical ? 958 pi->y + pi->height : pi->x + pi->width) + gap)) 959 break; 960 return ix; 961 } 962 /*}}}*/ 963 /*{{{ int PixmapListQueryDrag(widget)*/ 964 extern int PixmapListQueryDrag 965 FUNCARG((widget), 966 Widget widget 967 ) 968 /* used to find out which pixmap was selected to initiate 969 * a drag 970 */ 971 { 972 if(!XtIsSubclass(widget, (WidgetClass)&pixmapListClassRec)) 973 return -1; 974 return ((PixmapListWidget)widget)->pixmap_list.drag_set; 975 } 976 /*}}}*/ 977 /* private routines */ 978 /*{{{ void PaintPixmap(plw, pi, ix)*/ 979 static VOIDFUNC PaintPixmap 980 FUNCARG((plw, pi, ix), 981 PixmapListWidget plw 982 ARGSEP PixmapInfo *pi /* pixmap info pointer */ 983 ARGSEP unsigned ix /* pixmap number */ 984 ) 985 /* repaint a specific pixmap 986 * We have to repaint the border too. 987 */ 988 { 989 Position x, y; 990 991 if(!pi) 992 pi = &plw->pixmap_list.pixmap_info[ix]; 993 x = pi->x + plw->pixmap_list.x; 994 y = pi->y + plw->pixmap_list.y; 995 if(x >= (int)plw->core.width || x + (int)pi->width <= 0 || 996 y >= (int)plw->core.height || y + (int)pi->height <= 0) 997 return; 998 if(pi->pixmap != None) 999 XCopyArea(XtDisplay(plw), pi->pixmap, XtWindow(plw), 1000 plw->pixmap_list.gc, 0, 0, pi->width, pi->height, 1001 x, y); 1002 if(plw->pixmap_list.border_width) 1003 XDrawRectangle(XtDisplay(plw), XtWindow(plw), plw->pixmap_list.border_gc, 1004 x - (plw->pixmap_list.border_width + 1) / 2, 1005 y - (plw->pixmap_list.border_width + 1) / 2, 1006 pi->width + plw->pixmap_list.border_width, 1007 pi->height + plw->pixmap_list.border_width); 1008 if(ix == plw->pixmap_list.was) 1009 { 1010 XFillRectangle(XtDisplay(plw), XtWindow(plw), plw->pixmap_list.gc, 1011 x, y, pi->width, pi->height); 1012 return; 1013 } 1014 if(ix == plw->pixmap_list.selected && 1015 plw->pixmap_list.highlit != False) 1016 XDrawRectangle(XtDisplay(plw), XtWindow(plw), plw->pixmap_list.gc, 1017 x + (plw->pixmap_list.highlight_thickness >> 1), 1018 y + (plw->pixmap_list.highlight_thickness >> 1), 1019 pi->width - plw->pixmap_list.highlight_thickness, 1020 pi->height - plw->pixmap_list.highlight_thickness); 1021 return; 1022 } 1023 /*}}}*/ 1024 /*{{{ void PaintRect(plw, start, length)*/ 1025 static VOIDFUNC PaintRect 1026 FUNCARG((plw, start, length), 1027 PixmapListWidget plw 1028 ARGSEP Position start /* starting offset */ 1029 ARGSEP Position length /* length of rectangle */ 1030 ) 1031 /* paint all the pixmaps which fall within the specified 1032 * distance allong the widget 1033 * clears to the background too. 1034 */ 1035 { 1036 PixmapInfo *pi; 1037 unsigned ix; 1038 Position offset; 1039 Position size; 1040 unsigned count; 1041 1042 /*{{{ set offset and size*/ 1043 if(plw->pixmap_list.orient == XtorientVertical) 1044 { 1045 offset = plw->pixmap_list.y; 1046 size = plw->core.height; 1047 } 1048 else 1049 { 1050 offset = plw->pixmap_list.x; 1051 size = plw->core.width; 1052 } 1053 /*}}}*/ 1054 /*{{{ clip start*/ 1055 if(start + offset < 0) 1056 { 1057 length += start + offset; 1058 start = -offset; 1059 } 1060 /*}}}*/ 1061 /*{{{ clip length*/ 1062 if(offset + start + length > size) 1063 length = size - offset - start; 1064 /*}}}*/ 1065 /*{{{ clear before first?*/ 1066 if(start < 0) 1067 { 1068 if(plw->pixmap_list.orient == XtorientVertical) 1069 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1070 0, start + offset, plw->core.width, -start, False); 1071 else 1072 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1073 start + offset, 0, -start, plw->core.height, False); 1074 length += start; 1075 start = 0; 1076 } 1077 /*}}}*/ 1078 /*{{{ find first pixmap*/ 1079 for(ix = 0, pi = plw->pixmap_list.pixmap_info, 1080 count = plw->pixmap_list.num_pixmaps; 1081 count; ix++, pi++, count--) 1082 if(start < (plw->pixmap_list.orient == XtorientVertical ? 1083 pi->y + pi->height : pi->x + pi->width) + 1084 plw->pixmap_list.border_width) 1085 break; 1086 /*}}}*/ 1087 for(; length > 0 && count; count--, ix++, pi++) 1088 if(plw->pixmap_list.orient == XtorientVertical) 1089 /*{{{ vertical*/ 1090 { 1091 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1092 0, pi->y + plw->pixmap_list.y - plw->pixmap_list.border_width - 1093 plw->pixmap_list.distance, plw->core.width, 1094 plw->pixmap_list.distance, False); 1095 if(plw->pixmap_list.width >= 0) 1096 { 1097 int width; 1098 1099 width = pi->x + plw->pixmap_list.x - 1100 plw->pixmap_list.border_width; 1101 if(width > 0) 1102 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1103 0, pi->y + plw->pixmap_list.y - 1104 plw->pixmap_list.border_width, 1105 width, pi->height + 2 * plw->pixmap_list.border_width, 1106 False); 1107 width = pi->x + plw->pixmap_list.x + pi->width + 1108 plw->pixmap_list.border_width; 1109 if((int)plw->core.width - width > 0) 1110 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1111 width, pi->y + plw->pixmap_list.y - 1112 plw->pixmap_list.border_width, 1113 plw->core.width - width, 1114 pi->height + 2 * plw->pixmap_list.border_width, False); 1115 } 1116 PaintPixmap(plw, pi, ix); 1117 length -= pi->y + pi->height + plw->pixmap_list.border_width - start; 1118 start = pi->y + pi->height + plw->pixmap_list.border_width; 1119 } 1120 /*}}}*/ 1121 else 1122 /*{{{ horizontal*/ 1123 { 1124 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1125 pi->x + plw->pixmap_list.x - plw->pixmap_list.border_width - 1126 plw->pixmap_list.distance, 0, plw->pixmap_list.distance, 1127 plw->core.height, False); 1128 if(plw->pixmap_list.height >= 0) 1129 { 1130 int height; 1131 1132 height = pi->y + plw->pixmap_list.y - 1133 plw->pixmap_list.border_width; 1134 if(height > 0) 1135 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1136 pi->x + plw->pixmap_list.x - plw->pixmap_list.border_width, 1137 0, pi->width + 2 * plw->pixmap_list.border_width, 1138 height, False); 1139 height = pi->y + plw->pixmap_list.y + pi->height + 1140 plw->pixmap_list.border_width; 1141 if((int)plw->core.height - height > 0) 1142 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1143 pi->x + plw->pixmap_list.x - plw->pixmap_list.border_width, 1144 height, pi->width + 2 * plw->pixmap_list.border_width, 1145 plw->core.height - height, False); 1146 } 1147 PaintPixmap(plw, pi, ix); 1148 length -= pi->x + pi->width + plw->pixmap_list.border_width - start; 1149 start = pi->x + pi->width + plw->pixmap_list.border_width; 1150 } 1151 /*}}}*/ 1152 /*{{{ clear after last?*/ 1153 if(length > 0) 1154 { 1155 if(plw->pixmap_list.orient == XtorientVertical) 1156 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1157 0, start + offset, plw->core.width, length, False); 1158 else 1159 XClearArea(XtDisplay((Widget)plw), XtWindow((Widget)plw), 1160 start + offset, 0, length, plw->core.height, False); 1161 } 1162 /*}}}*/ 1163 return; 1164 } 1165 /*}}}*/ 1166 /*{{{ void GetGC(plw)*/ 1167 static VOIDFUNC GetGC 1168 FUNCARG((widget), 1169 PixmapListWidget widget 1170 ) 1171 /* get the two gcs which we need 1172 */ 1173 { 1174 XGCValues values; 1175 1176 values.foreground = widget->pixmap_list.foreground; 1177 values.line_width = widget->pixmap_list.highlight_thickness; 1178 widget->pixmap_list.gc = XtGetGC((Widget)widget, GCForeground | GCLineWidth, 1179 &values); 1180 values.foreground = widget->pixmap_list.border_color; 1181 values.line_width = widget->pixmap_list.border_width; 1182 widget->pixmap_list.border_gc = XtGetGC((Widget)widget, 1183 GCForeground | GCLineWidth, &values); 1184 return; 1185 } 1186 /*}}}*/ 1187 /*{{{ void GetPixmapSize(plw, pi)*/ 1188 static VOIDFUNC GetPixmapSize 1189 FUNCARG((plw, pi), 1190 PixmapListWidget plw 1191 ARGSEP PixmapInfo *pi 1192 ) 1193 /* find the size of a pixmap, returns 0 if None 1194 */ 1195 { 1196 if(pi->pixmap != None) 1197 { 1198 Window root; 1199 int x, y; 1200 unsigned border; 1201 unsigned depth; 1202 Status status; 1203 1204 status = XGetGeometry(XtDisplay(plw), pi->pixmap, 1205 &root, &x, &y, (unsigned int *)&pi->width, 1206 (unsigned int *)&pi->height, &border, &depth); 1207 } 1208 else 1209 pi->width = pi->height = 0; 1210 return; 1211 } 1212 /*}}}*/ 1213 /*{{{ int GetPointerPosition(plw, event, x, y)*/ 1214 static int GetPointerPosition 1215 FUNCARG((plw, event, xp, yp), 1216 PixmapListWidget plw 1217 ARGSEP XEvent *event 1218 ARGSEP Position *xp /* x offset return */ 1219 ARGSEP Position *yp /* y offset return */ 1220 ) 1221 /* get the pointer position 1222 * returns the selected pixmap, or -1 for none 1223 * sets the pointer offset within that pixmap 1224 */ 1225 { 1226 unsigned got; 1227 Position x; 1228 Position y; 1229 1230 /*{{{ get position from event*/ 1231 switch(event->type) 1232 { 1233 case ButtonPress: 1234 case ButtonRelease: 1235 x = event->xbutton.x; 1236 y = event->xbutton.y; 1237 got = 0; 1238 break; 1239 case MotionNotify: 1240 x = event->xmotion.x; 1241 y = event->xmotion.y; 1242 got = 0; 1243 break; 1244 case EnterNotify: 1245 case LeaveNotify: 1246 x = event->xcrossing.x; 1247 y = event->xcrossing.y; 1248 got = 0; 1249 break; 1250 default: 1251 x = y = 0; 1252 got = -1; 1253 } 1254 /*}}}*/ 1255 if(!got) 1256 { 1257 Cardinal index; 1258 PixmapInfo *pi; 1259 1260 x -= plw->pixmap_list.x; 1261 y -= plw->pixmap_list.y; 1262 got = -1; 1263 for(index = plw->pixmap_list.num_pixmaps, 1264 pi = plw->pixmap_list.pixmap_info; 1265 index--; pi++) 1266 if(x >= pi->x && x < pi->x + pi->width && 1267 y >= pi->y && y < pi->y + pi->height) 1268 { 1269 got = plw->pixmap_list.num_pixmaps - 1 - index; 1270 x -= pi->x; 1271 y -= pi->y; 1272 break; 1273 } 1274 *xp = x; 1275 *yp = y; 1276 } 1277 return got; 1278 } 1279 /*}}}*/ 1280 /*{{{ void RemoveTimeOut(plw)*/ 1281 static VOIDFUNC RemoveTimeOut 1282 FUNCARG((plw), 1283 PixmapListWidget plw 1284 ) 1285 /* remove the flash timeout, if set 1286 */ 1287 { 1288 if(plw->pixmap_list.timeout != (XtIntervalId)0) 1289 { 1290 XtRemoveTimeOut(plw->pixmap_list.timeout); 1291 plw->pixmap_list.timeout = (XtIntervalId)0; 1292 plw->pixmap_list.was = -1; 1293 } 1294 return; 1295 } 1296 /*}}}*/ 1297 /*{{{ void ScrollJump(widget, client, call)*/ 1298 static VOIDFUNC ScrollJump 1299 FUNCARG((widget, client, call), 1300 Widget widget 1301 ARGSEP XtPointer client 1302 ARGSEP XtPointer call 1303 ) 1304 /* jumpscroll callbac from the scrollbar 1305 * set the offset approriately, and redraw the widget 1306 */ 1307 { 1308 PixmapListWidget plw; 1309 int start; 1310 int length; 1311 unsigned reset; 1312 1313 plw = (PixmapListWidget)client; 1314 start = (int)ceil(plw->pixmap_list.length * *(float *)call); 1315 length = plw->pixmap_list.orient == XtorientVertical ? 1316 plw->core.height : plw->core.width; 1317 reset = start + length > plw->pixmap_list.length; 1318 if(reset) 1319 start = plw->pixmap_list.length - length; 1320 if(start < 0) 1321 start = 0; 1322 length = 0; 1323 if(plw->pixmap_list.orient == XtorientVertical) 1324 { 1325 if(start != -plw->pixmap_list.y) 1326 { 1327 plw->pixmap_list.y = -start; 1328 length = plw->core.height; 1329 } 1330 } 1331 else 1332 { 1333 if(start != -plw->pixmap_list.x) 1334 { 1335 plw->pixmap_list.x = -start; 1336 length = plw->core.width; 1337 } 1338 } 1339 if(length) 1340 PaintRect(plw, start, length); 1341 if(reset) 1342 SetScrollbar(plw); 1343 return; 1344 } 1345 /*}}}*/ 1346 /*{{{ void ScrollScroll(widget, client, call)*/ 1347 static VOIDFUNC ScrollScroll 1348 FUNCARG((widget, client, call), 1349 Widget widget 1350 ARGSEP XtPointer client 1351 ARGSEP XtPointer call 1352 ) 1353 /* scroll callback from the scrollbar. 1354 * adjust the offset, and redraw appropriately 1355 */ 1356 { 1357 PixmapListWidget plw; 1358 int start; 1359 int length; 1360 1361 plw = (PixmapListWidget)client; 1362 if(!(int)call) 1363 return; 1364 length = plw->pixmap_list.orient == XtorientVertical ? 1365 plw->core.height : plw->core.width; 1366 start = length / 2; 1367 if((int)call > 0) 1368 start = -start; 1369 start -= plw->pixmap_list.orient == XtorientVertical ? 1370 plw->pixmap_list.y : plw->pixmap_list.x; 1371 if(start < 0) 1372 start = 0; 1373 else if(start + length > plw->pixmap_list.length) 1374 start = plw->pixmap_list.length - length; 1375 length = 0; 1376 if(plw->pixmap_list.orient == XtorientVertical) 1377 { 1378 if(start != -plw->pixmap_list.y) 1379 { 1380 plw->pixmap_list.y = -start; 1381 length = plw->core.height; 1382 } 1383 } 1384 else 1385 { 1386 if(start != -plw->pixmap_list.x) 1387 { 1388 plw->pixmap_list.x = -start; 1389 length = plw->core.width; 1390 } 1391 } 1392 if(length) 1393 { 1394 PaintRect(plw, start, length); 1395 SetScrollbar(plw); 1396 } 1397 return; 1398 } 1399 /*}}}*/ 1400 /*{{{ void SetScrollbar(plw)*/ 1401 static VOIDFUNC SetScrollbar 1402 FUNCARG((plw), 1403 PixmapListWidget plw 1404 ) 1405 /* set the scrollbar scales appropriately 1406 * this needs to be done when 1407 * we're resized 1408 * we insert a pixmap 1409 * we remove a pixmap 1410 * our geometry changes 1411 */ 1412 { 1413 float shown, top; 1414 Arg args[2]; 1415 1416 if(!plw->pixmap_list.scroll) 1417 return; 1418 shown = (float)(plw->pixmap_list.orient == XtorientVertical ? 1419 plw->core.height + 1 : plw->core.width + 1) / 1420 (float)plw->pixmap_list.length; 1421 if(shown > (float)1.0) 1422 shown = (float)1.0; 1423 top = (float)(plw->pixmap_list.orient == XtorientVertical ? 1424 -plw->pixmap_list.y : -plw->pixmap_list.x) / 1425 (float)plw->pixmap_list.length; 1426 XtSetArg(args[0], XtNtopOfThumb, sizeof(float) > sizeof(XtArgVal) ? 1427 (XtArgVal)&top : *(XtArgVal *)&top); 1428 XtSetArg(args[1], XtNshown, sizeof(float) > sizeof(XtArgVal) ? 1429 (XtArgVal)&shown : *(XtArgVal *)&shown); 1430 XtSetValues(plw->pixmap_list.scroll, args, 2); 1431 return; 1432 } 1433 /*}}}*/ 1434 /*{{{ void TimeOut(data, id)*/ 1435 static VOIDFUNC TimeOut 1436 FUNCARG((data, id), 1437 XtPointer data 1438 ARGSEP XtIntervalId *id 1439 ) 1440 /* unflash the selected pixmap 1441 */ 1442 { 1443 PixmapListWidget plw; 1444 int ix; 1445 1446 plw = (PixmapListWidget)data; 1447 plw->pixmap_list.timeout = (XtIntervalId)0; 1448 ix = plw->pixmap_list.was; 1449 plw->pixmap_list.was = -1; 1450 if(XtIsRealized((Widget)plw) && ix >= 0) 1451 PaintPixmap(plw, NULL, ix); 1452 return; 1453 } 1454 /*}}}*/ 1455