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