OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tk8.6.12 / unix / tkUnixMenubu.c
1 /*
2  * tkUnixMenubu.c --
3  *
4  *      This file implements the Unix specific portion of the menubutton
5  *      widget.
6  *
7  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution of
10  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  */
12
13 #include "tkInt.h"
14 #include "tkMenubutton.h"
15
16 \f
17 /*
18  *----------------------------------------------------------------------
19  *
20  * TkpCreateMenuButton --
21  *
22  *      Allocate a new TkMenuButton structure.
23  *
24  * Results:
25  *      Returns a newly allocated TkMenuButton structure.
26  *
27  * Side effects:
28  *      None
29  *
30  *----------------------------------------------------------------------
31  */
32
33 TkMenuButton *
34 TkpCreateMenuButton(
35     TCL_UNUSED(Tk_Window))
36 {
37     return (TkMenuButton *)ckalloc(sizeof(TkMenuButton));
38 }
39 \f
40 /*
41  *----------------------------------------------------------------------
42  *
43  * TkpDisplayMenuButton --
44  *
45  *      This function is invoked to display a menubutton widget.
46  *
47  * Results:
48  *      None.
49  *
50  * Side effects:
51  *      Commands are output to X to display the menubutton in its current
52  *      mode.
53  *
54  *----------------------------------------------------------------------
55  */
56
57 void
58 TkpDisplayMenuButton(
59     ClientData clientData)      /* Information about widget. */
60 {
61     TkMenuButton *mbPtr = (TkMenuButton *)clientData;
62     GC gc;
63     Tk_3DBorder border;
64     Pixmap pixmap;
65     int x = 0;                  /* Initialization needed only to stop compiler
66                                  * warning. */
67     int y = 0;
68     Tk_Window tkwin = mbPtr->tkwin;
69     int fullWidth, fullHeight;
70     int textXOffset, textYOffset;
71     int imageWidth, imageHeight;
72     int imageXOffset, imageYOffset;
73     int width = 0, height = 0;
74                                 /* Image information that will be used to
75                                  * restrict disabled pixmap as well */
76     int haveImage = 0, haveText = 0;
77
78     mbPtr->flags &= ~REDRAW_PENDING;
79     if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
80         return;
81     }
82
83     if ((mbPtr->state == STATE_DISABLED) && (mbPtr->disabledFg != NULL)) {
84         gc = mbPtr->disabledGC;
85         border = mbPtr->normalBorder;
86     } else if ((mbPtr->state == STATE_ACTIVE)
87                && !Tk_StrictMotif(mbPtr->tkwin)) {
88         gc = mbPtr->activeTextGC;
89         border = mbPtr->activeBorder;
90     } else {
91         gc = mbPtr->normalTextGC;
92         border = mbPtr->normalBorder;
93     }
94
95     if (mbPtr->image != NULL) {
96         Tk_SizeOfImage(mbPtr->image, &width, &height);
97         haveImage = 1;
98     } else if (mbPtr->bitmap != None) {
99         Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
100         haveImage = 1;
101     }
102     imageWidth  = width;
103     imageHeight = height;
104
105     haveText = (mbPtr->textWidth != 0 && mbPtr->textHeight != 0);
106
107     /*
108      * In order to avoid screen flashes, this function redraws the menu button
109      * in a pixmap, then copies the pixmap to the screen in a single
110      * operation. This means that there's no point in time where the on-sreen
111      * image has been cleared.
112      */
113
114     pixmap = Tk_GetPixmap(mbPtr->display, Tk_WindowId(tkwin),
115             Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
116     Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
117             Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
118
119     imageXOffset = 0;
120     imageYOffset = 0;
121     textXOffset = 0;
122     textYOffset = 0;
123     fullWidth = 0;
124     fullHeight = 0;
125
126     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {
127         switch ((enum compound) mbPtr->compound) {
128         case COMPOUND_TOP:
129         case COMPOUND_BOTTOM:
130             /*
131              * Image is above or below text.
132              */
133
134             if (mbPtr->compound == COMPOUND_TOP) {
135                 textYOffset = height + mbPtr->padY;
136             } else {
137                 imageYOffset = mbPtr->textHeight + mbPtr->padY;
138             }
139             fullHeight = height + mbPtr->textHeight + mbPtr->padY;
140             fullWidth = (width > mbPtr->textWidth ? width : mbPtr->textWidth);
141             textXOffset = (fullWidth - mbPtr->textWidth)/2;
142             imageXOffset = (fullWidth - width)/2;
143             break;
144         case COMPOUND_LEFT:
145         case COMPOUND_RIGHT:
146             /*
147              * Image is left or right of text.
148              */
149
150             if (mbPtr->compound == COMPOUND_LEFT) {
151                 textXOffset = width + mbPtr->padX;
152             } else {
153                 imageXOffset = mbPtr->textWidth + mbPtr->padX;
154             }
155             fullWidth = mbPtr->textWidth + mbPtr->padX + width;
156             fullHeight = (height > mbPtr->textHeight ? height :
157                     mbPtr->textHeight);
158             textYOffset = (fullHeight - mbPtr->textHeight)/2;
159             imageYOffset = (fullHeight - height)/2;
160             break;
161         case COMPOUND_CENTER:
162             /*
163              * Image and text are superimposed.
164              */
165
166             fullWidth = (width > mbPtr->textWidth ? width : mbPtr->textWidth);
167             fullHeight = (height > mbPtr->textHeight ? height :
168                     mbPtr->textHeight);
169             textXOffset = (fullWidth - mbPtr->textWidth)/2;
170             imageXOffset = (fullWidth - width)/2;
171             textYOffset = (fullHeight - mbPtr->textHeight)/2;
172             imageYOffset = (fullHeight - height)/2;
173             break;
174         case COMPOUND_NONE:
175             break;
176         }
177
178         TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
179                 mbPtr->indicatorWidth + fullWidth, fullHeight, &x, &y);
180
181         imageXOffset += x;
182         imageYOffset += y;
183         if (mbPtr->image != NULL) {
184             Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
185                     imageXOffset, imageYOffset);
186         } else if (mbPtr->bitmap != None) {
187             XSetClipOrigin(mbPtr->display, gc, imageXOffset, imageYOffset);
188             XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
189                     gc, 0, 0, (unsigned) width, (unsigned) height,
190                     imageXOffset, imageYOffset, 1);
191             XSetClipOrigin(mbPtr->display, gc, 0, 0);
192         }
193
194         Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout,
195                 x + textXOffset, y + textYOffset, 0, -1);
196         Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout,
197                 x + textXOffset, y + textYOffset, mbPtr->underline);
198     } else if (haveImage) {
199         TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
200                 width + mbPtr->indicatorWidth, height, &x, &y);
201         imageXOffset += x;
202         imageYOffset += y;
203         if (mbPtr->image != NULL) {
204             Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
205                     imageXOffset, imageYOffset);
206         } else if (mbPtr->bitmap != None) {
207             XSetClipOrigin(mbPtr->display, gc, x, y);
208             XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
209                     gc, 0, 0, (unsigned) width, (unsigned) height,
210                     x, y, 1);
211             XSetClipOrigin(mbPtr->display, gc, 0, 0);
212         }
213     } else {
214         TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY,
215                 mbPtr->textWidth + mbPtr->indicatorWidth,
216                 mbPtr->textHeight, &x, &y);
217         Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout,
218                 x + textXOffset, y + textYOffset, 0, -1);
219         Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc,
220                 mbPtr->textLayout, x + textXOffset, y + textYOffset,
221                 mbPtr->underline);
222     }
223
224     /*
225      * If the menu button is disabled with a stipple rather than a special
226      * foreground color, generate the stippled effect.
227      */
228
229     if ((mbPtr->state == STATE_DISABLED)
230             && ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) {
231         /*
232          * Stipple the whole button if no disabledFg was specified, otherwise
233          * restrict stippling only to displayed image
234          */
235
236         if (mbPtr->disabledFg == NULL) {
237             XFillRectangle(mbPtr->display, pixmap, mbPtr->stippleGC,
238                     mbPtr->inset, mbPtr->inset,
239                     (unsigned) (Tk_Width(tkwin) - 2*mbPtr->inset),
240                     (unsigned) (Tk_Height(tkwin) - 2*mbPtr->inset));
241         } else {
242             XFillRectangle(mbPtr->display, pixmap, mbPtr->stippleGC,
243                     imageXOffset, imageYOffset,
244                     (unsigned) imageWidth, (unsigned) imageHeight);
245         }
246     }
247
248     /*
249      * Draw the cascade indicator for the menu button on the right side of the
250      * window, if desired.
251      */
252
253     if (mbPtr->indicatorOn) {
254         int borderWidth;
255
256         borderWidth = (mbPtr->indicatorHeight+1)/3;
257         if (borderWidth < 1) {
258             borderWidth = 1;
259         }
260         /*y += mbPtr->textHeight / 2;*/
261         Tk_Fill3DRectangle(tkwin, pixmap, border,
262                 Tk_Width(tkwin) - mbPtr->inset - mbPtr->indicatorWidth
263                 + mbPtr->indicatorHeight,
264                 ((int) (Tk_Height(tkwin) - mbPtr->indicatorHeight))/2,
265                 mbPtr->indicatorWidth - 2*mbPtr->indicatorHeight,
266                 mbPtr->indicatorHeight, borderWidth, TK_RELIEF_RAISED);
267     }
268
269     /*
270      * Draw the border and traversal highlight last. This way, if the menu
271      * button's contents overflow onto the border they'll be covered up by the
272      * border.
273      */
274
275     if (mbPtr->relief != TK_RELIEF_FLAT) {
276         Tk_Draw3DRectangle(tkwin, pixmap, border,
277                 mbPtr->highlightWidth, mbPtr->highlightWidth,
278                 Tk_Width(tkwin) - 2*mbPtr->highlightWidth,
279                 Tk_Height(tkwin) - 2*mbPtr->highlightWidth,
280                 mbPtr->borderWidth, mbPtr->relief);
281     }
282     if (mbPtr->highlightWidth != 0) {
283         if (mbPtr->flags & GOT_FOCUS) {
284             gc = Tk_GCForColor(mbPtr->highlightColorPtr, pixmap);
285         } else {
286             gc = Tk_GCForColor(mbPtr->highlightBgColorPtr, pixmap);
287         }
288         Tk_DrawFocusHighlight(tkwin, gc, mbPtr->highlightWidth, pixmap);
289     }
290
291     /*
292      * Copy the information from the off-screen pixmap onto the screen, then
293      * delete the pixmap.
294      */
295
296     XCopyArea(mbPtr->display, pixmap, Tk_WindowId(tkwin),
297             mbPtr->normalTextGC, 0, 0, (unsigned) Tk_Width(tkwin),
298             (unsigned) Tk_Height(tkwin), 0, 0);
299     Tk_FreePixmap(mbPtr->display, pixmap);
300 }
301 \f
302 /*
303  *----------------------------------------------------------------------
304  *
305  * TkpDestroyMenuButton --
306  *
307  *      Free data structures associated with the menubutton control.
308  *
309  * Results:
310  *      None.
311  *
312  * Side effects:
313  *      Restores the default control state.
314  *
315  *----------------------------------------------------------------------
316  */
317
318 void
319 TkpDestroyMenuButton(
320     TkMenuButton *mbPtr)
321 {
322 }
323 \f
324 /*
325  *----------------------------------------------------------------------
326  *
327  * TkpComputeMenuButtonGeometry --
328  *
329  *      After changes in a menu button's text or bitmap, this function
330  *      recomputes the menu button's geometry and passes this information
331  *      along to the geometry manager for the window.
332  *
333  * Results:
334  *      None.
335  *
336  * Side effects:
337  *      The menu button's window may change size.
338  *
339  *----------------------------------------------------------------------
340  */
341
342 void
343 TkpComputeMenuButtonGeometry(
344     TkMenuButton *mbPtr)        /* Widget record for menu button. */
345 {
346     int width, height, mm, pixels;
347     int  avgWidth, txtWidth, txtHeight;
348     int haveImage = 0, haveText = 0;
349     Tk_FontMetrics fm;
350
351     mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
352
353     width = 0;
354     height = 0;
355     txtWidth = 0;
356     txtHeight = 0;
357     avgWidth = 0;
358
359     if (mbPtr->image != NULL) {
360         Tk_SizeOfImage(mbPtr->image, &width, &height);
361         haveImage = 1;
362     } else if (mbPtr->bitmap != None) {
363         Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
364         haveImage = 1;
365     }
366
367     if (haveImage == 0 || mbPtr->compound != COMPOUND_NONE) {
368         Tk_FreeTextLayout(mbPtr->textLayout);
369
370         mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
371                 -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
372                 &mbPtr->textHeight);
373         txtWidth = mbPtr->textWidth;
374         txtHeight = mbPtr->textHeight;
375         avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
376         Tk_GetFontMetrics(mbPtr->tkfont, &fm);
377         haveText = (txtWidth != 0 && txtHeight != 0);
378     }
379
380     /*
381      * If the menubutton is compound (ie, it shows both an image and text),
382      * the new geometry is a combination of the image and text geometry. We
383      * only honor the compound bit if the menubutton has both text and an
384      * image, because otherwise it is not really a compound menubutton.
385      */
386
387     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {
388         switch ((enum compound) mbPtr->compound) {
389         case COMPOUND_TOP:
390         case COMPOUND_BOTTOM:
391             /*
392              * Image is above or below text.
393              */
394
395             height += txtHeight + mbPtr->padY;
396             width = (width > txtWidth ? width : txtWidth);
397             break;
398         case COMPOUND_LEFT:
399         case COMPOUND_RIGHT:
400             /*
401              * Image is left or right of text.
402              */
403
404             width += txtWidth + mbPtr->padX;
405             height = (height > txtHeight ? height : txtHeight);
406             break;
407         case COMPOUND_CENTER:
408             /*
409              * Image and text are superimposed.
410              */
411
412             width = (width > txtWidth ? width : txtWidth);
413             height = (height > txtHeight ? height : txtHeight);
414             break;
415         case COMPOUND_NONE:
416             break;
417         }
418         if (mbPtr->width > 0) {
419             width = mbPtr->width;
420         }
421         if (mbPtr->height > 0) {
422             height = mbPtr->height;
423         }
424         width += 2*mbPtr->padX;
425         height += 2*mbPtr->padY;
426     } else {
427         if (haveImage) {
428             if (mbPtr->width > 0) {
429                 width = mbPtr->width;
430             }
431             if (mbPtr->height > 0) {
432                 height = mbPtr->height;
433             }
434         } else {
435             width = txtWidth;
436             height = txtHeight;
437             if (mbPtr->width > 0) {
438                 width = mbPtr->width * avgWidth;
439             }
440             if (mbPtr->height > 0) {
441                 height = mbPtr->height * fm.linespace;
442             }
443         }
444     }
445
446     if (! haveImage) {
447         width += 2*mbPtr->padX;
448         height += 2*mbPtr->padY;
449     }
450
451     if (mbPtr->indicatorOn) {
452         mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
453         pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
454         mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
455         mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
456                 + 2*mbPtr->indicatorHeight;
457         width += mbPtr->indicatorWidth;
458     } else {
459         mbPtr->indicatorHeight = 0;
460         mbPtr->indicatorWidth = 0;
461     }
462
463     Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),
464             (int) (height + 2*mbPtr->inset));
465     Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
466 }
467 \f
468 /*
469  * Local Variables:
470  * mode: c
471  * c-basic-offset: 4
472  * fill-column: 78
473  * End:
474  */