X11workbench Toolkit  1.0
window_dressing.c
Go to the documentation of this file.
1 // _ _ _ _ //
3 // __ __(_) _ __ __| | ___ __ __ __| | _ __ ___ ___ ___ (_) _ __ __ _ ___ //
4 // \ \ /\ / /| || '_ \ / _` | / _ \\ \ /\ / / / _` || '__|/ _ \/ __|/ __|| || '_ \ / _` | / __| //
5 // \ V V / | || | | || (_| || (_) |\ V V / | (_| || | | __/\__ \\__ \| || | | || (_| | _| (__ //
6 // \_/\_/ |_||_| |_| \__,_| \___/ \_/\_/_____\__,_||_| \___||___/|___/|_||_| |_| \__, |(_)\___| //
7 // |_____| |___/ //
8 // //
9 // Utilities for painting and handling standard components of windows //
10 // //
12 
13 /*****************************************************************************
14 
15  X11workbench - X11 programmer's 'work bench' application and toolkit
16  Copyright (c) 2010-2019 by Bob Frazier (aka 'Big Bad Bombastic Bob')
17 
18 
19  DISCLAIMER: The X11workbench application and toolkit software are supplied
20  'as-is', with no warranties, either implied or explicit.
21  Any claims to alleged functionality or features should be
22  considered 'preliminary', and might not function as advertised.
23 
24  MIT-like license:
25 
26  There is no restriction as to what you can do with this software, so long
27  as you include the above copyright notice and DISCLAIMER for any distributed
28  work that is equal to or derived from this one, along with this paragraph
29  that explains the terms of the license if the source is also being made
30  available. A "derived work" describes a work that uses a significant portion
31  of the source files or algorithms that are included with this one.
32  Specifically excluded from this are files that were generated by the software,
33  or anything that is included with the software that is part of another package
34  (such as files that were created or added during the 'configure' process).
35  Specifically included is the use of part or all of any of the X11 workbench
36  toolkit source or header files in your distributed application. If you do not
37  ship the source, the above copyright statement is still required to be placed
38  in a reasonably prominent place, such as documentation, splash screens, and/or
39  'about the application' dialog boxes.
40 
41  Use and distribution are in accordance with GPL, LGPL, and/or the above
42  MIT-like license. See COPYING and README files for more information.
43 
44 
45  Additional information at http://sourceforge.net/projects/X11workbench
46 
47 ******************************************************************************/
48 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <memory.h>
56 #include <string.h>
57 #include <strings.h>
58 #include <errno.h>
59 #include <X11/Xlib.h>
60 
61 #include "window_dressing.h"
62 #include "pixmap_helper.h"
63 #include "conf_help.h"
64 #include "draw_text.h"
65 
66 
67 static XColor clrScrollFG,
68  clrScrollBG,
69  clrScrollAFG,
70  clrScrollABG,
71  clrScrollHFG,
72  clrScrollHBG,
73  clrScrollBD,
74  clrScrollBD2,
75  clrScrollBD3;
76 
79 static int iInitScrollColorFlag = 0;
80 
81 
85 #define COPY_COLOR_NAME(X,Y,Z) {const char *pX = X(WBGetDefaultDisplay()); if(pX) strncpy(Y,pX,sizeof(Y)); else strncpy(Y,Z,sizeof(Y));}
86 
89 static void CheckInitScrollColors(void)
90 {
91  // TODO: consider freeing the colors with XFreeColors on exit
92  // TODO: consider not even bothering with 'XAllocColor' and just use PXM_RGBToPixel()
93 
95  {
96  static const char *szBorder2="#FFFFFF", *szBorder2W="#C8C6C0", *szBorder3="#9C9A94"; // for 3D borders
97  char szFG[16], szBG[16], szBD[16], szHFG[16], szHBG[16], szAFG[16], szABG[16]; // must be at least 14 characters
98 // static const char szFGName[]="Scrollbar.foreground";
99 // static const char szBGName[]="Scrollbar.background";
100 // static const char szHFGName[]="Scrollbar.highlightForeground";
101 // static const char szHBGName[]="Scrollbar.highlightBackground";
102 // static const char szAFGName[]="Scrollbar.activeForeground";
103 // static const char szABGName[]="Scrollbar.activeBackground";
104 // static const char szBDName[]="Scrollbar.border";
105 
106  Colormap colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
107 
108 
109  COPY_COLOR_NAME(CHGetTextColor,szFG,"#000000");
110 // LOAD_COLOR0(szFGName,szFG) else LOAD_COLOR0("*Dialog.foreground",szFG) else LOAD_COLOR0("*Form.foreground", szFG)
111 // else LOAD_COLOR0("*WmDialogShell.foreground",szFG) else LOAD_COLOR0("*WmForm.foreground", szFG)
112 // else LOAD_COLOR("*foreground", szFG, "#000000");
113 
115 // LOAD_COLOR0(szBGName,szBG) else LOAD_COLOR0("*Dialog.background",szBG) else LOAD_COLOR0("*Form.background", szBG)
116 // else LOAD_COLOR0("*WmDialogShell.background",szBG)
117 // else LOAD_COLOR("*WmForm.background", szBG, "#dcdad5"); // default for gnome is dcdad5
118 
121  COPY_COLOR_NAME(CHGetActiveTextColor,szAFG,"#000000");
123 // LOAD_COLOR(szHFGName,szHFG,szFG);
124 // LOAD_COLOR(szHBGName,szHBG,szBG);
125 // LOAD_COLOR(szAFGName,szAFG,szFG);
126 // LOAD_COLOR(szABGName,szABG,szBG);
127 
128  COPY_COLOR_NAME(CHGetBorderColor,szBD,"#000000");
129 // LOAD_COLOR0(szBDName,szBD) else LOAD_COLOR0("*Dialog.border",szBD) else LOAD_COLOR0("*Form.border", szBD)
130 // else LOAD_COLOR0("*WmDialogShell.border",szBD) else LOAD_COLOR0("*WmForm.border", szBD)
131 // else LOAD_COLOR0("*borderColor", szBD)
132 // else LOAD_COLOR("*border", szBD, "black"); // default for gnome
133 
134  XParseColor(WBGetDefaultDisplay(), colormap, szFG, &clrScrollFG);
135  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollFG);
136  XParseColor(WBGetDefaultDisplay(), colormap, szBG, &clrScrollBG);
137  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBG);
138  XParseColor(WBGetDefaultDisplay(), colormap, szAFG, &clrScrollAFG);
139  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollAFG);
140  XParseColor(WBGetDefaultDisplay(), colormap, szABG, &clrScrollABG);
141  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollABG);
142  XParseColor(WBGetDefaultDisplay(), colormap, szHFG, &clrScrollHFG);
143  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollHFG);
144  XParseColor(WBGetDefaultDisplay(), colormap, szHBG, &clrScrollHBG);
145  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollHBG);
146  XParseColor(WBGetDefaultDisplay(), colormap, szBD, &clrScrollBD);
147 
148  // 3D border colors for now these are hard-coded - later derive them from FG and BG colors
149  if(clrScrollBG.red >= 60000 && clrScrollBG.green >= 60000 &&
150  clrScrollBG.blue >= 60000) // note see man page on XColor, values 0 through 65535 for RGB
151  {
152  XParseColor(WBGetDefaultDisplay(), colormap, szBorder2W, &clrScrollBD2);
153  }
154  else
155  {
156  XParseColor(WBGetDefaultDisplay(), colormap, szBorder2, &clrScrollBD2);
157  }
158 
159  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBD2);
160  XParseColor(WBGetDefaultDisplay(), colormap, szBorder3, &clrScrollBD3);
161  XAllocColor(WBGetDefaultDisplay(), colormap, &clrScrollBD3);
162 
164  }
165 }
166 
167 
168 static void DebugDumpScrollInfo(WB_SCROLLINFO *pSI)
169 {
170 
171  WBDebugPrint("%s - Debug Dump of Scroll Info\n"
172  " iScrollState = %d,\n"
173  " iVScrollWidth = %d, iHScrollHeight = %d, iVBarHeight = %d, iHBarWidth = %d,\n"
174  " iHKnob = %d, iVKnob = %d, iHKnobSize = %d, iVKnobSize = %d,\n"
175  " iHMin = %d, iHMax = %d iVMin = %d, iVMax = %d, iHPos = %d, iVPos = %d\n"
176  " geomHBar: %d,%d,%d,%d\n"
177  " geomHLeft: %d,%d,%d,%d\n"
178  " geomHRight: %d,%d,%d,%d\n"
179  " geomHKnob: %d,%d,%d,%d\n"
180  " geomVBar: %d,%d,%d,%d\n"
181  " geomVUp: %d,%d,%d,%d\n"
182  " geomVDown: %d,%d,%d,%d\n"
183  " geomVKnob: %d,%d,%d,%d\n",
184  __FUNCTION__,
185  pSI->iScrollState, pSI->iVScrollWidth, pSI->iHScrollHeight,
186  pSI->iVBarHeight, pSI->iHBarWidth,
187  pSI->iHKnob, pSI->iVKnob, pSI->iHKnobSize, pSI->iVKnobSize,
188  pSI->iHMin, pSI->iHMax, pSI->iVMin, pSI->iVMax, pSI->iHPos, pSI->iVPos,
189  pSI->geomHBar.x, pSI->geomHBar.y, pSI->geomHBar.width, pSI->geomHBar.height,
190  pSI->geomHLeft.x, pSI->geomHLeft.y, pSI->geomHLeft.width, pSI->geomHLeft.height,
191  pSI->geomHRight.x, pSI->geomHRight.y, pSI->geomHRight.width, pSI->geomHRight.height,
192  pSI->geomHKnob.x, pSI->geomHKnob.y, pSI->geomHKnob.width, pSI->geomHKnob.height,
193  pSI->geomVBar.x, pSI->geomVBar.y, pSI->geomVBar.width, pSI->geomVBar.height,
194  pSI->geomVUp.x, pSI->geomVUp.y, pSI->geomVUp.width, pSI->geomVUp.height,
195  pSI->geomVDown.x, pSI->geomVDown.y, pSI->geomVDown.width, pSI->geomVDown.height,
196  pSI->geomVKnob.x, pSI->geomVKnob.y, pSI->geomVKnob.width, pSI->geomVKnob.height);
197 }
198 
199 
200 #if 0 /* this function not currently used. consider removeing it in a refactor */
201 static char ilog2n(unsigned char y)
202 {
203  if(y & 0x08)
204  return 4;
205  else if(y & 0x04)
206  return 3;
207  else if(y & 0x02)
208  return 2;
209  else if(y & 0x01)
210  return 1;
211  else
212  return 0;
213 }
214 #endif // 0
215 
216 #if 0 /* this function not currently used. consider removeing it in a refactor */
217 static char ilog2c(unsigned char y)
218 {
219  if(y & 0xf0)
220  return ilog2n(y >> 4) + 4;
221 
222  return ilog2n(y);
223 }
224 #endif // 0
225 
226 #if 0 /* this function not currently used. consider removeing it in a refactor */
227 static int ilog2s(unsigned short y)
228 {
229  if(y & 0xff00)
230  {
231  return ilog2c((unsigned char)(y >> 8)) + 8;
232  }
233 
234  return ilog2c((unsigned char)y);
235 }
236 #endif // 0
237 
238 #if 0 /* this function not currently used. consider removeing it in a refactor */
239 static int ilog2(unsigned int y)
240 {
241  if(y & 0xffff0000)
242  {
243  return ilog2s((unsigned short)(y >> 16)) + 16;
244  }
245 
246  return ilog2s((unsigned short)y);
247 }
248 #endif // 0
249 
250 #if 0 /* this function not currently used. consider removeing it in a refactor */
251 static int ilog2ll(WB_UINT64 y)
252 {
253  if(y & 0xffffffff00000000LL)
254  {
255  return ilog2((unsigned int)(y >> 32)) + 32;
256  }
257 
258  return ilog2((unsigned int)y);
259 }
260 #endif // 0
261 
262 
263 int WBSetVScrollRange(WB_SCROLLINFO *pSI, int iMin, int iMax)
264 {
265 int iRval;
266 
267  iRval = pSI->iVMin < pSI->iVMax;
268 
269  // TODO: data validation
270  pSI->iVMin = iMin;
271  pSI->iVMax = iMax;
272 
273  return (pSI->iVMin < pSI->iVMax) != iRval ? 1 : 0; // 'visibility' changed
274 }
275 
276 int WBSetHScrollRange(WB_SCROLLINFO *pSI, int iMin, int iMax)
277 {
278 int iRval;
279 
280  iRval = pSI->iHMin < pSI->iHMax;
281 
282  // TODO: data validation
283  pSI->iHMin = iMin;
284  pSI->iHMax = iMax;
285 
286  return (pSI->iHMin < pSI->iHMax) != iRval ? 1 : 0; // 'visibility' changed
287 }
288 
289 void WBSetVScrollPos(WB_SCROLLINFO *pSI, int iPos)
290 {
291  // TODO: data validation
292  pSI->iVPos = iPos;
293 }
294 
295 void WBSetHScrollPos(WB_SCROLLINFO *pSI, int iPos)
296 {
297  // TODO: data validation
298  pSI->iHPos = iPos;
299 }
300 
301 static int InternalNotifySelf(Window wID, Atom aNotify, long lData0, long lData1, long lData2, long lData3, long lData4)
302 {
303 Display *pDisplay = WBGetWindowDisplay(wID);
304 
305  XClientMessageEvent evt = {
306  .type=ClientMessage,
307  .serial=0,
308  .send_event=0,
309  .display=pDisplay,
310  .window=wID,
311  .message_type=aNotify,
312  .format=32
313  };
314  evt.data.l[0] = lData0;
315  evt.data.l[1] = lData1;
316  evt.data.l[2] = lData2;
317  evt.data.l[3] = lData3;
318  evt.data.l[4] = lData4;
319 
320  return WBWindowDispatch(wID, (XEvent *)&evt);
321 }
322 
323 
324 static void InternalCalcVScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth, int iHScrollHeight)
325 {
326 int iKnobSize, iKnobPos, iBarHeight;
327 int i1, i2;
328 int nListItems;
329 
330 
331  iBarHeight = pgeomClient->height;
332 
333  pScrollInfo->iVScrollWidth = iVScrollWidth;
334  pScrollInfo->iVBarHeight = iBarHeight;
335 
336  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
337  "%s.%d - iVScrollWidth=%d, iHScrollHeight=%d iBarHeight=%d geomClient=%d,%d,%d,%d border=%d\n",
338  __FUNCTION__, __LINE__, iVScrollWidth, iHScrollHeight, iBarHeight,
339  pgeomClient->x, pgeomClient->y, pgeomClient->width, pgeomClient->height, pgeomClient->border);
340 
341  if(pScrollInfo->iVPos < pScrollInfo->iVMin || pScrollInfo->iVPos > pScrollInfo->iVMax)
342  {
343  pScrollInfo->iVPos = -1; // for now
344  }
345 
346  nListItems = pScrollInfo->iVMax - pScrollInfo->iVMin + 1;
347 
348 
349  // knob height equals 'nListItems / nListItems!' multiplied by
350  // the available knob height, for a minimum value of 'iHScrollHeight'
351 
352  iKnobSize = (iBarHeight - 4 * iHScrollHeight - 2);
353 
354  if(iKnobSize > iHScrollHeight) // / 2)
355  {
356  i1 = iHScrollHeight * (2 * iHScrollHeight + 1); // 'twice scroll height' factorial
357  i2 = iHScrollHeight * 2;
358 
359  while(i2 > 2 && i1 > iKnobSize) // using the above starting point get 'max factorial less than height'
360  {
361  i1 -= i2;
362  i2--;
363  }
364 
365  if(nListItems >= i2) // more than twice scroll height?
366  {
367  if(nListItems > iKnobSize || iKnobSize - i1 < iHScrollHeight / 2)
368  {
369  iKnobSize = -1; // to fix later
370  }
371  else
372  {
373  iKnobSize -= i1; // twice scroll height factorial
374  iKnobSize -= (nListItems - iHScrollHeight * 2 + 1);
375  }
376  }
377  else
378  {
379  iKnobSize -= i1 // 'twice knob height' factorial
380  - (nListItems + 1) * nListItems / 2; // 'nListItems' factorial
381  }
382 
383  if(iKnobSize < iHScrollHeight) // 3 * iHScrollHeight / 4)
384  {
385  iKnobSize = iHScrollHeight; // 3 * iHScrollHeight / 4; // minimum size
386  }
387  }
388  else
389  {
390  iKnobSize = iHScrollHeight; // 3 * iHScrollHeight / 4; // worst case use this anyway
391  }
392 
393  // cache these geometries because I need them for mouse handling
394 
395  pScrollInfo->iVKnobSize = iKnobSize;
396 
397  pScrollInfo->geomVBar.x = pgeomClient->x
398  + pgeomClient->width
399  - iVScrollWidth
400  + 2 * pgeomClient->border; // to account for the border size
401 
402  pScrollInfo->geomVBar.y = pgeomClient->y
403  - pgeomClient->border; // to account for the border size
404  pScrollInfo->geomVBar.height = pgeomClient->height
405  + 2 * pgeomClient->border; // to account for the border size
406  pScrollInfo->geomVBar.width = iVScrollWidth;
407 
408  // is there a vertical scroll bar? If so, I need to adjust the width
409  if(pScrollInfo->iHMin < pScrollInfo->iHMax) // not '-1'
410  {
411  pScrollInfo->geomVBar.height -= iHScrollHeight; // make it a tad smaller
412  }
413 
414 
415  pScrollInfo->geomVUp.x = pScrollInfo->geomVBar.x + 1;
416  pScrollInfo->geomVUp.y = pScrollInfo->geomVBar.y + 1;
417  pScrollInfo->geomVUp.width = pScrollInfo->geomVBar.width - 2;
418  pScrollInfo->geomVUp.height = pScrollInfo->geomVUp.width;
419 
420  pScrollInfo->geomVDown.x = pScrollInfo->geomVUp.x;
421  pScrollInfo->geomVDown.y = pScrollInfo->geomVBar.y
422  + pScrollInfo->geomVBar.height
423  - pScrollInfo->geomVDown.height
424  - 1;
425  pScrollInfo->geomVDown.width = pScrollInfo->geomVUp.width;
426  pScrollInfo->geomVDown.height = pScrollInfo->geomVUp.height;
427 
428  pScrollInfo->geomVKnob.x = pScrollInfo->geomVDown.x;
429  pScrollInfo->geomVKnob.width = pScrollInfo->geomVDown.width;
430  pScrollInfo->geomVKnob.height = iKnobSize;
431 
432  // now that I have a reasonable estimate of the knob size, calculate
433  // the starting vertical position of the knob
434 
435  if(pScrollInfo->iVPos <= 0 || nListItems <= 0)
436  {
437  iKnobPos = 0;
438  }
439  else
440  {
441  int iBarScrollArea = pScrollInfo->geomVDown.y
442  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height)
443  - iKnobSize
444  - 1; // inclusive value
445 
446  if(pScrollInfo->iVPos >= (nListItems - 1))
447  {
448  iKnobPos = iBarScrollArea;
449  }
450  else
451  {
452  iKnobPos = (WB_INT64)pScrollInfo->iVPos * (WB_INT64)iBarScrollArea
453  / (WB_INT64)(nListItems - 1);
454  }
455  }
456 
457 
458  pScrollInfo->geomVKnob.y = (pScrollInfo->iVKnob = iKnobPos)
459  + pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height;
460 
461  // 'fixed' (as in static) values go here
462  pScrollInfo->geomVBar.border = 1;
463  pScrollInfo->geomVUp.border = 0;
464  pScrollInfo->geomVDown.border = 0;
465  pScrollInfo->geomVKnob.border = 0;
466 
467  WB_IF_DEBUG_LEVEL(DebugLevel_Heavy | DebugSubSystem_ScrollBar)
468  {
469  DebugDumpScrollInfo(pScrollInfo);
470  }
471 }
472 
473 
474 static void InternalCalcHScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth, int iHScrollHeight)
475 {
476 int iKnobSize, iKnobPos, iBarWidth;
477 int i1, i2;
478 int nListItems;
479 
480 
481 
482  iBarWidth = pgeomClient->width;
483 
484  pScrollInfo->iHScrollHeight = iHScrollHeight;
485  pScrollInfo->iHBarWidth = iBarWidth;
486 
487 
488  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
489  "%s.%d - iVScrollWidth=%d, iHScrollHeight=%d iBarWidth=%d geomClient=%d,%d,%d,%d border=%d\n",
490  __FUNCTION__, __LINE__, iVScrollWidth, iHScrollHeight, iBarWidth,
491  pgeomClient->x, pgeomClient->y, pgeomClient->width, pgeomClient->height, pgeomClient->border);
492 
493 
494  if(pScrollInfo->iHPos < pScrollInfo->iHMin || pScrollInfo->iHPos > pScrollInfo->iHMax)
495  {
496  pScrollInfo->iHPos = -1; // for now
497  }
498 
499  nListItems = pScrollInfo->iHMax - pScrollInfo->iHMin + 1;
500 
501 
502  // knob height equals 'nListItems / nListItems!' multiplied by
503  // the available knob height, for a minimum value of 'iHScrollHeight'
504 
505  iKnobSize = (iBarWidth - 4 * iVScrollWidth - 2);
506 
507  if(iKnobSize > iVScrollWidth) // / 2)
508  {
509  i1 = iVScrollWidth * (2 * iVScrollWidth + 1); // 'twice scroll width' factorial
510  i2 = iVScrollWidth * 2;
511 
512  while(i2 > 2 && i1 > iKnobSize) // using the above starting point get 'max factorial less than width'
513  {
514  i1 -= i2;
515  i2--;
516  }
517 
518  if(nListItems >= i2) // more than twice scroll height?
519  {
520  if(nListItems > iKnobSize || iKnobSize - i1 < iVScrollWidth / 2)
521  {
522  iKnobSize = -1; // to fix later
523  }
524  else
525  {
526  iKnobSize -= i1; // twice scroll height factorial
527  iKnobSize -= (nListItems - iVScrollWidth * 2 + 1);
528  }
529  }
530  else
531  {
532  iKnobSize -= i1 // 'twice knob height' factorial
533  - (nListItems + 1) * nListItems / 2; // 'nListItems' factorial
534  }
535 
536  if(iKnobSize < iVScrollWidth) // 3 * iVScrollWidth / 4)
537  {
538  iKnobSize = iVScrollWidth; // 3 * iVScrollWidth / 4; // minimum size
539  }
540  }
541  else
542  {
543  iKnobSize = iVScrollWidth; //3 * iVScrollWidth / 4; // worst case use this anyway
544  }
545 
546  // cache these geometries because I need them for mouse handling
547 
548  pScrollInfo->iHKnobSize = iKnobSize;
549 
550  pScrollInfo->geomHBar.x = pgeomClient->x
551  - pgeomClient->border; // to account for the border size
552  pScrollInfo->geomHBar.y = pgeomClient->y
553  + pgeomClient->height
554  - iHScrollHeight
555  + 2 * pgeomClient->border; // to account for the border size
556  pScrollInfo->geomHBar.width = pgeomClient->width
557  + 2 * pgeomClient->border; // to account for the border size
558  pScrollInfo->geomHBar.height = iHScrollHeight;
559 
560  // is there a vertical scroll bar? If so, I need to adjust the width
561  if(pScrollInfo->iVMin < pScrollInfo->iVMax) // not '-1'
562  {
563  pScrollInfo->geomHBar.width -= iVScrollWidth; // make it a tad smaller
564  }
565 
566  pScrollInfo->geomHLeft.x = pScrollInfo->geomHBar.x;
567  pScrollInfo->geomHLeft.y = pScrollInfo->geomHBar.y + 1;
568  pScrollInfo->geomHLeft.height = pScrollInfo->geomHBar.height - 2;
569  pScrollInfo->geomHLeft.width = pScrollInfo->geomHLeft.height;
570 
571  pScrollInfo->geomHRight.x = pScrollInfo->geomHBar.x
572  + pScrollInfo->geomHBar.width
573  - pScrollInfo->geomHLeft.width
574  - 1;
575  pScrollInfo->geomHRight.y = pScrollInfo->geomHLeft.y;
576  pScrollInfo->geomHRight.height = pScrollInfo->geomHLeft.height;
577  pScrollInfo->geomHRight.width = pScrollInfo->geomHLeft.width;
578 
579  pScrollInfo->geomHKnob.y = pScrollInfo->geomHLeft.y;
580  pScrollInfo->geomHKnob.height = pScrollInfo->geomHLeft.height;
581  pScrollInfo->geomHKnob.width = iKnobSize;
582 
583  // now that I have a reasonable estimate of the knob size, calculate
584  // the starting horizontal position of the knob
585 
586  if(pScrollInfo->iHPos <= 0 || nListItems <= 0)
587  {
588 // WB_ERROR_PRINT("*** TEMPORARY: iHPos=%d, nListItems=%d\n",
589 // pScrollInfo->iHPos, nListItems);
590  iKnobPos = 0;
591  }
592  else
593  {
594  int iBarScrollArea = pScrollInfo->geomHRight.x
595  - (pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width)
596  - iKnobSize
597  - 1; // inclusive value
598 
599  if(pScrollInfo->iHPos >= (nListItems - 1))
600  {
601  iKnobPos = iBarScrollArea;
602  }
603  else
604  {
605  iKnobPos = (WB_INT64)pScrollInfo->iHPos * (WB_INT64)iBarScrollArea
606  / (WB_INT64)(nListItems - 1);
607  }
608 
609 // WB_ERROR_PRINT("*** TEMPORARY: %d %d %d %d ==> %d %d %d ==> %d\n",
610 // pScrollInfo->geomHRight.x, pScrollInfo->geomHLeft.x, pScrollInfo->geomHLeft.width,
611 // iKnobSize, iBarScrollArea,
612 // pScrollInfo->iHPos, nListItems, iKnobPos);
613  }
614 
615 
616  pScrollInfo->geomHKnob.x = (pScrollInfo->iHKnob = iKnobPos)
617  + pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width;
618 
619  // 'fixed' (as in static) values go here
620  pScrollInfo->geomVBar.border = 1;
621  pScrollInfo->geomVUp.border = 0;
622  pScrollInfo->geomVDown.border = 0;
623  pScrollInfo->geomVKnob.border = 0;
624 
625  WB_IF_DEBUG_LEVEL(DebugLevel_Heavy | DebugSubSystem_ScrollBar)
626  {
627  DebugDumpScrollInfo(pScrollInfo);
628  }
629 }
630 
631 
632 
633 
634 void WBCalcVScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth,
635  int iHScrollHeight, int nListItems, int nPos)
636 {
637 int iBarHeight, iBarWidth;
638 
639 
640  iBarHeight = pgeomClient->height;
641  iBarWidth = pgeomClient->width;
642 
643  if(pScrollInfo->iVBarHeight == iBarHeight &&
644  pScrollInfo->iHBarWidth == iBarWidth &&
645  pScrollInfo->iVKnob >= 0 &&
646  pScrollInfo->iVKnobSize >= 0 &&
647  pScrollInfo->iVPos == nPos &&
648  pScrollInfo->iVMin == 0 &&
649  pScrollInfo->iVMax == (nListItems - 1))
650  {
651  // assume it's set up correctly
652 
653 // WB_ERROR_TEXT("TEMPORARY: short cycling calc scroll info\n");
654 // return;
655  }
656 
657  if(pScrollInfo->iHBarWidth != iBarWidth ||
658  pScrollInfo->iVBarHeight != iBarHeight) // TODO: do i need this???
659  {
660  // client size change detected
661  // zero out the H Scroll info so that it forces re-calculation next time
662  pScrollInfo->iHKnob = pScrollInfo->iHKnobSize = pScrollInfo->iHPos = pScrollInfo->iHMin = pScrollInfo->iHMax = 0;
663  }
664 
665  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
666  "%s.%d - %d %d %d %d %d\n", __FUNCTION__, __LINE__,
667  iBarHeight, iVScrollWidth, iHScrollHeight, nListItems, nPos);
668 
669  pScrollInfo->iVMin = 0;
670  pScrollInfo->iVMax = nListItems - 1;
671 
672  if(nPos == -1 ||
673  (nPos >= pScrollInfo->iVMin && nPos <= pScrollInfo->iVMax))
674  {
675  pScrollInfo->iVPos = nPos;
676  }
677  else
678  {
679  pScrollInfo->iVPos = nPos = -1;
680  }
681 
682  InternalCalcVScrollBar(pScrollInfo, pgeomClient, iVScrollWidth, iHScrollHeight);
683 
684  pScrollInfo->iHScrollHeight = iHScrollHeight;
685  pScrollInfo->iHBarWidth = iBarWidth;
686 
687  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
688  "%s.%d - iHScrollHeight=%d, iBarWidth=%d\n", __FUNCTION__, __LINE__,
689  iHScrollHeight, iBarWidth);
690 
691 }
692 
693 void WBCalcHScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth,
694  int iHScrollHeight, int nListItems, int nPos)
695 {
696 int /*iKnobSize, iKnobPos,*/ iBarHeight, iBarWidth;
697 //int i1, i2;
698 
699  iBarHeight = pgeomClient->height;
700  iBarWidth = pgeomClient->width;
701 
702  if(pScrollInfo->iVBarHeight == iBarHeight &&
703  pScrollInfo->iHBarWidth == iBarWidth &&
704  pScrollInfo->iVKnob >= 0 &&
705  pScrollInfo->iVKnobSize >= 0 &&
706  pScrollInfo->iVPos == nPos &&
707  pScrollInfo->iVMin == 0 &&
708  pScrollInfo->iVMax == (nListItems - 1))
709  {
710  // assume it's set up correctly
711 
712 // WB_ERROR_TEXT("TEMPORARY: short cycling calc scroll info\n");
713 // return;
714  }
715 
716  if(pScrollInfo->iVBarHeight != iBarHeight ||
717  pScrollInfo->iHBarWidth != iBarWidth) // TODO: do I need this??
718  {
719  // client size change detected
720  // zero out the V Scroll info so that it forces re-calculation next time
721  pScrollInfo->iVKnob = pScrollInfo->iVKnobSize = pScrollInfo->iVPos = pScrollInfo->iVMin = pScrollInfo->iVMax = 0;
722  }
723 
724  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
725  "%s.%d - %d %d %d %d %d\n", __FUNCTION__, __LINE__,
726  iBarWidth, iVScrollWidth, iHScrollHeight, nListItems, nPos);
727 
728  pScrollInfo->iHMin = 0;
729  pScrollInfo->iHMax = nListItems - 1;
730 
731 
732  if(nPos == -1 ||
733  (nPos >= 0 && nPos < nListItems))
734  {
735  pScrollInfo->iHPos = nPos;
736  }
737  else
738  {
739  pScrollInfo->iHPos = nPos = -1;
740  }
741 
742  InternalCalcHScrollBar(pScrollInfo, pgeomClient, iVScrollWidth, iHScrollHeight);
743 
744  pScrollInfo->iVScrollWidth = iVScrollWidth;
745  pScrollInfo->iVBarHeight = iBarHeight;
746 
747  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
748  "%s.%d - iHScrollHeight=%d, iBarWidth=%d\n", __FUNCTION__, __LINE__,
749  iVScrollWidth, iBarHeight);
750 }
751 
752 
753 
754 int WBCalcVScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iY)
755 {
756  if(pScrollInfo &&
757  (pScrollInfo->iVMax >= pScrollInfo->iVMin))
758  {
759  int nListItems = pScrollInfo->iVMax - pScrollInfo->iVMin + 1;
760  int iKnobSize = pScrollInfo->geomVKnob.height;
761  int iKnobPos = iY - iKnobSize / 3
762  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height);
763 
764  int iBarScrollArea = pScrollInfo->geomVDown.y
765  - (pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height)
766  - iKnobSize
767  - 1; // inclusive value
768 
769  if(iBarScrollArea <= 0)
770  {
771  return pScrollInfo->iVMin; // always assume 1st item's index
772  }
773  else
774  {
775  int nPos = (WB_INT64)iKnobPos * (WB_INT64)(nListItems - 1)
776  / (WB_INT64)iBarScrollArea;
777 
778  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
779  "%s.%d iY=%d; nLI=%d KS=%d KP=%d BSA=%d nP=%d\n",
780  __FUNCTION__, __LINE__,
781  iY, nListItems, iKnobSize, iKnobPos, iBarScrollArea, nPos);
782 
783  if(nPos < pScrollInfo->iVMin)
784  {
785  return pScrollInfo->iVMin;
786  }
787  else if(nPos > pScrollInfo->iVMax)
788  {
789  return pScrollInfo->iVMax;
790  }
791  else
792  {
793  return nPos;
794  }
795  }
796  }
797 
798  return -1; // can't evaluate, so return -1
799 }
800 
801 int WBCalcHScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iX)
802 {
803  if(pScrollInfo &&
804  (pScrollInfo->iHMax >= pScrollInfo->iHMin))
805  {
806  int nListItems = pScrollInfo->iHMax - pScrollInfo->iHMin + 1;
807  int iKnobSize = pScrollInfo->geomHKnob.width;
808  int iKnobPos = iX - iKnobSize / 3
809  - (pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width);
810 
811  int iBarScrollArea = pScrollInfo->geomHRight.x
812  - (pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width)
813  - iKnobSize
814  - 1; // inclusive value
815 
816  if(iBarScrollArea <= 0)
817  {
818  return pScrollInfo->iHMin; // always assume 1st item's index
819  }
820  else
821  {
822  int nPos = (WB_INT64)iKnobPos * (WB_INT64)(nListItems - 1)
823  / (WB_INT64)iBarScrollArea;
824 
825  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
826  "%s.%d iX=%d; nLI=%d KS=%d KP=%d BSA=%d nP=%d\n",
827  __FUNCTION__, __LINE__,
828  iX, nListItems, iKnobSize, iKnobPos, iBarScrollArea, nPos);
829 
830  if(nPos < pScrollInfo->iHMin)
831  {
832  return pScrollInfo->iHMin;
833  }
834  else if(nPos > pScrollInfo->iHMax)
835  {
836  return pScrollInfo->iHMax;
837  }
838  else
839  {
840  return nPos;
841  }
842  }
843  }
844 
845  return -1; // can't evaluate, so return -1
846 }
847 
848 
850  WB_GEOM *pgeomClient, WB_GEOM *pgeomUsable)
851 {
852 WB_GEOM geom;
853 int iVScrollWidth, iHScrollHeight;
854 XCharStruct xBounds;
855 
856  // TODO: data validation
857 
858  if(!pFont)
859  {
860  pFont = WBGetDefaultFont();
861  }
862 
863  geom.x = pgeomClient->x;
864  geom.y = pgeomClient->y;
865  geom.width = pgeomClient->width;
866  geom.height = pgeomClient->height;
867  geom.border = pgeomClient->border;
868 
869  xBounds = WBFontMaxBounds(pFont);
870 
871  iVScrollWidth = WBTextWidth(pFont, "X", 1) * 2 + 4; // standard width of vertical scrollbar
872  iHScrollHeight = xBounds.ascent + xBounds.descent + 4;
873 
874  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
875  "%s.%d - iVScrollWidth=%d, iHScrollHeight=%d geom=%d,%d,%d,%d (%d)\n",
876  __FUNCTION__, __LINE__, iVScrollWidth, iHScrollHeight,
877  geom.x, geom.y, geom.width, geom.height, geom.border);
878 
879  // calculate the rectangles for the scroll bars
880 
881  if(pSI->iVMin < pSI->iVMax)
882  {
883 // InternalCalcVScrollBar(pSI, pgeomClient, iVScrollWidth, pScrollInfo->iVMin,
884 // pScrollInfo->iVMax, pScrollInfo->iVPos);
885  InternalCalcVScrollBar(pSI, pgeomClient, iVScrollWidth, iHScrollHeight);
886 
887  geom.width -= iVScrollWidth;
888  }
889 
890  if(pSI->iHMin < pSI->iHMax)
891  {
892 // InternalCalcHScrollBar(pSI, pgeomClient, iHScrollHeight, pScrollInfo->iHMin,
893 // pScrollInfo->iHMax, pScrollInfo->iHPos);
894  InternalCalcHScrollBar(pSI, pgeomClient, iVScrollWidth, iHScrollHeight);
895 
896 
897  geom.height -= iHScrollHeight;
898  }
899 
900  if(pgeomUsable)
901  {
902  memcpy(pgeomUsable, &geom, sizeof(*pgeomUsable));
903  }
904 
905  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
906  " SCROLL INFO: iVBarHeight = %-6d iHBarWidth = %d\n"
907  " iVKnob = %-6d iHKnob = %d\n"
908  " iVKnobSize = %-6d iHKnobSize = %d\n"
909  " iVPos = %-6d iHPos = %d\n"
910  " iVMin = %-6d iVMin = %d\n"
911  " iVMax = %-6d iVMax = %d\n\n",
912  pSI->iVBarHeight, pSI->iHBarWidth,
913  pSI->iVKnob, pSI->iHKnob,
914  pSI->iVKnobSize, pSI->iHKnobSize,
915  pSI->iVPos, pSI->iHPos,
916  pSI->iVMin, pSI->iHMin,
917  pSI->iVMax, pSI->iHMax);
918 }
919 
920 void WBInvalidateVScrollGeom(Window wID, WB_SCROLLINFO *pScrollInfo, int bAll, int bUpdate)
921 {
922 WB_GEOM geom;
923 
924  if(wID == None || !pScrollInfo)
925  {
926  return;
927  }
928 
929  // calculate geometry of the scrollbar minus the up/down buttons and border
930 
931  geom.border = 0;
932 
933  if(bAll)
934  {
935  geom.x = pScrollInfo->geomVBar.x;
936  geom.y = pScrollInfo->geomVBar.y;
937  geom.width = pScrollInfo->geomVBar.width;
938  geom.height = pScrollInfo->geomVBar.height;
939  geom.border = pScrollInfo->geomVBar.border;
940  }
941  else
942  {
943  geom.x = pScrollInfo->geomVBar.x;
944  geom.y = pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height;
945  geom.width = pScrollInfo->geomVBar.width;
946  geom.height = pScrollInfo->geomVDown.y - geom.y;
947  geom.border = pScrollInfo->geomVBar.border; // just use this one
948  }
949 
950  WBInvalidateGeom(wID, &geom, bUpdate); // invalidate scroll area before notifying
951 }
952 
953 void WBInvalidateHScrollGeom(Window wID, WB_SCROLLINFO *pScrollInfo, int bAll, int bUpdate)
954 {
955 WB_GEOM geom;
956 
957  if(wID == None || !pScrollInfo)
958  {
959  return;
960  }
961 
962  // calculate geometry of the scrollbar minus the left/right buttons and border
963 
964  geom.border = 0;
965 
966  if(bAll)
967  {
968  geom.x = pScrollInfo->geomHBar.x;
969  geom.y = pScrollInfo->geomHBar.y;
970  geom.width = pScrollInfo->geomHBar.width;
971  geom.height = pScrollInfo->geomHBar.height;
972  geom.border = pScrollInfo->geomHBar.border;
973  }
974  else
975  {
976  geom.x = pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width;
977  geom.y = pScrollInfo->geomHBar.y;
978  geom.width = pScrollInfo->geomHRight.x - geom.x;
979  geom.height = pScrollInfo->geomHBar.height;
980  geom.border = pScrollInfo->geomHBar.border; // just use this one
981  }
982 
983  WBInvalidateGeom(wID, &geom, bUpdate); // invalidate scroll area before notifying
984 }
985 
986 
987 int WBScrollBarEvent(Window wID, XEvent *pEvent, WB_SCROLLINFO *pScrollInfo)
988 {
989 int iRval, iX, iY, iDirection, iPosition;
990 
991 
992  if(wID == None || !pEvent || pEvent->type != ClientMessage || !pScrollInfo)
993  {
994  return 0; // only client message events and valid parameters
995  }
996 
997  // TODO handle mouse-up events ??
998  if(pEvent->xclient.message_type == aWB_POINTER)
999  {
1000  if(pEvent->xclient.data.l[0] == WB_POINTER_CLICK)
1001  {
1002  // TODO: handle shift-click, ctrl-click, alt-click
1003 
1004  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1005  !pEvent->xclient.data.l[2])
1006  {
1007  iX = pEvent->xclient.data.l[3];
1008  iY = pEvent->xclient.data.l[4];
1009 
1010  if(WB_LIKELY(pScrollInfo != NULL))
1011  {
1012  iDirection = (int)WB_SCROLL_NA;
1013  iPosition = 0;
1014 
1015  if(WBPointInGeom(iX, iY, pScrollInfo->geomVBar))
1016  {
1017  if(WBPointInGeom(iX, iY, pScrollInfo->geomVUp))
1018  {
1019  iDirection = WB_SCROLL_BACKWARD;
1020  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1021  "%s Mouse click in vertical scroll bar (up)\n", __FUNCTION__);
1022  }
1023  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVDown))
1024  {
1025  iDirection = WB_SCROLL_FORWARD;
1026  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1027  "%s Mouse click in vertical scroll bar (down)\n", __FUNCTION__);
1028  }
1029  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVKnob))
1030  {
1031  // ON THE KNOB - VScroll
1032 
1033  iDirection = WB_SCROLL_KNOB;
1034  iPosition = WBCalcVScrollDragPos(pScrollInfo, iY);
1035 
1036  if(iPosition < 0)
1037  {
1038  iPosition = pScrollInfo->iVMin; //pListInfo->nTop;
1039  }
1040 
1041  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1042  "%s Mouse click in vertical scroll bar (knob), iPosition=%d\n", __FUNCTION__, iPosition);
1043  }
1044  else if(iY >= pScrollInfo->geomVUp.y + pScrollInfo->geomVUp.height &&
1045  iY < pScrollInfo->geomVKnob.y)
1046  {
1047  iDirection = WB_SCROLL_PAGEBACK;
1048  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1049  "%s Mouse click in vertical scroll bar (page up)\n", __FUNCTION__);
1050  }
1051  else if(iY >= pScrollInfo->geomVKnob.y + pScrollInfo->geomVKnob.height &&
1052  iY < pScrollInfo->geomVDown.y)
1053  {
1054  iDirection = WB_SCROLL_PAGEFWD;
1055  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1056  "%s Mouse click in vertical scroll bar (page down)\n", __FUNCTION__);
1057  }
1058  else
1059  {
1060  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1061  "%s Mouse click in vertical scroll bar (unknown)\n", __FUNCTION__);
1062  }
1063 
1064  InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_VERTICAL, iDirection, iPosition, 0, 0);
1065 
1066  return 1; // handled
1067  }
1068  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHBar))
1069  {
1070  if(WBPointInGeom(iX, iY, pScrollInfo->geomHLeft))
1071  {
1072  iDirection = WB_SCROLL_BACKWARD;
1073  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1074  "%s Mouse click in horizontal scroll bar (left)\n", __FUNCTION__);
1075  }
1076  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHRight))
1077  {
1078  iDirection = WB_SCROLL_FORWARD;
1079  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1080  "%s Mouse click in horizontal scroll bar (right)\n", __FUNCTION__);
1081  }
1082  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHKnob))
1083  {
1084  // ON THE KNOB - HScroll
1085 
1086  iDirection = WB_SCROLL_KNOB;
1087 // iPosition = pScrollInfo->iHMin; // NO!
1088  iPosition = WBCalcHScrollDragPos(pScrollInfo, iX);
1089 
1090  if(iPosition < 0)
1091  {
1092  iPosition = pScrollInfo->iHMin; //pListInfo->nTop;
1093  }
1094 
1095  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1096  "%s Mouse click in horizontal scroll bar (knob). iPosition=%d\n", __FUNCTION__, iPosition);
1097 
1098  // TODO: determine position of knob
1099  }
1100  else if(iX >= pScrollInfo->geomHLeft.x + pScrollInfo->geomHLeft.width &&
1101  iX < pScrollInfo->geomHKnob.x)
1102  {
1103  iDirection = WB_SCROLL_PAGEBACK;
1104  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1105  "%s Mouse click in horizontal scroll bar (page left)\n", __FUNCTION__);
1106  }
1107  else if(iX >= pScrollInfo->geomHKnob.x + pScrollInfo->geomHKnob.width &&
1108  iX < pScrollInfo->geomHRight.x)
1109  {
1110  iDirection = WB_SCROLL_PAGEFWD;
1111  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1112  "%s Mouse click in horizontal scroll bar (page right)\n", __FUNCTION__);
1113  }
1114  else
1115  {
1116  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1117  "%s Mouse click in horizontal scroll bar (unknown)\n", __FUNCTION__);
1118  }
1119 
1120  InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_HORIZONTAL, iDirection, iPosition, 0, 0);
1121 
1122  return 1; // handled
1123  }
1124  }
1125  }
1126  }
1127  else if(pEvent->xclient.data.l[0] == WB_POINTER_DBLCLICK)
1128  {
1129  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1130  !pEvent->xclient.data.l[2])
1131  {
1132  iX = pEvent->xclient.data.l[3];
1133  iY = pEvent->xclient.data.l[4];
1134  // assume selection already done, so notify owner
1135 
1136  if(WB_LIKELY(pScrollInfo != NULL))
1137  {
1138  if(WBPointInGeom(iX, iY, pScrollInfo->geomVBar))
1139  {
1140  // if not within knob, re-post to self as single-click
1141  if(!WBPointInGeom(iX, iY, pScrollInfo->geomVKnob))
1142  {
1143  XClientMessageEvent evt;
1144  memcpy(&evt, pEvent, sizeof(evt));
1145  evt.data.l[0] = WB_POINTER_CLICK;
1146 
1147  return WBScrollBarEvent(wID, (XEvent *)&evt, pScrollInfo);
1148  }
1149  }
1150  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHBar))
1151  {
1152  // if not within knob, re-post to self as single-click
1153  if(!WBPointInGeom(iX, iY, pScrollInfo->geomHKnob))
1154  {
1155  XClientMessageEvent evt;
1156  memcpy(&evt, pEvent, sizeof(evt));
1157  evt.data.l[0] = WB_POINTER_CLICK;
1158 
1159  return WBScrollBarEvent(wID, (XEvent *)&evt, pScrollInfo);
1160  }
1161  }
1162  }
1163  }
1164  }
1165  else if(pEvent->xclient.data.l[0] == WB_POINTER_CANCEL)
1166  {
1167  // canceling drag (as appropriate)
1168 
1169 // if(pScrollInfo &&
1170 // pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1171 // !pEvent->xclient.data.l[2])
1172 // {
1173 // pScrollInfo->iScrollState &= ~WBScrollState_LDRAG;
1174 // }
1175  if((pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
1176  (pScrollInfo->iScrollState & WBScrollState_MDRAG) ||
1177  (pScrollInfo->iScrollState & WBScrollState_RDRAG))
1178  {
1180 
1181  return 1; // "handled"
1182  }
1183  }
1184  else if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG ||
1185  pEvent->xclient.data.l[0] == WB_POINTER_MOVE)
1186  {
1187  if(pEvent->xclient.data.l[1] == WB_POINTER_BUTTON1 && // left button
1188  !pEvent->xclient.data.l[2])
1189  {
1190  iX = pEvent->xclient.data.l[3];
1191  iY = pEvent->xclient.data.l[4];
1192 
1193  if(WB_LIKELY(pScrollInfo != NULL))
1194  {
1195  if(!WBPointInGeom(iX, iY, pScrollInfo->geomVBar) &&
1196  !WBPointInGeom(iX, iY, pScrollInfo->geomHBar) &&
1197  (!(pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
1198  pEvent->xclient.data.l[0] == WB_POINTER_DRAG))
1199  {
1200  // TODO: this is for multi-select listboxes, doing a drag-select
1201 
1202  pScrollInfo->iScrollState &= ~WBScrollState_LDRAG; // make sure
1203 
1204  return 0; // "not handled" (allow drag-select to be handled by scrollbar owner)
1205  }
1206  else if(WBPointInGeom(iX, iY, pScrollInfo->geomVKnob) ||
1207  WB_LIKELY(pEvent->xclient.data.l[0] == WB_POINTER_MOVE &&
1208  (pScrollInfo->iScrollState & WBScrollState_LDRAG)))
1209  {
1210  if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG) // begin drag, return window ID
1211  {
1212  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1213  "%s Mouse drag in vert scroll bar (knob)\n", __FUNCTION__);
1214 
1215  pScrollInfo->iScrollState |= WBScrollState_LDRAG; // set the state bit for left-drag
1216  return((int)wID); // enabling the drag
1217  }
1218 
1219  iPosition = WBCalcVScrollDragPos(pScrollInfo, iY);
1220 
1221  if(iPosition < 0)
1222  {
1223  iPosition = pScrollInfo->iVMin; //pListInfo->nTop;
1224  }
1225 
1226  // track the mouse position along the center of the knob, if possible
1227 
1228  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1229  "%s Mouse motion in scroll bar (knob) iPosition=%d\n", __FUNCTION__, iPosition);
1230 
1231  InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_VERTICAL,
1232  WB_SCROLL_KNOB, iPosition, 0, 0);
1233 
1234  return 1; // handled
1235  }
1236  else if(WBPointInGeom(iX, iY, pScrollInfo->geomHKnob) ||
1237  WB_LIKELY(pEvent->xclient.data.l[0] == WB_POINTER_MOVE &&
1238  (pScrollInfo->iScrollState & WBScrollState_HLDRAG)))
1239  {
1240  if(pEvent->xclient.data.l[0] == WB_POINTER_DRAG) // begin drag, return window ID
1241  {
1242  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1243  "%s Mouse drag in horiz scroll bar (knob)\n", __FUNCTION__);
1244 
1245  pScrollInfo->iScrollState |= WBScrollState_HLDRAG; // set the state bit for left-drag
1246  return((int)wID); // enabling the drag (window ID cannot be 'None')
1247  }
1248 
1249  iPosition = WBCalcHScrollDragPos(pScrollInfo, iX);
1250 
1251  if(iPosition < 0)
1252  {
1253  iPosition = pScrollInfo->iHMin; // pListInfo->nTop;
1254  }
1255 
1256  // track the mouse position along the center of the knob, if possible
1257 
1258  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1259  "%s Mouse motion in scroll bar (knob) iPosition=%d\n", __FUNCTION__, iPosition);
1260 
1261  InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_HORIZONTAL,
1262  WB_SCROLL_KNOB, iPosition, 0, 0);
1263 
1264  return 1; // handled
1265  }
1266  else
1267  {
1268  WB_DEBUG_PRINT(DebugLevel_Medium | DebugSubSystem_ScrollBar | DebugSubSystem_Event,
1269  "%s mouse motion in scroll bar outside of knob\n", __FUNCTION__);
1270  }
1271  }
1272  }
1273  }
1274  else if(pEvent->xclient.data.l[0] == WB_POINTER_DROP)
1275  {
1276  if(WB_LIKELY(pScrollInfo != NULL))
1277  {
1278  if((pScrollInfo->iScrollState & WBScrollState_LDRAG) ||
1279  (pScrollInfo->iScrollState & WBScrollState_MDRAG) ||
1280  (pScrollInfo->iScrollState & WBScrollState_RDRAG))
1281  {
1283 
1284  return 1; // "handled" (just a notification anyway)
1285  }
1286  }
1287  }
1288  else if(pEvent->xclient.data.l[0] == WB_POINTER_SCROLLUP)
1289  {
1290  iRval = InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_VERTICAL, WB_SCROLL_BACKWARD, 0, 0, 0);
1291 
1292  if(iRval)
1293  {
1294  return iRval; // to indicate it was handled
1295  }
1296  }
1297  else if(pEvent->xclient.data.l[0] == WB_POINTER_SCROLLDOWN)
1298  {
1299  iRval = InternalNotifySelf(wID, aSCROLL_NOTIFY, WB_SCROLL_VERTICAL, WB_SCROLL_FORWARD, 0, 0, 0);
1300 
1301  if(iRval)
1302  {
1303  return iRval; // to indicate it was handled
1304  }
1305  }
1306 
1307  // TODO: anything else?
1308  }
1309  else if(pEvent->xclient.message_type == aWB_CHAR)
1310  {
1311  // handle cursors only - up, down, left, right, home, end, page up, page down, etc.
1312 
1313  long lKey WB_UNUSED = pEvent->xclient.data.l[0]; // return from WBKeyEventProcessKey
1314  long lAltCtrlShift WB_UNUSED = pEvent->xclient.data.l[1]; // *piAltCtrlShift from WBKeyEventProcessKey
1315 #ifndef NO_DEBUG
1316  int nChar WB_UNUSED = (int)pEvent->xclient.data.l[2]; // # of characters decoded into pBuf (below)
1317  char *pBuf WB_UNUSED = (char *)&(pEvent->xclient.data.l[3]); // decode buffer (at least 8 chars in length)
1318 #endif // !NO_DEBUG
1319 
1320 #warning scroll bar hot keys have not been implemented yet
1321  // TODO: scroll bar hotkeys
1322 
1323 
1324  }
1325 
1326 // WB_ERROR_PRINT("TEMPORARY: %s %d - NOT handled\n", __FUNCTION__, __LINE__);
1327 // WBDebugDumpEvent(pEvent);
1328 
1329  return 0;
1330 }
1331 
1332 
1333 // this assumes WB_SCROLLINFO is valid. To make it so, call WBUpdateScrollBarGeometry() or similar
1334 
1335 void WBPaintHScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID,
1336  WBGC gc, WB_GEOM *pgeomClient)
1337 {
1339 
1340  // fill scrollbar with background color
1341  WBSetForeground(gc, clrScrollBG.pixel);
1342  WBFillRectangle(pDisplay, wID, gc, pScrollInfo->geomHBar.x - 1, pScrollInfo->geomHBar.y,
1343  pScrollInfo->geomHBar.width + 1, pScrollInfo->geomHBar.height);
1344 
1345  // draw 3D borders around everything
1346 
1347  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHBar),
1348  clrScrollBD3.pixel, clrScrollBD2.pixel);
1349 
1350  // if the scrollbar is DISABLED, do not draw the rest of it
1351  if(pScrollInfo->iHPos < pScrollInfo->iHMin ||
1352  pScrollInfo->iHPos > pScrollInfo->iHMax ||
1353  pScrollInfo->iHMax < pScrollInfo->iHMin)
1354  {
1355  WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1356  "%s - grey out iHPos=%d iHMin=%d iHMax=%d\n", __FUNCTION__,
1357  pScrollInfo->iHPos, pScrollInfo->iHMin, pScrollInfo->iHMax);
1358 
1359  return; // I am done (greyed out bar)
1360  }
1361 
1362  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1363  "%s - paint 'left' button %d %d %d %d (%d)\n", __FUNCTION__,
1364  pScrollInfo->geomHLeft.x,
1365  pScrollInfo->geomHLeft.y,
1366  pScrollInfo->geomHLeft.width,
1367  pScrollInfo->geomHLeft.height,
1368  pScrollInfo->geomHLeft.border);
1369 
1370  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHLeft),
1371  clrScrollBD2.pixel, clrScrollBD3.pixel);
1372 
1373  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1374  "%s - paint 'right' button %d %d %d %d (%d)\n", __FUNCTION__,
1375  pScrollInfo->geomHRight.x,
1376  pScrollInfo->geomHRight.y,
1377  pScrollInfo->geomHRight.width,
1378  pScrollInfo->geomHRight.height,
1379  pScrollInfo->geomHRight.border);
1380 
1381  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHRight),
1382  clrScrollBD2.pixel, clrScrollBD3.pixel);
1383 
1384  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1385  "%s - paint horizontal 'knob' %d %d %d %d (%d)\n", __FUNCTION__,
1386  pScrollInfo->geomHKnob.x,
1387  pScrollInfo->geomHKnob.y,
1388  pScrollInfo->geomHKnob.width,
1389  pScrollInfo->geomHKnob.height,
1390  pScrollInfo->geomHKnob.border);
1391 
1392  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomHKnob),
1393  clrScrollBD2.pixel, clrScrollBD3.pixel);
1394 
1395  // draw arrows
1396 
1397  WBDrawLeftArrow(pDisplay, wID, gc, &(pScrollInfo->geomHLeft), clrScrollFG.pixel);
1398  WBDrawRightArrow(pDisplay, wID, gc, &(pScrollInfo->geomHRight), clrScrollFG.pixel);
1399 }
1400 
1401 // NOTE: this assumes WB_SCROLLINFO is valid. To make it so, call WBUpdateScrollBarGeometry() or similar
1402 
1403 void WBPaintVScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID,
1404  WBGC gc, WB_GEOM *pgeomClient)
1405 {
1407 
1408  // fill scrollbar with background color
1409  WBSetForeground(gc, clrScrollBG.pixel);
1410  WBFillRectangle(pDisplay, wID, gc, pScrollInfo->geomVBar.x - 1, pScrollInfo->geomVBar.y,
1411  pScrollInfo->geomVBar.width + 1, pScrollInfo->geomVBar.height);
1412 
1413  // draw 3D borders around everything
1414 
1415  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVBar),
1416  clrScrollBD3.pixel, clrScrollBD2.pixel);
1417 
1418  // if the scrollbar is DISABLED, do not draw the rest of it
1419  if(pScrollInfo->iVPos < pScrollInfo->iVMin ||
1420  pScrollInfo->iVPos > pScrollInfo->iVMax ||
1421  pScrollInfo->iVMax < pScrollInfo->iVMin)
1422  {
1423  WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1424  "%s - grey out iVPos=%d iVMin=%d iVMax=%d\n", __FUNCTION__,
1425  pScrollInfo->iVPos, pScrollInfo->iVMin, pScrollInfo->iVMax);
1426 
1427  return; // I am done (greyed out bar)
1428  }
1429 
1430  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1431  "%s - paint 'up' button %d %d %d %d (%d)\n", __FUNCTION__,
1432  pScrollInfo->geomVUp.x,
1433  pScrollInfo->geomVUp.y,
1434  pScrollInfo->geomVUp.width,
1435  pScrollInfo->geomVUp.height,
1436  pScrollInfo->geomVUp.border);
1437 
1438  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVUp),
1439  clrScrollBD2.pixel, clrScrollBD3.pixel);
1440 
1441  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1442  "%s - paint 'down' button %d %d %d %d (%d)\n", __FUNCTION__,
1443  pScrollInfo->geomVDown.x,
1444  pScrollInfo->geomVDown.y,
1445  pScrollInfo->geomVDown.width,
1446  pScrollInfo->geomVDown.height,
1447  pScrollInfo->geomVDown.border);
1448 
1449  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVDown),
1450  clrScrollBD2.pixel, clrScrollBD3.pixel);
1451 
1452  WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_ScrollBar | DebugSubSystem_Expose,
1453  "%s - paint vertical 'knob' %d %d %d %d (%d)\n", __FUNCTION__,
1454  pScrollInfo->geomVKnob.x,
1455  pScrollInfo->geomVKnob.y,
1456  pScrollInfo->geomVKnob.width,
1457  pScrollInfo->geomVKnob.height,
1458  pScrollInfo->geomVKnob.border);
1459 
1460  WBDraw3DBorderRect(pDisplay, wID, gc, &(pScrollInfo->geomVKnob),
1461  clrScrollBD2.pixel, clrScrollBD3.pixel);
1462 
1463  // draw arrows
1464 
1465  WBDrawUpArrow(pDisplay, wID, gc, &(pScrollInfo->geomVUp), clrScrollFG.pixel);
1466  WBDrawDownArrow(pDisplay, wID, gc, &(pScrollInfo->geomVDown), clrScrollFG.pixel);
1467 }
1468 
1469 
1470 
1472 // //
1473 // ____ _ ____ _ _ _ //
1474 // | _ \ _ __ __ _ __ __(_) _ __ __ _ | _ \ _ __ (_) _ __ ___ __ _ | |_ (_)__ __ ___ ___ //
1475 // | | | || '__|/ _` |\ \ /\ / /| || '_ \ / _` | | |_) || '__|| || '_ ` _ \ / _` || __|| |\ \ / // _ \/ __| //
1476 // | |_| || | | (_| | \ V V / | || | | || (_| | | __/ | | | || | | | | || (_| || |_ | | \ V /| __/\__ \ //
1477 // |____/ |_| \__,_| \_/\_/ |_||_| |_| \__, | |_| |_| |_||_| |_| |_| \__,_| \__||_| \_/ \___||___/ //
1478 // |___/ //
1479 // //
1481 
1482 void WBDrawBorderRect(Display *pDisplay, Drawable wID, WBGC gc,
1483  WB_GEOM *pgeomBorder, unsigned long lBorderColor)
1484 {
1485 XPoint xpt[5];
1486 
1487  if(!pgeomBorder || !pDisplay || wID == None || gc == None)
1488  {
1489  return; // parameter validation
1490  }
1491 
1492  WBSetForeground(gc, lBorderColor);
1493 
1494  xpt[0].x=pgeomBorder->x;
1495  xpt[0].y=pgeomBorder->y;
1496 
1497  xpt[1].x = xpt[0].x
1498  + pgeomBorder->width
1499  - 1; // 'inclusive' values
1500 
1501  xpt[1].y = xpt[0].y;
1502 
1503  xpt[2].x = xpt[1].x;
1504  xpt[2].y = xpt[1].y
1505  + pgeomBorder->height
1506  - 1;
1507 
1508  xpt[3].x = xpt[0].x;
1509  xpt[3].y = xpt[2].y;
1510 
1511  xpt[4].x = xpt[0].x;
1512  xpt[4].y = xpt[0].y + 1; // exclude final point
1513 
1514  WBDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
1515 }
1516 
1517 void WBDraw3DBorderRect(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder,
1518  unsigned long lBorderColor1, unsigned long lBorderColor2)
1519 {
1520 XPoint xpt[4];
1521 XColor clr;
1522 int iR, iG, iB;
1523 
1524 
1525  if(!pgeomBorder || !pDisplay || wID == None || gc == None)
1526  {
1527  return; // parameter validation
1528  }
1529 
1530  WBSetForeground(gc, lBorderColor1);
1531  xpt[0].x = pgeomBorder->x;
1532  xpt[0].y = pgeomBorder->y
1533  + pgeomBorder->height - 1 - 1; // exclude first point
1534 
1535  xpt[1].x = xpt[0].x;
1536  xpt[1].y = pgeomBorder->y;
1537 
1538  xpt[2].x = xpt[0].x
1539  + pgeomBorder->width - 1 - 1; // exclude last point
1540  xpt[2].y = xpt[1].y;
1541 
1542  WBDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
1543 
1544  WBSetForeground(gc, lBorderColor2);
1545 
1546  xpt[0].x = pgeomBorder->x
1547  + pgeomBorder->width - 1;
1548  xpt[0].y = pgeomBorder->y + 1; // exclude first point
1549 
1550  xpt[1].x = xpt[0].x;
1551  xpt[1].y = pgeomBorder->y
1552  + pgeomBorder->height - 1;
1553 
1554  xpt[2].x = pgeomBorder->x + 1; // exclude final point
1555  xpt[2].y = xpt[1].y;
1556 
1557  WBDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
1558 
1559  // Use the RGB info to calculate an 'average' color for the corners
1560 
1561  bzero(&clr, sizeof(clr));
1562  clr.pixel = lBorderColor1;
1563 
1564  PXM_PixelToRGB(NULL, &clr);
1565 
1566  iR = (clr.flags & DoRed) ? (unsigned int)clr.red : 0;
1567  iG = (clr.flags & DoGreen) ? (unsigned int)clr.green : 0;
1568  iB = (clr.flags & DoBlue) ? (unsigned int)clr.blue : 0;
1569 
1570  bzero(&clr, sizeof(clr));
1571  clr.pixel = lBorderColor2;
1572 
1573  PXM_PixelToRGB(NULL, &clr);
1574 
1575  iR += (clr.flags & DoRed) ? (unsigned int)clr.red : 0;
1576  iG += (clr.flags & DoGreen) ? (unsigned int)clr.green : 0;
1577  iB += (clr.flags & DoBlue) ? (unsigned int)clr.blue : 0;
1578 
1579  bzero(&clr, sizeof(clr));
1580 
1581  clr.red = iR >> 1;
1582  clr.green = iG >> 1;
1583  clr.blue = iB >> 1;
1584 
1585  PXM_RGBToPixel(NULL, &clr); // TODO: alloc the color as well?
1586 
1587 // WB_ERROR_PRINT("TEMPORARY: %s - average of %08xH and %08xH is %08xH (%d, %d, %d)\n", __FUNCTION__,
1588 // (unsigned int)lBorderColor1, (unsigned int)lBorderColor2,
1589 // (unsigned int)clr.pixel, clr.red, clr.green, clr.blue);
1590 
1591  WBSetForeground(gc, clr.pixel);
1592 
1593  xpt[0].x = pgeomBorder->x;
1594  xpt[1].y = pgeomBorder->y;
1595 
1596  xpt[1].x = xpt[0].x + pgeomBorder->width - 1;
1597  xpt[0].y = xpt[1].y + pgeomBorder->height - 1;
1598 
1599  WBDrawPoints(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
1600 
1601  WBSetForeground(gc, lBorderColor1);
1602 
1603 }
1604 
1605 void WBDrawBorderElipse(Display *pDisplay, Drawable wID, WBGC gc,
1606  WB_GEOM *pgeomBorder, unsigned long lBorderColor)
1607 {
1608  if(!pgeomBorder || !pDisplay || wID == None || gc == None)
1609  {
1610  return; // parameter validation
1611  }
1612 
1613  WBSetForeground(gc, lBorderColor);
1614 
1615  WBDrawArc(pDisplay, wID, gc,
1616  pgeomBorder->x, pgeomBorder->y,
1617  pgeomBorder->width, pgeomBorder->height,
1618  0, 360 * 64); // draw a full circle within the geom bounds
1619 }
1620 
1621 void WBDraw3DBorderElipse(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder,
1622  unsigned long lBorderColor1, unsigned long lBorderColor2)
1623 {
1624  if(!pgeomBorder || !pDisplay || wID == None || gc == None)
1625  {
1626  return; // parameter validation
1627  }
1628 
1629  // use lBorderColor1 from 45 to 225, and lBorderColor2 from 225 back to 45
1630  // (positive angles indicate counterclockwise rotation for WBDrawArc)
1631 
1632  WBSetForeground(gc, lBorderColor2);
1633 
1634  WBDrawArc(pDisplay, wID, gc,
1635  pgeomBorder->x, pgeomBorder->y,
1636  pgeomBorder->width, pgeomBorder->height,
1637  0, 360 * 64); // entire circle
1638 
1639  WBSetForeground(gc, lBorderColor1);
1640 
1641  WBDrawArc(pDisplay, wID, gc,
1642  pgeomBorder->x, pgeomBorder->y,
1643  pgeomBorder->width, pgeomBorder->height,
1644  45 * 64, 180 * 64); // upper half-circle 45 to 180
1645 
1646  WBDrawArc(pDisplay, wID, gc,
1647  pgeomBorder->x, pgeomBorder->y,
1648  pgeomBorder->width, pgeomBorder->height,
1649  -135 * 64, -180 * 64); // upper half-circle 180 to 225 (-135)
1650 
1651 // WBSetForeground(gc, lBorderColor2);
1652 //
1653 // WBDrawArc(pDisplay, wID, gc,
1654 // pgeomBorder->x, pgeomBorder->y,
1655 // pgeomBorder->width, pgeomBorder->height,
1656 // -45 * 64, -225 * 64); // lower half-circle
1658 }
1659 
1660 void WBDrawDashedRect(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
1661 {
1662 static const char dash_list[4]={1,2,2,1};
1663 WBGC gc2;
1664 
1665 
1666  gc2 = WBGetWindowCopyGC2(wID, gc);
1667 
1668  if(gc2)
1669  {
1670  WBDrawBorderRect(pDisplay, wID, gc2, pgeomRect, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
1671  WBSetDashes(gc2, 1, dash_list, 4);
1672  WBSetLineAttributes(gc2, 1, LineOnOffDash, CapNotLast, JoinBevel);
1673  WBSetBackground(gc2, WhitePixel(pDisplay, DefaultScreen(pDisplay)));
1674  WBDrawBorderRect(pDisplay, wID, gc2, pgeomRect, lColor);
1675 
1676  WBFreeGC(gc2);
1677  }
1678  else
1679  {
1680  WB_ERROR_PRINT("%s:%d - unable to create GC\n", __FUNCTION__, __LINE__);
1681  }
1682 }
1683 
1684 void WBDrawLeftArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
1685 {
1686 XPoint xpt[5];
1687 long lBG, lFG;
1688 
1689  lBG = WBGetGCBGColor(gc);
1690  lFG = WBGetGCFGColor(gc); // save color context
1691 
1692  WBSetForeground(gc, lColor);
1693  WBSetBackground(gc, lColor);
1694 
1695  // LEFT ARROW
1696  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2);
1697  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2) + (pgeomRect->height >> 2);
1698  xpt[1].x = xpt[0].x + (pgeomRect->width >> 1) - 1;
1699  xpt[1].y = pgeomRect->y + (pgeomRect->height >> 2);
1700  xpt[2].x = xpt[1].x;
1701  xpt[2].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
1702  xpt[3].x = xpt[0].x;
1703  xpt[3].y = xpt[2].y - (pgeomRect->height >> 2);
1704  xpt[4].x = xpt[0].x;
1705  xpt[4].y = xpt[0].y;
1706 
1707  WBDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
1708  WBFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
1709 
1710  WBSetForeground(gc, lFG);
1711  WBSetBackground(gc, lBG); // restore color context
1712 }
1713 
1714 void WBDrawUpArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
1715 {
1716 XPoint xpt[5];
1717 long lBG, lFG;
1718 
1719  lBG = WBGetGCBGColor(gc);
1720  lFG = WBGetGCFGColor(gc); // save color context
1721 
1722  WBSetForeground(gc, lColor);
1723  WBSetBackground(gc, lColor);
1724 
1725  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2) + (pgeomRect->width >> 2);
1726  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2);
1727  xpt[1].x = pgeomRect->x + (pgeomRect->width >> 2);
1728  xpt[1].y = xpt[0].y + (pgeomRect->height >> 1) - 1;
1729  xpt[2].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
1730  xpt[2].y = xpt[1].y;
1731  xpt[3].x = xpt[2].x - (pgeomRect->width >> 2);
1732  xpt[3].y = xpt[0].y;
1733  xpt[4].x = xpt[0].x;
1734  xpt[4].y = xpt[0].y;
1735 
1736  WBDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
1737  WBFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
1738 
1739  WBSetForeground(gc, lFG);
1740  WBSetBackground(gc, lBG); // restore color context
1741 }
1742 
1743 void WBDrawRightArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
1744 {
1745 XPoint xpt[5];
1746 long lBG, lFG;
1747 
1748  lBG = WBGetGCBGColor(gc);
1749  lFG = WBGetGCFGColor(gc); // save color context
1750 
1751  WBSetForeground(gc, lColor);
1752  WBSetBackground(gc, lColor);
1753 
1754  // RIGHT ARROW
1755  xpt[0].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
1756  xpt[0].y = pgeomRect->y + (pgeomRect->height >> 2) + (pgeomRect->height >> 2);
1757  xpt[1].x = xpt[0].x - (pgeomRect->width >> 1) + 1;
1758  xpt[1].y = pgeomRect->y + (pgeomRect->height >> 2);
1759  xpt[2].x = xpt[1].x;
1760  xpt[2].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
1761  xpt[3].x = xpt[0].x;
1762  xpt[3].y = xpt[2].y - (pgeomRect->height >> 2);
1763  xpt[4].x = xpt[0].x;
1764  xpt[4].y = xpt[0].y;
1765 
1766  WBDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
1767  WBFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
1768 
1769  WBSetForeground(gc, lFG);
1770  WBSetBackground(gc, lBG); // restore color context
1771 }
1772 
1773 void WBDrawDownArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
1774 {
1775 XPoint xpt[5];
1776 long lBG, lFG;
1777 
1778  lBG = WBGetGCBGColor(gc);
1779  lFG = WBGetGCFGColor(gc); // save color context
1780 
1781  WBSetForeground(gc, lColor);
1782  WBSetBackground(gc, lColor);
1783 
1784  xpt[0].x = pgeomRect->x + (pgeomRect->width >> 2) + (pgeomRect->width >> 2);
1785  xpt[0].y = pgeomRect->y + pgeomRect->height - 1 - (pgeomRect->height >> 2);
1786  xpt[1].x = pgeomRect->x + (pgeomRect->width >> 2);
1787  xpt[1].y = xpt[0].y - (pgeomRect->height >> 1) + 1;
1788  xpt[2].x = pgeomRect->x + pgeomRect->width - 1 - (pgeomRect->width >> 2);
1789  xpt[2].y = xpt[1].y;
1790  xpt[3].x = xpt[2].x - (pgeomRect->width >> 2);
1791  xpt[3].y = xpt[0].y;
1792  xpt[4].x = xpt[0].x;
1793  xpt[4].y = xpt[0].y;
1794 
1795  WBDrawLines(pDisplay, wID, gc, xpt, 5, CoordModeOrigin);
1796  WBFillPolygon(pDisplay, wID, gc, xpt, 5, /*Convex*/Nonconvex, CoordModeOrigin);
1797 
1798  WBSetForeground(gc, lFG);
1799  WBSetBackground(gc, lBG); // restore color context
1800 }
1801 
1802 void WBDraw3DBorderTab(Display *pDisplay, Drawable dw, WBGC gc, WB_GEOM *pgeomOutline,
1803  int fFocus, unsigned long lFGColor, unsigned long lBGColor,
1804  unsigned long lBorderColor1, unsigned long lBorderColor2,
1805  unsigned long lHighlightColor,
1806  WB_FONTC pFont, WB_FONTC pFontBold,
1807  Atom aGraphic, const char *szText)
1808 {
1809 XPoint xpt[13];
1810 XColor clrAvg, clrTemp;
1811 unsigned long lHighlightColor2;
1812 int iFontHeight, bFocus;
1813 int i1, i2, iR, iG, iB, iY, iU, iV, iYBG, iY0, iU0, iV0;
1814 Region rgnClip;
1815 WBGC gc2;
1816 WB_RECT rctTemp;
1817 
1818 
1819  if(!pFont)
1820  {
1821  pFont = WBGetDefaultFont();
1822  }
1823 
1824  if(!pFontBold)
1825  {
1826  pFontBold = WBGetDefaultFont();
1827  }
1828 
1829  iFontHeight = WBFontHeight(pFont);
1830 
1831 
1832  // begin by creating a region that consists of my 'rounded rect' polygon
1833 
1834  // create a rounded-corner trapezoid the encompasses the tab. corner pixels will
1835  // be averages of the border colors.
1836 
1837  // lower left corner
1838  xpt[0].x = pgeomOutline->x;
1839  xpt[0].y = pgeomOutline->y + pgeomOutline->height + 1; // for clip rgn, I do this
1840 
1841  // left side
1842  xpt[1].x = xpt[0].x + 2; // slight trapezoid
1843  xpt[1].y = pgeomOutline->y + 3; // room for corner
1844 
1845  // upper left corner
1846  xpt[2].x = xpt[1].x + 1;
1847  xpt[2].y = xpt[1].y - 1; // 45 degrees
1848  xpt[3].x = xpt[2].x + 1;
1849  xpt[3].y = xpt[2].y - 1; // again
1850  xpt[4].x = xpt[3].x + 1;
1851  xpt[4].y = xpt[3].y - 1; // now we're "on point"
1852 
1853  // top row
1854  xpt[5].x = xpt[0].x + pgeomOutline->width - 5;
1855  xpt[5].y = xpt[4].y;
1856 
1857  // upper right corner
1858  xpt[6].x = xpt[5].x + 1;
1859  xpt[6].y = xpt[5].y + 1; // 45 degrees
1860  xpt[7].x = xpt[6].x + 1;
1861  xpt[7].y = xpt[6].y + 1; // 45 degrees
1862  xpt[8].x = xpt[7].x + 1;
1863  xpt[8].y = xpt[7].y + 1; // 45 degrees
1864 
1865  // right side
1866  xpt[9].x = pgeomOutline->x + pgeomOutline->width;
1867  xpt[9].y = xpt[0].y; // same y as 1st point
1868 
1869  xpt[10].x = xpt[0].x;
1870  xpt[10].y = xpt[0].y; // close up the polygon
1871 
1872  rgnClip = XPolygonRegion(xpt, 11, WindingRule);
1873  if(rgnClip == None)
1874  {
1875  WB_ERROR_PRINT("ERROR: %s - unable to create polygon region\n", __FUNCTION__);
1876  return;
1877  }
1878 
1879  // create GC copy and select the clipping region
1880 
1881  gc2 = WBCopyDrawableGC(pDisplay, dw, gc);
1882 
1883  if(gc2 == None)
1884  {
1885  XDestroyRegion(rgnClip);
1886 
1887  WB_ERROR_PRINT("ERROR: %s - unable to create GC\n", __FUNCTION__);
1888  return;
1889  }
1890 
1891  // select the clip region
1892  WBSetRegion(gc2, rgnClip);
1893 
1894  // set 'bFocus' to indicate if I have focus. 'fFocus' also indicates 'x' button state
1895  // 0 or < -1 is "I do not have focus". -1 or > 0 is "I have focus". negative is 'x button clicked'
1896 
1897  bFocus = fFocus > 0 || fFocus == -1;
1898 
1899  lHighlightColor2 = lHighlightColor; // initially, to avoid warnings later. it's only assigned/used when bFocus is TRUE
1900 
1901  if(bFocus)
1902  {
1903  // do the background color in the tab. this will use the clip region to help me
1904 
1905  clrTemp.pixel = lBGColor; // default background color
1906  PXM_PixelToRGB(NULL, &clrTemp);
1907 
1908  iR = clrTemp.red >> 8;
1909  iG = clrTemp.green >> 8;
1910  iB = clrTemp.blue >> 8;
1911 
1912  PXM_RGBToYUV(iR, iG, iB, &iYBG, NULL, NULL); // get 'Y' for the background (assume grey)
1913  // if the background Y is less than 'pure white', split the difference
1914  if(iYBG < 255)
1915  {
1916  iYBG = (iYBG + 256) / 2; // halfway between white and background luminocity
1917  }
1918 
1919  iY0 = iYBG; // initialize this way
1920 
1921  clrTemp.pixel = lHighlightColor;
1922  PXM_PixelToRGB(NULL, &clrTemp);
1923 
1924  iR = clrTemp.red >> 8; // convert to 8-bit colors
1925  iG = clrTemp.green >> 8;
1926  iB = clrTemp.blue >> 8;
1927 
1928  PXM_RGBToYUV(iR, iG, iB, &iY0, &iU0, &iV0); // cache YUV as iY0, iU0, iV0
1929 
1930  // restrict the range of the brightness of the highlight color vs background
1931 
1932  if(iY0 > 5 * iYBG / 8) // no more than 5/8 of backgroun luma
1933  {
1934  iY0 = 5 * iYBG / 8;
1935  }
1936  else if(iY0 < 3 * iYBG / 8) // at least 3/8 of background luma
1937  {
1938  iY0 = 3 * iYBG / 8;
1939  }
1940 
1941  PXM_YUVToRGB(iY0, iU0, iV0, &iR, &iG, &iB); // convert back from YUV to RGB
1942 
1943  clrTemp.red = (iR << 8) + 128; // convert to 16-bit colors
1944  clrTemp.green = (iG << 8) + 128;
1945  clrTemp.blue = (iB << 8) + 128;
1946 
1947  PXM_RGBToPixel(NULL, &clrTemp); // fix 'pixel' entry
1948 
1949  lHighlightColor2 = clrTemp.pixel; // and store it for later (this is the shadow color now)
1950 
1951 
1952  i2 = 6 * (xpt[0].y - xpt[5].y - 2) / 7; // calculate 6/7 of the tab height, what I deem to be the 'white' point
1953 
1954 // WB_ERROR_PRINT("TEMPORARY: %s - i2 is %d, from %d and %d\n", __FUNCTION__,
1955 // i2, xpt[0].y, xpt[5].y);
1956 
1957  for(i1=xpt[5].y; i1 < xpt[0].y - 2; i1++)
1958  {
1959  XPoint xpt2[2];
1960  int iR2 = abs(i1 - (xpt[5].y + i2 / 2)); // 'i2 / 2' is 3/7 of the height...
1961 
1962  iR2 = 128 + WB_icos(iR2 * 240 / i2); // 255 would be pi/2, so go slightly less than that for 'full range' on the cosine
1963  // NOTE: a value closer to '255' will darken the darkest part of the shadow
1964  iR2 = ((int)iR2 * (int)iR2) / 256; // use cos^2 - 'icos' returns a value between 0 and 255
1965 // iR2 *= iR2; old way, squared it
1966 // iR2 = isqrt(iR2); old way, square root
1967 
1968  iY = iY0; // grab cached YUV values for highlight color
1969  iU = iU0;
1970  iV = iV0;
1971 
1972  // NOTE: 'iY' is the brightness of the highlight color, 'iYBG' the brightness of the background (averaged with white)
1973 
1974 // iY = iYBG * 3 / 4 + ((384 - iYBG) * iR2) / 384; // allows brightness to drop to a bit less than the background's brightness
1975  iY = (iYBG - iY + iY / 2) * iR2 / 256 + iY + iY / 2 + 4;
1976 
1977  if(iY > 255)
1978  {
1979  // 'U' and 'V' are actually signed values, +127,-128 so must subtract 128 before calc, add after
1980  // and in this case, we fade to white as luminocity adjusts to a value of 'pure white'
1981  iU = 128 + (iU - 128) * 255 / iY * 255 / iY; // this will make the color "fade to white"
1982  iV = 128 + (iV - 128) * 255 / iY * 255 / iY; // by reducing U and V by the amount in excess of '255' the luma goes
1983  iY = 255;
1984  }
1985 
1986  PXM_YUVToRGB(iY, iU, iV, &iR, &iG, &iB);
1987 
1988  clrTemp.red = (iR << 8) + 128; // convert to 16-bit color - adding 128 is for the roundoff
1989  clrTemp.green = (iG << 8) + 128;
1990  clrTemp.blue = (iB << 8) + 128;
1991  clrTemp.flags = DoRed | DoGreen | DoBlue;
1992 
1993  PXM_RGBToPixel(NULL, &clrTemp);
1994 
1995 // WB_ERROR_PRINT("TEMPORARY: %s - YUV is %d, %d, %d, RGB is %d, %d, %d for %lu (%08lxH)\n", __FUNCTION__,
1996 // iY, iU, iV,
1997 // clrTemp.red, clrTemp.green, clrTemp.blue, clrTemp.pixel, clrTemp.pixel);
1998 
1999  WBSetForeground(gc2, clrTemp.pixel); // select this color
2000 
2001  xpt2[0].x = pgeomOutline->x + 1;
2002  xpt2[0].y = i1;
2003  xpt2[1].x = pgeomOutline->x + pgeomOutline->width - 2;
2004  xpt2[1].y = xpt2[0].y;
2005 
2006  if(i1 < xpt[5].y + 2) // corner hack, based on observation
2007  {
2008  xpt2[0].x += (xpt[5].y + 2) - i1;
2009  xpt2[1].x -= (xpt[5].y + 2) - i1;
2010  }
2011 
2012  // draw the line
2013  WBDrawLines(pDisplay, dw, gc2, xpt2, 2, CoordModeOrigin); // stop at point 6 (don't paint 6 to 7)
2014  }
2015  }
2016 
2017 
2018  // next, squeeze in the right/left edges of my points. I've observed I need to do this
2019  // as a hack, don't do the left squeeze for the 'focus' tab
2020 
2021  if(!bFocus)
2022  {
2023  for(i1=0; i1 < 5; i1++)
2024  {
2025  xpt[i1].x ++;
2026  }
2027  }
2028 
2029  for(i1=5; i1 < 10; i1++)
2030  {
2031  xpt[i1].x --;
2032  }
2033 
2034  if(!bFocus)
2035  {
2036  xpt[0].y -= 3; // one above 'bottom' (where I'll draw a line)
2037  }
2038  else
2039  {
2040  xpt[0].y -= 2;
2041  }
2042 
2043  xpt[9].y = xpt[0].y; // same y as 1st point
2044 
2045  xpt[10].x = xpt[0].x; // re-close up polygon (again)
2046  xpt[10].y = xpt[0].y; // close up the polygon
2047 
2048 
2049  // make a copy of the GC
2050 
2051  WBSetForeground(gc2, lFGColor);
2052  WBSetBackground(gc2, lBGColor);
2053 
2054  // Use the RGB info to calculate an 'average' color for the corner transition
2055 
2056  bzero(&clrAvg, sizeof(clrAvg));
2057  clrAvg.pixel = lBorderColor1;
2058 
2059  PXM_PixelToRGB(NULL, &clrAvg);
2060 
2061  iR = (clrAvg.flags & DoRed) ? (unsigned int)clrAvg.red : 0;
2062  iG = (clrAvg.flags & DoGreen) ? (unsigned int)clrAvg.green : 0;
2063  iB = (clrAvg.flags & DoBlue) ? (unsigned int)clrAvg.blue : 0;
2064 
2065  bzero(&clrAvg, sizeof(clrAvg));
2066  clrAvg.pixel = lBorderColor2;
2067 
2068  PXM_PixelToRGB(NULL, &clrAvg);
2069 
2070  iR += (clrAvg.flags & DoRed) ? (unsigned int)clrAvg.red : 0;
2071  iG += (clrAvg.flags & DoGreen) ? (unsigned int)clrAvg.green : 0;
2072  iB += (clrAvg.flags & DoBlue) ? (unsigned int)clrAvg.blue : 0;
2073 
2074  bzero(&clrAvg, sizeof(clrAvg));
2075 
2076  clrAvg.red = iR >> 1;
2077  clrAvg.green = iG >> 1;
2078  clrAvg.blue = iB >> 1;
2079 
2080  PXM_RGBToPixel(NULL, &clrAvg); // TODO: alloc the color as well?
2081 
2082  // next, draw polygon using 3D colors
2083 
2084  WBSetForeground(gc2, lBorderColor1);
2085  WBDrawLines(pDisplay, dw, gc2, xpt, 7, CoordModeOrigin); // stop at point 6 (don't paint 6 to 7)
2086 
2087  WBSetForeground(gc2, lBorderColor2);
2088  WBDrawLines(pDisplay, dw, gc2, xpt + 8, 2, CoordModeOrigin); // stop at point 6 (don't paint 6 or 7)
2089 
2090  if(bFocus)
2091  {
2092  // for non-focus, draw the bottom (7 to 8) using border color 2. for focus, draw as background color
2093 
2094  WBSetForeground(gc2, lBGColor);
2095  }
2096 
2097  WBDrawLines(pDisplay, dw, gc2, xpt + 9, 2, CoordModeOrigin); // the bottom line
2098 
2099  // paint pixels 6 and 7 with the 'average' color
2100  WBSetForeground(gc2, clrAvg.pixel);
2101  WBDrawPoints(pDisplay, dw, gc2, xpt + 6, 2, CoordModeOrigin);
2102 
2103  if(!bFocus)
2104  {
2105  // when not in focus, also do avg color for the first pixel. this completes the 3D effect 'color transition'
2106  WBDrawPoints(pDisplay, dw, gc2, xpt, 1, CoordModeOrigin);
2107  }
2108 
2109 
2110 
2111  // TAB TEXT (TODO: image atom)
2112 
2113  rctTemp.left = pgeomOutline->x + 1;
2114  rctTemp.top = pgeomOutline->y + 1;
2115  rctTemp.right = rctTemp.left + pgeomOutline->width - 1;
2116  rctTemp.bottom = rctTemp.top + pgeomOutline->height - 1;
2117 
2118  if(!szText)
2119  {
2120  szText = "{untitled}";
2121  }
2122 
2123  // for now just do centered text. it's 3D text, shifted up-left and bottom-right for 3D effect
2124 
2125  if(bFocus) // 3D "sunken" text if I have the focus
2126  {
2127  rctTemp.left--;
2128  rctTemp.top--;
2129  rctTemp.right--;
2130  rctTemp.bottom--;
2131 
2132  WBSetBackground(gc2, lBGColor);
2133 // WBSetForeground(gc2, lHighlightColor2);
2134  WBSetForeground(gc2, lBGColor);
2135 
2136  DTDrawSingleLineText(pFont, szText, pDisplay, gc2, dw, 0, 0, &rctTemp,
2138 
2139  rctTemp.left += 2;
2140  rctTemp.top += 2;
2141  rctTemp.right += 2;
2142  rctTemp.bottom += 2;
2143 
2144 // WBSetForeground(gc2, lBGColor);
2145  WBSetForeground(gc2, lHighlightColor2);
2146 
2147  // for now just do centered text
2148  DTDrawSingleLineText(pFont, szText, pDisplay, gc2, dw, 0, 0, &rctTemp,
2150 
2151 
2152  rctTemp.left--;
2153  rctTemp.top--;
2154  rctTemp.right--;
2155  rctTemp.bottom--;
2156 
2157 // WBSetBackground(gc2, lHighlightColor2);
2158  }
2159  else
2160  {
2161  WBSetBackground(gc2, lBGColor);
2162  }
2163 
2164  WBSetForeground(gc2, lFGColor);
2165 
2166  // for now just do centered text
2167  DTDrawSingleLineText(pFont, szText, pDisplay, gc2, dw, 0, 0, &rctTemp,
2169 
2170 
2171  // NOW, I need to draw the 'x' for the close button. Fist, I calculate its rect
2172 
2173  rctTemp.top = pgeomOutline->y + 2; // top plus 2 pixels
2174  rctTemp.bottom = rctTemp.top + iFontHeight; // height is font height
2175  rctTemp.right = pgeomOutline->x + pgeomOutline->width - 6; // right is 6 pixels from right edge
2176  rctTemp.left = rctTemp.right - iFontHeight + 2; // left is 2 pixels + font height from right
2177 
2178  if(fFocus < 0) // clicking 'x' ?
2179  {
2180  WBSetForeground(gc2, lHighlightColor);
2181  WBSetBackground(gc2, lHighlightColor);
2182  }
2183  else
2184  {
2185  WBSetForeground(gc2, lBGColor);
2186  WBSetBackground(gc2, lBGColor);
2187  }
2188 
2189  // fill in with selected colors
2190 
2191  WBFillRectangle(pDisplay, dw, gc2, rctTemp.left, rctTemp.top, rctTemp.right - rctTemp.left, rctTemp.bottom - rctTemp.top);
2192 
2193  if(fFocus < 0) // clicking 'x' ?
2194  {
2195  WBSetForeground(gc2, lBGColor);
2196  }
2197  else
2198  {
2199  WBSetForeground(gc2, lHighlightColor);
2200  }
2201 
2202  // now draw the '+' using a BOLD font
2203 
2204  rctTemp.left -=2;
2205  rctTemp.right += 2;
2206  rctTemp.top -= 2;
2207  rctTemp.bottom += 2; // big enough to 'center' properly
2208 
2209  DTDrawSingleLineText(pFontBold, "x", pDisplay, gc2, dw, 0, 0, &rctTemp,
2211 
2212 
2213  WBFreeGC(gc2);
2214  XDestroyRegion(rgnClip);
2215 
2216 
2217 // WB_ERROR_PRINT("TEMPORARY: %s - only partially implemented\n", __FUNCTION__);
2218 }
2219 
2220 
2221 
const char * CHGetHighlightForegroundColor(Display *pDisplay)
returns highlight foreground color
Definition: conf_help.c:3409
#define WB_LIKELY(x)
optimization for code branching when condition is 'likely'. use within conditionals
int WBDrawPoints(Display *display, Drawable d, WBGC gc, XPoint *points, int npoints, int mode)
Wrapper for XDrawPoints()
void WBDraw3DBorderElipse(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor1, unsigned long lBorderColor2)
Draw a 3D 'border' elipse within a bounding geometry.
2nd parameter (direction) - up, left
void PXM_RGBToYUV(int iR, int iG, int iB, int *piY, int *piU, int *piV)
Convert R, G, B values to Y, U, V with 0-255 range.
#define WB_POINTER_DBLCLICK
WB_POINTER 'double-click' event, send in lieu of WB_POINTER_CLICK for double-click.
#define WB_POINTER_CLICK
Mouse 'click' event.
static XColor clrScrollABG
active background scroll bar color
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:364
#define WB_POINTER_DROP
WB_POINTER 'drop' event, only sent if drag/drop supported AND was not 'canceled'; see WB_POINTER_CANC...
int WBFontHeight(WB_FONTC pFont0)
Get the maximum character height from a WB_FONT.
Definition: font_helper.c:546
Utilities for copying and drawing text, determining text extents, and so on.
static XColor clrScrollBG
background scroll bar color
void WBPaintHScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomClient)
Paint the horizontal scroll bar within a window based on WB_SCROLLINFO.
int iHPos
current horozontal scroll position (N/A if outside of min/max range)
int WBSetLineAttributes(WBGC hGC, unsigned int line_width, int line_style, int cap_style, int join_style)
Assign font to a WBGC, a wrapper for XSetLineAttributes()
generic 'NA' or 'UNDEFINED' value
#define WB_POINTER_SCROLLDOWN
WB_POINTER 'scroll down' event, caused by mouse button 5.
void PXM_YUVToRGB(int iY, int iU, int iV, int *piR, int *piG, int *piB)
Convert Y, U, V values to R, G, B with 0-255 range.
WB_GEOM geomVDown
geometry for the vertical scroll bar 'down' button (empty if not visible)
WB_GEOM geomHRight
geometry for the horizontal scroll bar 'right' button (empty if not visible)
int WBScrollBarEvent(Window wID, XEvent *pEvent, WB_SCROLLINFO *pScrollInfo)
Event handler for scroll bars.
unsigned int border
unsigned int width
const char * CHGetActiveBackgroundColor(Display *pDisplay)
returns background color for active elements
Definition: conf_help.c:3323
int WBWindowDispatch(Window wID, XEvent *pEvent)
Dispatches a window XEvent. May be called directly.
int WBCalcHScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iX)
Calculate and assign the correct horizontal scroll bar position from mouse coordinates.
1st parameter (bar) - The vertical scroll bar for the control or window.
int iHBarWidth
calculated width of horizontal scroll bar (re-calculate on window size change)
2nd parameter (direction) - 'knob track' - pos in data.l[2]
static XColor clrScrollBD3
3D highlight scroll bar border color (dark)
WB_GEOM geomVBar
geometry for the vertical scroll bar excluding border (empty if not visible)
int WBFillPolygon(Display *display, Drawable d, WBGC gc, XPoint *points, int npoints, int shape, int mode)
Wrapper for XFillPolygon()
horizontally centered text. tabs are treated as white space
Definition: draw_text.h:78
void WBDrawLeftArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw a left arrow in a window within a specified geometry.
static int iInitScrollColorFlag
initialization flag for scroll colors. when zero, colors not yet initialized
Atom aWB_CHAR
keystroke/character notifications generated by API
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
internal wrapper struct for X11 'geometry' definition
'configuration helper' main header file for the X11 Work Bench Toolkit API
void PXM_RGBToPixel(XStandardColormap *pMap, XColor *pColor)
Icon Registration for application 'large' and 'small' icons.
int iVScrollWidth
calculated width of vertical scroll bar (in pixels); 0 if not known
const char * CHGetActiveTextColor(Display *pDisplay)
returns 'active' text color
Definition: conf_help.c:3366
void PXM_PixelToRGB(XStandardColormap *pMap, XColor *pColor)
Convert the pixel menber of an XColor to RGB.
void DTDrawSingleLineText(WB_FONTC pFont, const char *szText, Display *pDisplay, WBGC gc, Drawable dw, int iTabWidth, int iTabOrigin, const WB_RECT *prcBounds, int iAlignment)
draw single-line text
Definition: draw_text.c:1531
int WBSetForeground(WBGC hGC, unsigned long foreground)
Assign foreground color, a wrapper for XSetForeground()
int WBDrawArc(Display *display, Drawable d, WBGC gc, int x, int y, unsigned int width, unsigned int height, int angle1, int angle2)
Wrapper for XDrawArc()
Atom aWB_POINTER
pointer click/double-click/drag notifications generated by API
#define COPY_COLOR_NAME(X, Y, Z)
macro to get a color name or use default if it does not exist in settings
#define WBGetWindowCopyGC2(wID, gcSrc)
makes a copy of the specified WBGC for the desired window
internal flag, applies simple anti-aliasing. See WBSimpleAntiAliasImage() and WBSimpleAntiAliasPixmap...
Definition: draw_text.h:119
void WBInvalidateHScrollGeom(Window wID, WB_SCROLLINFO *pScrollInfo, int bAll, int bUpdate)
Utility function to invalidate the geometry for the horizontal scroll bar.
Atom aSCROLL_NOTIFY
void WBInvalidateGeom(Window wID, const WB_GEOM *pGeom, int bPaintNow)
'Paint' helper, invalidates a geometry for asynchronous Expose event generation
1st parameter (bar) - The horizontal scroll bar for the control or window
int WBDrawLines(Display *display, Drawable d, WBGC gc, XPoint *points, int npoints, int mode)
Wrapper for XDrawLine()
void WBDrawRightArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw a right arrow in a window within a specified geometry.
int iScrollState
scroll state flags - see enumeration WBScrollState_ENUM
static XColor clrScrollBD2
3D highlight scroll bar border color (light)
left button in 'drag' state on vertical scroll bar (relies on drag cancel)
int iVMax
maximum vertical range (0 if no bar)
center using entire text height (ascent + descent for single line)
Definition: draw_text.h:86
WB_GEOM geomVKnob
geometry for the vertical scroll bar 'knob' (empty if not visible)
const char * CHGetTextColor(Display *pDisplay)
returns text color
Definition: conf_help.c:3399
#define WB_POINTER_SCROLLUP
WB_POINTER 'scroll up' event, caused by mouse button 4.
unsigned long long WB_UINT64
Platform abstract unsigned 64-bit integer.
int WBSetRegion(WBGC hGC, Region rgnClip)
Assign clipping region, wrapper for XSetRegion()
int iVBarHeight
calculated height of vertical scroll bar (re-calculate on window size change)
const char * CHGetHighlightBackgroundColor(Display *pDisplay)
returns highlight background color
Definition: conf_help.c:3425
int iVPos
current vertical scroll position (N/A if outside of min/max range)
#define WB_ERROR_PRINT(...)
Preferred method of implementing an 'error level' debug message for all subsystems.
Definition: debug_helper.h:474
int iHMin
minimum horizontal range (0 if no bar)
void WBSetHScrollPos(WB_SCROLLINFO *pSI, int iPos)
Set the scroll range for a horizontal scrollbar in the WB_SCROLLINFO structure.
WB_GEOM geomHKnob
geometry for the horizontal scroll bar 'knob' (empty if not visible)
const char * CHGetDialogBackgroundColor(Display *pDisplay)
returns background color for dialog frame elements
Definition: conf_help.c:3308
2nd parameter (direction) - pgup, pgleft
#define WB_POINTER_CANCEL
WB_POINTER 'cancel' event, cancels an ongoing operation, such as drag/drop (useful for resource clean...
XCharStruct WBFontMaxBounds(WB_FONTC pFont0)
Get a 'maximized' copy of 'max_bounds' (applicable to all font faces in the WB_FONT)
Definition: font_helper.c:592
WB_GEOM geomHBar
geometry for the horizontal scroll bar excluding border (empty if not visible)
middle button in 'drag' state on vertical scroll bar
#define WB_POINTER_MOVE
WB_POINTER 'move' event, for motion notification during drag/drop.
#define WB_POINTER_DRAG
WB_POINTER 'drag' event, window proc MUST return the window ID to auto-support drag/drop.
#define WB_POINTER_BUTTON1
WB_POINTER button bitmask indicating that button 1 is pressed.
int iHScrollHeight
calculated height of horizontal scroll bar (in pixels); 0 if not known
int WBSetHScrollRange(WB_SCROLLINFO *pSI, int iMin, int iMax)
Set the scroll range for a horizontal scrollbar in the WB_SCROLLINFO structure.
int WBCalcVScrollDragPos(WB_SCROLLINFO *pScrollInfo, int iY)
Calculate and assign the correct vertical scroll bar position from mouse coordinates.
void WBDrawDashedRect(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw a 'dashed' rectangle.
void WBSetVScrollPos(WB_SCROLLINFO *pSI, int iPos)
Set the scroll range for a vertical scrollbar in the WB_SCROLLINFO structure.
int iVKnob
calculated relative Y pixel position of vertical scroll 'knob'
static XColor clrScrollFG
foreground scroll bar color
static XColor clrScrollHBG
highlight background scroll bar color
static XColor clrScrollBD
standard scroll bar border color
unsigned int height
char WB_icos(int iVal)
integer 127 * cos(iVal * pi / 512) calculation via lookup table
internal wrapper struct for 'rectangle' definition
int iHMax
maximum horizontal range (0 if no bar)
static XColor clrScrollAFG
active foreground scroll bar color
void WBDrawUpArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw an up arrow in a window within a specified geometry.
int WBTextWidth(WB_FONTC pFont, const char *szText, int cbText)
Obtain the pixel width of specified text for a specified WB_FONT.
Definition: font_helper.c:747
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
void WBFreeGC(WBGC hGC)
Free resources for a WBGC, wrapper for XFreeGC()
void WBInvalidateVScrollGeom(Window wID, WB_SCROLLINFO *pScrollInfo, int bAll, int bUpdate)
Utility function to invalidate the geometry for the vertical scroll bar.
long long WB_INT64
Platform abstract 64-bit integer.
int iHKnob
calculated relative X pixel position of horizontal scroll 'knob'
2nd parameter (direction) - pgdn, pgright
int iHKnobSize
calculated pixel width of horizontal scroll 'knob'
void WBDraw3DBorderRect(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor1, unsigned long lBorderColor2)
Draw a 3D 'border' rectangle.
int iVMin
minimum vertical range (0 if no bar)
unsigned long WBGetGCFGColor(WBGC gc)
returns the currently assigned foreground color for a WBGC
unsigned long WBGetGCBGColor(WBGC gc)
returns the currently assigned background color for a WBGC
WBGC WBCopyDrawableGC(Display *pDisplay, Drawable dw, WBGC hGCOrig)
makes a copy of the specified WBGC for the desired 'Drawable'
static void CheckInitScrollColors(void)
internal utility to check and initialize scroll bar standard colors
#define WB_UNUSED
marks a variable as likely to be 'unused'. warning abatement. Place macro directly after the variable...
int WBFillRectangle(Display *display, Drawable d, WBGC gc, int x, int y, unsigned int width, unsigned int height)
Wrapper for XFillRectangle()
int WBSetBackground(WBGC hGC, unsigned long background)
Assign background color, a wrapper for XSetBackground()
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
An allocated structure containing XFontStruct, XFontInfo, and XftFont [as applicable] for a specified...
Definition: font_helper.h:152
int WBSetVScrollRange(WB_SCROLLINFO *pSI, int iMin, int iMax)
Set the scroll range for a vertical scrollbar in the WB_SCROLLINFO structure.
static XColor clrScrollHFG
highlight foreground scroll bar color
void WBCalcHScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth, int iHScrollHeight, int nListItems, int nPos)
Calculate the parameters for a horizontal scroll bar.
void WBCalcVScrollBar(WB_SCROLLINFO *pScrollInfo, WB_GEOM *pgeomClient, int iVScrollWidth, int iHScrollHeight, int nListItems, int nPos)
Calculate the parameters for a vertical scroll bar.
int iVKnobSize
calculated pixel height of vertical scroll 'knob'
WB_GEOM geomVUp
geometry for the vertical scroll bar 'up' button (empty if not visible)
#define WB_IF_DEBUG_LEVEL(L)
Preferred method of implementing conditional debug 'if block' code.
Definition: debug_helper.h:404
internal wrapper struct for GC with local cache
int WBSetDashes(WBGC hGC, int dash_offset, const char dash_list[], int n)
Assign font to a WBGC, a wrapper for XSetFont()
#define WBPointInGeom(X, Y, G)
Returns logical TRUE if the point (X,Y) is within the borders of the geometry 'G'.
void WBDrawBorderRect(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor)
Draw a 'border' rectangle.
Structure that defines scroll bar info for both horizontal and vertical scroll bars.
void WBDrawBorderElipse(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomBorder, unsigned long lBorderColor)
Draw a 'border' elipse within a bounding geometry.
2nd parameter (direction) - down, right
WB_GEOM geomHLeft
geometry for the horizontal scroll bar 'left' button (empty if not visible)
void WBPaintVScrollBar(WB_SCROLLINFO *pScrollInfo, Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomClient)
Paint the vertical scroll bar within a window based on WB_SCROLLINFO.
const char * CHGetBorderColor(Display *pDisplay)
returns border color
Definition: conf_help.c:3279
left button in 'drag' state on horizontal scroll bar (relies on drag cancel)
right button in 'drag' state on vertical scroll bar
void WBDraw3DBorderTab(Display *pDisplay, Drawable dw, WBGC gc, WB_GEOM *pgeomOutline, int fFocus, unsigned long lFGColor, unsigned long lBGColor, unsigned long lBorderColor1, unsigned long lBorderColor2, unsigned long lHighlightColor, WB_FONTC pFont, WB_FONTC pFontBold, Atom aGraphic, const char *szText)
Draw a 'tab' within a specified 'outline' rectangle.
void WBUpdateScrollBarGeometry(WB_SCROLLINFO *pSI, WB_FONTC pFont, WB_GEOM *pgeomClient, WB_GEOM *pgeomUsable)
Update the scroll bar geometry within the WB_SCROLLINFO structure.
void WBDrawDownArrow(Display *pDisplay, Drawable wID, WBGC gc, WB_GEOM *pgeomRect, unsigned long lColor)
Draw a down arrow in a window within a specified geometry.
WB_FONTC WBGetDefaultFont(void)
Returns a pointer to the default font WB_FONT for the default display. This is a shared resource; do ...