tkUnixScrlbr.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnixScrollbar.c --
  3.  *
  4.  * This file implements the Unix specific portion of the scrollbar
  5.  * widget.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tkUnixScrlbr.c,v 1.3 2000/11/22 01:49:38 ericm Exp $
  13.  */
  14. #include "tkScrollbar.h"
  15. /*
  16.  * Minimum slider length, in pixels (designed to make sure that the slider
  17.  * is always easy to grab with the mouse).
  18.  */
  19. #define MIN_SLIDER_LENGTH 5
  20. /*
  21.  * Declaration of Unix specific scrollbar structure.
  22.  */
  23. typedef struct UnixScrollbar {
  24.     TkScrollbar info; /* Generic scrollbar info. */
  25.     GC troughGC; /* For drawing trough. */
  26.     GC copyGC; /* Used for copying from pixmap onto screen. */
  27. } UnixScrollbar;
  28. /*
  29.  * The class procedure table for the scrollbar widget.  All fields except
  30.  * size are left initialized to NULL, which should happen automatically
  31.  * since the variable is declared at this scope.
  32.  */
  33. Tk_ClassProcs tkpScrollbarProcs = {
  34.     sizeof(Tk_ClassProcs) /* size */
  35. };
  36. /*
  37.  *----------------------------------------------------------------------
  38.  *
  39.  * TkpCreateScrollbar --
  40.  *
  41.  * Allocate a new TkScrollbar structure.
  42.  *
  43.  * Results:
  44.  * Returns a newly allocated TkScrollbar structure.
  45.  *
  46.  * Side effects:
  47.  * Registers an event handler for the widget.
  48.  *
  49.  *----------------------------------------------------------------------
  50.  */
  51. TkScrollbar *
  52. TkpCreateScrollbar(tkwin)
  53.     Tk_Window tkwin;
  54. {
  55.     UnixScrollbar *scrollPtr = (UnixScrollbar *)ckalloc(sizeof(UnixScrollbar));
  56.     scrollPtr->troughGC = None;
  57.     scrollPtr->copyGC = None;
  58.     Tk_CreateEventHandler(tkwin,
  59.     ExposureMask|StructureNotifyMask|FocusChangeMask,
  60.     TkScrollbarEventProc, (ClientData) scrollPtr);
  61.     return (TkScrollbar *) scrollPtr;
  62. }
  63. /*
  64.  *--------------------------------------------------------------
  65.  *
  66.  * TkpDisplayScrollbar --
  67.  *
  68.  * This procedure redraws the contents of a scrollbar window.
  69.  * It is invoked as a do-when-idle handler, so it only runs
  70.  * when there's nothing else for the application to do.
  71.  *
  72.  * Results:
  73.  * None.
  74.  *
  75.  * Side effects:
  76.  * Information appears on the screen.
  77.  *
  78.  *--------------------------------------------------------------
  79.  */
  80. void
  81. TkpDisplayScrollbar(clientData)
  82.     ClientData clientData; /* Information about window. */
  83. {
  84.     register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  85.     register Tk_Window tkwin = scrollPtr->tkwin;
  86.     XPoint points[7];
  87.     Tk_3DBorder border;
  88.     int relief, width, elementBorderWidth;
  89.     Pixmap pixmap;
  90.     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  91. goto done;
  92.     }
  93.     if (scrollPtr->vertical) {
  94. width = Tk_Width(tkwin) - 2*scrollPtr->inset;
  95.     } else {
  96. width = Tk_Height(tkwin) - 2*scrollPtr->inset;
  97.     }
  98.     elementBorderWidth = scrollPtr->elementBorderWidth;
  99.     if (elementBorderWidth < 0) {
  100. elementBorderWidth = scrollPtr->borderWidth;
  101.     }
  102.     /*
  103.      * In order to avoid screen flashes, this procedure redraws
  104.      * the scrollbar in a pixmap, then copies the pixmap to the
  105.      * screen in a single operation.  This means that there's no
  106.      * point in time where the on-sreen image has been cleared.
  107.      */
  108.     pixmap = Tk_GetPixmap(scrollPtr->display, Tk_WindowId(tkwin),
  109.     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  110.     if (scrollPtr->highlightWidth != 0) {
  111. GC gc;
  112. if (scrollPtr->flags & GOT_FOCUS) {
  113.     gc = Tk_GCForColor(scrollPtr->highlightColorPtr, pixmap);
  114. } else {
  115.     gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, pixmap);
  116. }
  117. Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, pixmap);
  118.     }
  119.     Tk_Draw3DRectangle(tkwin, pixmap, scrollPtr->bgBorder,
  120.     scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  121.     Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  122.     Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
  123.     scrollPtr->borderWidth, scrollPtr->relief);
  124.     XFillRectangle(scrollPtr->display, pixmap,
  125.     ((UnixScrollbar*)scrollPtr)->troughGC,
  126.     scrollPtr->inset, scrollPtr->inset,
  127.     (unsigned) (Tk_Width(tkwin) - 2*scrollPtr->inset),
  128.     (unsigned) (Tk_Height(tkwin) - 2*scrollPtr->inset));
  129.     /*
  130.      * Draw the top or left arrow.  The coordinates of the polygon
  131.      * points probably seem odd, but they were carefully chosen with
  132.      * respect to X's rules for filling polygons.  These point choices
  133.      * cause the arrows to just fill the narrow dimension of the
  134.      * scrollbar and be properly centered.
  135.      */
  136.     if (scrollPtr->activeField == TOP_ARROW) {
  137. border = scrollPtr->activeBorder;
  138. relief = scrollPtr->activeField == TOP_ARROW ? scrollPtr->activeRelief
  139. : TK_RELIEF_RAISED;
  140.     } else {
  141. border = scrollPtr->bgBorder;
  142. relief = TK_RELIEF_RAISED;
  143.     }
  144.     if (scrollPtr->vertical) {
  145. points[0].x = scrollPtr->inset - 1;
  146. points[0].y = scrollPtr->arrowLength + scrollPtr->inset - 1;
  147. points[1].x = width + scrollPtr->inset;
  148. points[1].y = points[0].y;
  149. points[2].x = width/2 + scrollPtr->inset;
  150. points[2].y = scrollPtr->inset - 1;
  151. Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3,
  152. elementBorderWidth, relief);
  153.     } else {
  154. points[0].x = scrollPtr->arrowLength + scrollPtr->inset - 1;
  155. points[0].y = scrollPtr->inset - 1;
  156. points[1].x = scrollPtr->inset;
  157. points[1].y = width/2 + scrollPtr->inset;
  158. points[2].x = points[0].x;
  159. points[2].y = width + scrollPtr->inset;
  160. Tk_Fill3DPolygon(tkwin, pixmap, border, points, 3,
  161. elementBorderWidth, relief);
  162.     }
  163.     /*
  164.      * Display the bottom or right arrow.
  165.      */
  166.     if (scrollPtr->activeField == BOTTOM_ARROW) {
  167. border = scrollPtr->activeBorder;
  168. relief = scrollPtr->activeField == BOTTOM_ARROW
  169. ? scrollPtr->activeRelief : TK_RELIEF_RAISED;
  170.     } else {
  171. border = scrollPtr->bgBorder;
  172. relief = TK_RELIEF_RAISED;
  173.     }
  174.     if (scrollPtr->vertical) {
  175. points[0].x = scrollPtr->inset;
  176. points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength
  177. - scrollPtr->inset + 1;
  178. points[1].x = width/2 + scrollPtr->inset;
  179. points[1].y = Tk_Height(tkwin) - scrollPtr->inset;
  180. points[2].x = width + scrollPtr->inset;
  181. points[2].y = points[0].y;
  182. Tk_Fill3DPolygon(tkwin, pixmap, border,
  183. points, 3, elementBorderWidth, relief);
  184.     } else {
  185. points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength
  186. - scrollPtr->inset + 1;
  187. points[0].y = scrollPtr->inset - 1;
  188. points[1].x = points[0].x;
  189. points[1].y = width + scrollPtr->inset;
  190. points[2].x = Tk_Width(tkwin) - scrollPtr->inset;
  191. points[2].y = width/2 + scrollPtr->inset;
  192. Tk_Fill3DPolygon(tkwin, pixmap, border,
  193. points, 3, elementBorderWidth, relief);
  194.     }
  195.     /*
  196.      * Display the slider.
  197.      */
  198.     if (scrollPtr->activeField == SLIDER) {
  199. border = scrollPtr->activeBorder;
  200. relief = scrollPtr->activeField == SLIDER ? scrollPtr->activeRelief
  201. : TK_RELIEF_RAISED;
  202.     } else {
  203. border = scrollPtr->bgBorder;
  204. relief = TK_RELIEF_RAISED;
  205.     }
  206.     if (scrollPtr->vertical) {
  207. Tk_Fill3DRectangle(tkwin, pixmap, border,
  208. scrollPtr->inset, scrollPtr->sliderFirst,
  209. width, scrollPtr->sliderLast - scrollPtr->sliderFirst,
  210. elementBorderWidth, relief);
  211.     } else {
  212. Tk_Fill3DRectangle(tkwin, pixmap, border,
  213. scrollPtr->sliderFirst, scrollPtr->inset,
  214. scrollPtr->sliderLast - scrollPtr->sliderFirst, width,
  215. elementBorderWidth, relief);
  216.     }
  217.     /*
  218.      * Copy the information from the off-screen pixmap onto the screen,
  219.      * then delete the pixmap.
  220.      */
  221.     XCopyArea(scrollPtr->display, pixmap, Tk_WindowId(tkwin),
  222.     ((UnixScrollbar*)scrollPtr)->copyGC, 0, 0,
  223.     (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), 0, 0);
  224.     Tk_FreePixmap(scrollPtr->display, pixmap);
  225.     done:
  226.     scrollPtr->flags &= ~REDRAW_PENDING;
  227. }
  228. /*
  229.  *----------------------------------------------------------------------
  230.  *
  231.  * TkpComputeScrollbarGeometry --
  232.  *
  233.  * After changes in a scrollbar's size or configuration, this
  234.  * procedure recomputes various geometry information used in
  235.  * displaying the scrollbar.
  236.  *
  237.  * Results:
  238.  * None.
  239.  *
  240.  * Side effects:
  241.  * The scrollbar will be displayed differently.
  242.  *
  243.  *----------------------------------------------------------------------
  244.  */
  245. extern void
  246. TkpComputeScrollbarGeometry(scrollPtr)
  247.     register TkScrollbar *scrollPtr; /* Scrollbar whose geometry may
  248.  * have changed. */
  249. {
  250.     int width, fieldLength;
  251.     if (scrollPtr->highlightWidth < 0) {
  252. scrollPtr->highlightWidth = 0;
  253.     }
  254.     scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
  255.     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
  256.     : Tk_Height(scrollPtr->tkwin);
  257.     scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
  258.     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
  259.     : Tk_Width(scrollPtr->tkwin))
  260.     - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  261.     if (fieldLength < 0) {
  262. fieldLength = 0;
  263.     }
  264.     scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
  265.     scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
  266.     /*
  267.      * Adjust the slider so that some piece of it is always
  268.      * displayed in the scrollbar and so that it has at least
  269.      * a minimal width (so it can be grabbed with the mouse).
  270.      */
  271.     if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
  272. scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
  273.     }
  274.     if (scrollPtr->sliderFirst < 0) {
  275. scrollPtr->sliderFirst = 0;
  276.     }
  277.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  278.     + MIN_SLIDER_LENGTH)) {
  279. scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
  280.     }
  281.     if (scrollPtr->sliderLast > fieldLength) {
  282. scrollPtr->sliderLast = fieldLength;
  283.     }
  284.     scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
  285.     scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
  286.     /*
  287.      * Register the desired geometry for the window (leave enough space
  288.      * for the two arrows plus a minimum-size slider, plus border around
  289.      * the whole window, if any).  Then arrange for the window to be
  290.      * redisplayed.
  291.      */
  292.     if (scrollPtr->vertical) {
  293. Tk_GeometryRequest(scrollPtr->tkwin,
  294. scrollPtr->width + 2*scrollPtr->inset,
  295. 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  296. + scrollPtr->inset));
  297.     } else {
  298. Tk_GeometryRequest(scrollPtr->tkwin,
  299. 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  300. + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset);
  301.     }
  302.     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
  303. }
  304. /*
  305.  *----------------------------------------------------------------------
  306.  *
  307.  * TkpDestroyScrollbar --
  308.  *
  309.  * Free data structures associated with the scrollbar control.
  310.  *
  311.  * Results:
  312.  * None.
  313.  *
  314.  * Side effects:
  315.  * Frees the GCs associated with the scrollbar.
  316.  *
  317.  *----------------------------------------------------------------------
  318.  */
  319. void
  320. TkpDestroyScrollbar(scrollPtr)
  321.     TkScrollbar *scrollPtr;
  322. {
  323.     UnixScrollbar *unixScrollPtr = (UnixScrollbar *)scrollPtr;
  324.     if (unixScrollPtr->troughGC != None) {
  325. Tk_FreeGC(scrollPtr->display, unixScrollPtr->troughGC);
  326.     }
  327.     if (unixScrollPtr->copyGC != None) {
  328. Tk_FreeGC(scrollPtr->display, unixScrollPtr->copyGC);
  329.     }
  330. }
  331. /*
  332.  *----------------------------------------------------------------------
  333.  *
  334.  * TkpConfigureScrollbar --
  335.  *
  336.  * This procedure is called after the generic code has finished
  337.  * processing configuration options, in order to configure
  338.  * platform specific options.
  339.  *
  340.  * Results:
  341.  * None.
  342.  *
  343.  * Side effects:
  344.  * Configuration info may get changed.
  345.  *
  346.  *----------------------------------------------------------------------
  347.  */
  348. void
  349. TkpConfigureScrollbar(scrollPtr)
  350.     register TkScrollbar *scrollPtr; /* Information about widget;  may or
  351.  * may not already have values for
  352.  * some fields. */
  353. {
  354.     XGCValues gcValues;
  355.     GC new;
  356.     UnixScrollbar *unixScrollPtr = (UnixScrollbar *) scrollPtr;
  357.     Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder);
  358.     gcValues.foreground = scrollPtr->troughColorPtr->pixel;
  359.     new = Tk_GetGC(scrollPtr->tkwin, GCForeground, &gcValues);
  360.     if (unixScrollPtr->troughGC != None) {
  361. Tk_FreeGC(scrollPtr->display, unixScrollPtr->troughGC);
  362.     }
  363.     unixScrollPtr->troughGC = new;
  364.     if (unixScrollPtr->copyGC == None) {
  365. gcValues.graphics_exposures = False;
  366. unixScrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures,
  367.     &gcValues);
  368.     }
  369. }
  370. /*
  371.  *--------------------------------------------------------------
  372.  *
  373.  * TkpScrollbarPosition --
  374.  *
  375.  * Determine the scrollbar element corresponding to a
  376.  * given position.
  377.  *
  378.  * Results:
  379.  * One of TOP_ARROW, TOP_GAP, etc., indicating which element
  380.  * of the scrollbar covers the position given by (x, y).  If
  381.  * (x,y) is outside the scrollbar entirely, then OUTSIDE is
  382.  * returned.
  383.  *
  384.  * Side effects:
  385.  * None.
  386.  *
  387.  *--------------------------------------------------------------
  388.  */
  389. int
  390. TkpScrollbarPosition(scrollPtr, x, y)
  391.     register TkScrollbar *scrollPtr; /* Scrollbar widget record. */
  392.     int x, y; /* Coordinates within scrollPtr's
  393.  * window. */
  394. {
  395.     int length, width, tmp;
  396.     if (scrollPtr->vertical) {
  397. length = Tk_Height(scrollPtr->tkwin);
  398. width = Tk_Width(scrollPtr->tkwin);
  399.     } else {
  400. tmp = x;
  401. x = y;
  402. y = tmp;
  403. length = Tk_Width(scrollPtr->tkwin);
  404. width = Tk_Height(scrollPtr->tkwin);
  405.     }
  406.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  407.     || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  408. return OUTSIDE;
  409.     }
  410.     /*
  411.      * All of the calculations in this procedure mirror those in
  412.      * TkpDisplayScrollbar.  Be sure to keep the two consistent.
  413.      */
  414.     if (y < (scrollPtr->inset + scrollPtr->arrowLength)) {
  415. return TOP_ARROW;
  416.     }
  417.     if (y < scrollPtr->sliderFirst) {
  418. return TOP_GAP;
  419.     }
  420.     if (y < scrollPtr->sliderLast) {
  421. return SLIDER;
  422.     }
  423.     if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
  424. return BOTTOM_ARROW;
  425.     }
  426.     return BOTTOM_GAP;
  427. }