/[dtapublic]/sf_code/esrgpcpj/shared/tk_base/tkmenudraw.c
ViewVC logotype

Annotation of /sf_code/esrgpcpj/shared/tk_base/tkmenudraw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations) (download)
Sat Oct 8 06:43:03 2016 UTC (7 years, 5 months ago) by dashley
File MIME type: text/plain
File size: 31213 byte(s)
Initial commit.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkmenudraw.c,v 1.1.1.1 2001/06/13 05:06:08 dtashley Exp $ */
2    
3     /*
4     * tkMenuDraw.c --
5     *
6     * This module implements the platform-independent drawing and
7     * geometry calculations of menu widgets.
8     *
9     * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
10     *
11     * See the file "license.terms" for information on usage and redistribution
12     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13     *
14     * RCS: @(#) $Id: tkmenudraw.c,v 1.1.1.1 2001/06/13 05:06:08 dtashley Exp $
15     */
16    
17     #include "tkMenu.h"
18    
19     /*
20     * Forward declarations for procedures defined later in this file:
21     */
22    
23     static void AdjustMenuCoords _ANSI_ARGS_ ((TkMenu *menuPtr,
24     TkMenuEntry *mePtr, int *xPtr, int *yPtr,
25     char *string));
26     static void ComputeMenuGeometry _ANSI_ARGS_((
27     ClientData clientData));
28     static void DisplayMenu _ANSI_ARGS_((ClientData clientData));
29    
30     /*
31     *----------------------------------------------------------------------
32     *
33     * TkMenuInitializeDrawingFields --
34     *
35     * Fills in drawing fields of a new menu. Called when new menu is
36     * created by MenuCmd.
37     *
38     * Results:
39     * None.
40     *
41     * Side effects:
42     * menuPtr fields are initialized.
43     *
44     *----------------------------------------------------------------------
45     */
46    
47     void
48     TkMenuInitializeDrawingFields(menuPtr)
49     TkMenu *menuPtr; /* The menu we are initializing. */
50     {
51     menuPtr->textGC = None;
52     menuPtr->gray = None;
53     menuPtr->disabledGC = None;
54     menuPtr->activeGC = None;
55     menuPtr->indicatorGC = None;
56     menuPtr->disabledImageGC = None;
57     menuPtr->totalWidth = menuPtr->totalHeight = 0;
58     }
59    
60     /*
61     *----------------------------------------------------------------------
62     *
63     * TkMenuInitializeEntryDrawingFields --
64     *
65     * Fills in drawing fields of a new menu entry. Called when an
66     * entry is created.
67     *
68     * Results:
69     * None.
70     *
71     * Side effects:
72     * None.
73     *
74     *----------------------------------------------------------------------
75     */
76    
77     void
78     TkMenuInitializeEntryDrawingFields(mePtr)
79     TkMenuEntry *mePtr; /* The menu we are initializing. */
80     {
81     mePtr->width = 0;
82     mePtr->height = 0;
83     mePtr->x = 0;
84     mePtr->y = 0;
85     mePtr->indicatorSpace = 0;
86     mePtr->labelWidth = 0;
87     mePtr->textGC = None;
88     mePtr->activeGC = None;
89     mePtr->disabledGC = None;
90     mePtr->indicatorGC = None;
91     }
92    
93     /*
94     *----------------------------------------------------------------------
95     *
96     * TkMenuFreeDrawOptions --
97     *
98     * Frees up any structures allocated for the drawing of a menu.
99     * Called when menu is deleted.
100     *
101     * Results:
102     * None.
103     *
104     * Side effects:
105     * Storage is released.
106     *
107     *----------------------------------------------------------------------
108     */
109    
110     void
111     TkMenuFreeDrawOptions(menuPtr)
112     TkMenu *menuPtr;
113     {
114     if (menuPtr->textGC != None) {
115     Tk_FreeGC(menuPtr->display, menuPtr->textGC);
116     }
117     if (menuPtr->disabledImageGC != None) {
118     Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC);
119     }
120     if (menuPtr->gray != None) {
121     Tk_FreeBitmap(menuPtr->display, menuPtr->gray);
122     }
123     if (menuPtr->disabledGC != None) {
124     Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
125     }
126     if (menuPtr->activeGC != None) {
127     Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
128     }
129     if (menuPtr->indicatorGC != None) {
130     Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
131     }
132     }
133    
134     /*
135     *----------------------------------------------------------------------
136     *
137     * TkMenuEntryFreeDrawOptions --
138     *
139     * Frees up drawing structures for a menu entry. Called when
140     * menu entry is freed.
141     *
142     * RESULTS:
143     * None.
144     *
145     * Side effects:
146     * Storage is freed.
147     *
148     *----------------------------------------------------------------------
149     */
150    
151     void
152     TkMenuEntryFreeDrawOptions(mePtr)
153     TkMenuEntry *mePtr;
154     {
155     if (mePtr->textGC != None) {
156     Tk_FreeGC(mePtr->menuPtr->display, mePtr->textGC);
157     }
158     if (mePtr->disabledGC != None) {
159     Tk_FreeGC(mePtr->menuPtr->display, mePtr->disabledGC);
160     }
161     if (mePtr->activeGC != None) {
162     Tk_FreeGC(mePtr->menuPtr->display, mePtr->activeGC);
163     }
164     if (mePtr->indicatorGC != None) {
165     Tk_FreeGC(mePtr->menuPtr->display, mePtr->indicatorGC);
166     }
167     }
168    
169     /*
170     *----------------------------------------------------------------------
171     *
172     * TkMenuConfigureDrawOptions --
173     *
174     * Sets the menu's drawing attributes in preparation for drawing
175     * the menu.
176     *
177     * RESULTS:
178     * None.
179     *
180     * Side effects:
181     * Storage is allocated.
182     *
183     *----------------------------------------------------------------------
184     */
185    
186     void
187     TkMenuConfigureDrawOptions(menuPtr)
188     TkMenu *menuPtr; /* The menu we are configuring. */
189     {
190     XGCValues gcValues;
191     GC newGC;
192     unsigned long mask;
193     Tk_3DBorder border, activeBorder;
194     Tk_Font tkfont;
195     XColor *fg, *activeFg, *indicatorFg;
196    
197     /*
198     * A few options need special processing, such as setting the
199     * background from a 3-D border, or filling in complicated
200     * defaults that couldn't be specified to Tk_ConfigureWidget.
201     */
202    
203     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
204     Tk_SetBackgroundFromBorder(menuPtr->tkwin, border);
205    
206     tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
207     gcValues.font = Tk_FontId(tkfont);
208     fg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->fgPtr);
209     gcValues.foreground = fg->pixel;
210     gcValues.background = Tk_3DBorderColor(border)->pixel;
211     newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
212     &gcValues);
213     if (menuPtr->textGC != None) {
214     Tk_FreeGC(menuPtr->display, menuPtr->textGC);
215     }
216     menuPtr->textGC = newGC;
217    
218     gcValues.font = Tk_FontId(tkfont);
219     gcValues.background = Tk_3DBorderColor(border)->pixel;
220     if (menuPtr->disabledFgPtr != NULL) {
221     XColor *disabledFg;
222    
223     disabledFg = Tk_GetColorFromObj(menuPtr->tkwin,
224     menuPtr->disabledFgPtr);
225     gcValues.foreground = disabledFg->pixel;
226     mask = GCForeground|GCBackground|GCFont;
227     } else {
228     gcValues.foreground = gcValues.background;
229     mask = GCForeground;
230     if (menuPtr->gray == None) {
231     menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin,
232     "gray50");
233     }
234     if (menuPtr->gray != None) {
235     gcValues.fill_style = FillStippled;
236     gcValues.stipple = menuPtr->gray;
237     mask = GCForeground|GCFillStyle|GCStipple;
238     }
239     }
240     newGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
241     if (menuPtr->disabledGC != None) {
242     Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
243     }
244     menuPtr->disabledGC = newGC;
245    
246     gcValues.foreground = Tk_3DBorderColor(border)->pixel;
247     if (menuPtr->gray == None) {
248     menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin,
249     "gray50");
250     }
251     if (menuPtr->gray != None) {
252     gcValues.fill_style = FillStippled;
253     gcValues.stipple = menuPtr->gray;
254     newGC = Tk_GetGC(menuPtr->tkwin,
255     GCForeground|GCFillStyle|GCStipple, &gcValues);
256     }
257     if (menuPtr->disabledImageGC != None) {
258     Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC);
259     }
260     menuPtr->disabledImageGC = newGC;
261    
262     gcValues.font = Tk_FontId(tkfont);
263     activeFg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->activeFgPtr);
264     gcValues.foreground = activeFg->pixel;
265     activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
266     menuPtr->activeBorderPtr);
267     gcValues.background = Tk_3DBorderColor(activeBorder)->pixel;
268     newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
269     &gcValues);
270     if (menuPtr->activeGC != None) {
271     Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
272     }
273     menuPtr->activeGC = newGC;
274    
275     indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin,
276     menuPtr->indicatorFgPtr);
277     gcValues.foreground = indicatorFg->pixel;
278     gcValues.background = Tk_3DBorderColor(border)->pixel;
279     newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
280     &gcValues);
281     if (menuPtr->indicatorGC != None) {
282     Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
283     }
284     menuPtr->indicatorGC = newGC;
285     }
286    
287     /*
288     *----------------------------------------------------------------------
289     *
290     * TkMenuConfigureEntryDrawOptions --
291     *
292     * Calculates any entry-specific draw options for the given menu
293     * entry.
294     *
295     * Results:
296     * Returns a standard Tcl error.
297     *
298     * Side effects:
299     * Storage may be allocated.
300     *
301     *----------------------------------------------------------------------
302     */
303    
304     int
305     TkMenuConfigureEntryDrawOptions(mePtr, index)
306     TkMenuEntry *mePtr;
307     int index;
308     {
309    
310     XGCValues gcValues;
311     GC newGC, newActiveGC, newDisabledGC, newIndicatorGC;
312     unsigned long mask;
313     Tk_Font tkfont;
314     TkMenu *menuPtr = mePtr->menuPtr;
315    
316     tkfont = Tk_GetFontFromObj(menuPtr->tkwin,
317     (mePtr->fontPtr != NULL) ? mePtr->fontPtr : menuPtr->fontPtr);
318    
319     if (mePtr->state == ENTRY_ACTIVE) {
320     if (index != menuPtr->active) {
321     TkActivateMenuEntry(menuPtr, index);
322     }
323     } else {
324     if (index == menuPtr->active) {
325     TkActivateMenuEntry(menuPtr, -1);
326     }
327     }
328    
329     if ((mePtr->fontPtr != NULL)
330     || (mePtr->borderPtr != NULL)
331     || (mePtr->fgPtr != NULL)
332     || (mePtr->activeBorderPtr != NULL)
333     || (mePtr->activeFgPtr != NULL)
334     || (mePtr->indicatorFgPtr != NULL)) {
335     XColor *fg, *indicatorFg, *activeFg;
336     Tk_3DBorder border, activeBorder;
337    
338     fg = Tk_GetColorFromObj(menuPtr->tkwin, (mePtr->fgPtr != NULL)
339     ? mePtr->fgPtr : menuPtr->fgPtr);
340     gcValues.foreground = fg->pixel;
341     border = Tk_Get3DBorderFromObj(menuPtr->tkwin,
342     (mePtr->borderPtr != NULL) ? mePtr->borderPtr
343     : menuPtr->borderPtr);
344     gcValues.background = Tk_3DBorderColor(border)->pixel;
345    
346     gcValues.font = Tk_FontId(tkfont);
347    
348     /*
349     * Note: disable GraphicsExpose events; we know there won't be
350     * obscured areas when copying from an off-screen pixmap to the
351     * screen and this gets rid of unnecessary events.
352     */
353    
354     gcValues.graphics_exposures = False;
355     newGC = Tk_GetGC(menuPtr->tkwin,
356     GCForeground|GCBackground|GCFont|GCGraphicsExposures,
357     &gcValues);
358    
359     indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin,
360     (mePtr->indicatorFgPtr != NULL) ? mePtr->indicatorFgPtr
361     : menuPtr->indicatorFgPtr);
362     gcValues.foreground = indicatorFg->pixel;
363     newIndicatorGC = Tk_GetGC(menuPtr->tkwin,
364     GCForeground|GCBackground|GCGraphicsExposures,
365     &gcValues);
366    
367     if ((menuPtr->disabledFgPtr != NULL) || (mePtr->image != NULL)) {
368     XColor *disabledFg;
369    
370     disabledFg = Tk_GetColorFromObj(menuPtr->tkwin,
371     menuPtr->disabledFgPtr);
372     gcValues.foreground = disabledFg->pixel;
373     mask = GCForeground|GCBackground|GCFont|GCGraphicsExposures;
374     } else {
375     gcValues.foreground = gcValues.background;
376     gcValues.fill_style = FillStippled;
377     gcValues.stipple = menuPtr->gray;
378     mask = GCForeground|GCFillStyle|GCStipple;
379     }
380     newDisabledGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
381    
382     activeFg = Tk_GetColorFromObj(menuPtr->tkwin,
383     (mePtr->activeFgPtr != NULL) ? mePtr->activeFgPtr
384     : menuPtr->activeFgPtr);
385     activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
386     (mePtr->activeBorderPtr != NULL) ? mePtr->activeBorderPtr
387     : menuPtr->activeBorderPtr);
388    
389     gcValues.foreground = activeFg->pixel;
390     gcValues.background = Tk_3DBorderColor(activeBorder)->pixel;
391     newActiveGC = Tk_GetGC(menuPtr->tkwin,
392     GCForeground|GCBackground|GCFont|GCGraphicsExposures,
393     &gcValues);
394     } else {
395     newGC = None;
396     newActiveGC = None;
397     newDisabledGC = None;
398     newIndicatorGC = None;
399     }
400     if (mePtr->textGC != None) {
401     Tk_FreeGC(menuPtr->display, mePtr->textGC);
402     }
403     mePtr->textGC = newGC;
404     if (mePtr->activeGC != None) {
405     Tk_FreeGC(menuPtr->display, mePtr->activeGC);
406     }
407     mePtr->activeGC = newActiveGC;
408     if (mePtr->disabledGC != None) {
409     Tk_FreeGC(menuPtr->display, mePtr->disabledGC);
410     }
411     mePtr->disabledGC = newDisabledGC;
412     if (mePtr->indicatorGC != None) {
413     Tk_FreeGC(menuPtr->display, mePtr->indicatorGC);
414     }
415     mePtr->indicatorGC = newIndicatorGC;
416     return TCL_OK;
417     }
418    
419     /*
420     *----------------------------------------------------------------------
421     *
422     * TkEventuallyRecomputeMenu --
423     *
424     * Tells Tcl to redo the geometry because this menu has changed.
425     *
426     * Results:
427     * None.
428     *
429     * Side effects:
430     * Menu geometry is recomputed at idle time, and the menu will be
431     * redisplayed.
432     *
433     *----------------------------------------------------------------------
434     */
435    
436     void
437     TkEventuallyRecomputeMenu(menuPtr)
438     TkMenu *menuPtr;
439     {
440     if (!(menuPtr->menuFlags & RESIZE_PENDING)) {
441     menuPtr->menuFlags |= RESIZE_PENDING;
442     Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
443     }
444     }
445    
446     /*
447     *----------------------------------------------------------------------
448     *
449     * TkRecomputeMenu --
450     *
451     * Tells Tcl to redo the geometry because this menu has changed.
452     * Does it now; removes any ComputeMenuGeometries from the idler.
453     *
454     * Results:
455     * None.
456     *
457     * Side effects:
458     * Menu geometry is immediately reconfigured.
459     *
460     *----------------------------------------------------------------------
461     */
462    
463     void
464     TkRecomputeMenu(menuPtr)
465     TkMenu *menuPtr;
466     {
467     if (menuPtr->menuFlags & RESIZE_PENDING) {
468     Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
469     ComputeMenuGeometry((ClientData) menuPtr);
470     }
471     }
472    
473     /*
474     *----------------------------------------------------------------------
475     *
476     * TkEventuallyRedrawMenu --
477     *
478     * Arrange for an entry of a menu, or the whole menu, to be
479     * redisplayed at some point in the future.
480     *
481     * Results:
482     * None.
483     *
484     * Side effects:
485     * A when-idle hander is scheduled to do the redisplay, if there
486     * isn't one already scheduled.
487     *
488     *----------------------------------------------------------------------
489     */
490    
491     void
492     TkEventuallyRedrawMenu(menuPtr, mePtr)
493     register TkMenu *menuPtr; /* Information about menu to redraw. */
494     register TkMenuEntry *mePtr;/* Entry to redraw. NULL means redraw
495     * all the entries in the menu. */
496     {
497     int i;
498    
499     if (menuPtr->tkwin == NULL) {
500     return;
501     }
502     if (mePtr != NULL) {
503     mePtr->entryFlags |= ENTRY_NEEDS_REDISPLAY;
504     } else {
505     for (i = 0; i < menuPtr->numEntries; i++) {
506     menuPtr->entries[i]->entryFlags |= ENTRY_NEEDS_REDISPLAY;
507     }
508     }
509     if (!Tk_IsMapped(menuPtr->tkwin)
510     || (menuPtr->menuFlags & REDRAW_PENDING)) {
511     return;
512     }
513     Tcl_DoWhenIdle(DisplayMenu, (ClientData) menuPtr);
514     menuPtr->menuFlags |= REDRAW_PENDING;
515     }
516    
517     /*
518     *--------------------------------------------------------------
519     *
520     * ComputeMenuGeometry --
521     *
522     * This procedure is invoked to recompute the size and
523     * layout of a menu. It is called as a when-idle handler so
524     * that it only gets done once, even if a group of changes is
525     * made to the menu.
526     *
527     * Results:
528     * None.
529     *
530     * Side effects:
531     * Fields of menu entries are changed to reflect their
532     * current positions, and the size of the menu window
533     * itself may be changed.
534     *
535     *--------------------------------------------------------------
536     */
537    
538     static void
539     ComputeMenuGeometry(clientData)
540     ClientData clientData; /* Structure describing menu. */
541     {
542     TkMenu *menuPtr = (TkMenu *) clientData;
543    
544     if (menuPtr->tkwin == NULL) {
545     return;
546     }
547    
548     if (menuPtr->menuType == MENUBAR) {
549     TkpComputeMenubarGeometry(menuPtr);
550     } else {
551     TkpComputeStandardMenuGeometry(menuPtr);
552     }
553    
554     if ((menuPtr->totalWidth != Tk_ReqWidth(menuPtr->tkwin)) ||
555     (menuPtr->totalHeight != Tk_ReqHeight(menuPtr->tkwin))) {
556     Tk_GeometryRequest(menuPtr->tkwin, menuPtr->totalWidth,
557     menuPtr->totalHeight);
558     }
559    
560     /*
561     * Must always force a redisplay here if the window is mapped
562     * (even if the size didn't change, something else might have
563     * changed in the menu, such as a label or accelerator). The
564     * resize will force a redisplay above.
565     */
566    
567     TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
568    
569     menuPtr->menuFlags &= ~RESIZE_PENDING;
570     }
571    
572     /*
573     *----------------------------------------------------------------------
574     *
575     * TkMenuSelectImageProc --
576     *
577     * This procedure is invoked by the image code whenever the manager
578     * for an image does something that affects the size of contents
579     * of an image displayed in a menu entry when it is selected.
580     *
581     * Results:
582     * None.
583     *
584     * Side effects:
585     * Arranges for the menu to get redisplayed.
586     *
587     *----------------------------------------------------------------------
588     */
589    
590     void
591     TkMenuSelectImageProc(clientData, x, y, width, height, imgWidth,
592     imgHeight)
593     ClientData clientData; /* Pointer to widget record. */
594     int x, y; /* Upper left pixel (within image)
595     * that must be redisplayed. */
596     int width, height; /* Dimensions of area to redisplay
597     * (may be <= 0). */
598     int imgWidth, imgHeight; /* New dimensions of image. */
599     {
600     register TkMenuEntry *mePtr = (TkMenuEntry *) clientData;
601    
602     if ((mePtr->entryFlags & ENTRY_SELECTED)
603     && !(mePtr->menuPtr->menuFlags &
604     REDRAW_PENDING)) {
605     mePtr->menuPtr->menuFlags |= REDRAW_PENDING;
606     Tcl_DoWhenIdle(DisplayMenu, (ClientData) mePtr->menuPtr);
607     }
608     }
609    
610     /*
611     *----------------------------------------------------------------------
612     *
613     * DisplayMenu --
614     *
615     * This procedure is invoked to display a menu widget.
616     *
617     * Results:
618     * None.
619     *
620     * Side effects:
621     * Commands are output to X to display the menu in its
622     * current mode.
623     *
624     *----------------------------------------------------------------------
625     */
626    
627     static void
628     DisplayMenu(clientData)
629     ClientData clientData; /* Information about widget. */
630     {
631     register TkMenu *menuPtr = (TkMenu *) clientData;
632     register TkMenuEntry *mePtr;
633     register Tk_Window tkwin = menuPtr->tkwin;
634     int index, strictMotif;
635     Tk_Font tkfont;
636     Tk_FontMetrics menuMetrics;
637     int width;
638     int borderWidth;
639     Tk_3DBorder border;
640     int activeBorderWidth;
641     int relief;
642    
643    
644     menuPtr->menuFlags &= ~REDRAW_PENDING;
645     if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
646     return;
647     }
648    
649     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
650     &borderWidth);
651     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
652     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
653     menuPtr->activeBorderWidthPtr, &activeBorderWidth);
654    
655     if (menuPtr->menuType == MENUBAR) {
656     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, borderWidth,
657     borderWidth, Tk_Width(tkwin) - 2 * borderWidth,
658     Tk_Height(tkwin) - 2 * borderWidth, 0, TK_RELIEF_FLAT);
659     }
660    
661     strictMotif = Tk_StrictMotif(menuPtr->tkwin);
662    
663     /*
664     * See note in ComputeMenuGeometry. We don't want to be doing font metrics
665     * all of the time.
666     */
667    
668     tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
669     Tk_GetFontMetrics(tkfont, &menuMetrics);
670    
671     /*
672     * Loop through all of the entries, drawing them one at a time.
673     */
674    
675     for (index = 0; index < menuPtr->numEntries; index++) {
676     mePtr = menuPtr->entries[index];
677     if (menuPtr->menuType != MENUBAR) {
678     if (!(mePtr->entryFlags & ENTRY_NEEDS_REDISPLAY)) {
679     continue;
680     }
681     }
682     mePtr->entryFlags &= ~ENTRY_NEEDS_REDISPLAY;
683    
684     if (menuPtr->menuType == MENUBAR) {
685     width = mePtr->width;
686     } else {
687     if (mePtr->entryFlags & ENTRY_LAST_COLUMN) {
688     width = Tk_Width(menuPtr->tkwin) - mePtr->x
689     - activeBorderWidth;
690     } else {
691     width = mePtr->width + borderWidth;
692     }
693     }
694     TkpDrawMenuEntry(mePtr, Tk_WindowId(menuPtr->tkwin), tkfont,
695     &menuMetrics, mePtr->x, mePtr->y, width,
696     mePtr->height, strictMotif, 1);
697     if ((index > 0) && (menuPtr->menuType != MENUBAR)
698     && mePtr->columnBreak) {
699     mePtr = menuPtr->entries[index - 1];
700     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border,
701     mePtr->x, mePtr->y + mePtr->height,
702     mePtr->width,
703     Tk_Height(tkwin) - mePtr->y - mePtr->height -
704     activeBorderWidth, 0,
705     TK_RELIEF_FLAT);
706     }
707     }
708    
709     if (menuPtr->menuType != MENUBAR) {
710     int x, y, height;
711    
712     if (menuPtr->numEntries == 0) {
713     x = y = borderWidth;
714     width = Tk_Width(tkwin) - 2 * activeBorderWidth;
715     height = Tk_Height(tkwin) - 2 * activeBorderWidth;
716     } else {
717     mePtr = menuPtr->entries[menuPtr->numEntries - 1];
718     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
719     border, mePtr->x, mePtr->y + mePtr->height, mePtr->width,
720     Tk_Height(tkwin) - mePtr->y - mePtr->height
721     - activeBorderWidth, 0,
722     TK_RELIEF_FLAT);
723     x = mePtr->x + mePtr->width;
724     y = mePtr->y + mePtr->height;
725     width = Tk_Width(tkwin) - x - activeBorderWidth;
726     height = Tk_Height(tkwin) - y - activeBorderWidth;
727     }
728     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, x, y,
729     width, height, 0, TK_RELIEF_FLAT);
730     }
731    
732     Tk_GetReliefFromObj(NULL, menuPtr->reliefPtr, &relief);
733     Tk_Draw3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
734     border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), borderWidth,
735     relief);
736     }
737    
738     /*
739     *--------------------------------------------------------------
740     *
741     * TkMenuEventProc --
742     *
743     * This procedure is invoked by the Tk dispatcher for various
744     * events on menus.
745     *
746     * Results:
747     * None.
748     *
749     * Side effects:
750     * When the window gets deleted, internal structures get
751     * cleaned up. When it gets exposed, it is redisplayed.
752     *
753     *--------------------------------------------------------------
754     */
755    
756     void
757     TkMenuEventProc(clientData, eventPtr)
758     ClientData clientData; /* Information about window. */
759     XEvent *eventPtr; /* Information about event. */
760     {
761     TkMenu *menuPtr = (TkMenu *) clientData;
762    
763     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
764     TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
765     } else if (eventPtr->type == ConfigureNotify) {
766     TkEventuallyRecomputeMenu(menuPtr);
767     TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
768     } else if (eventPtr->type == ActivateNotify) {
769     if (menuPtr->menuType == TEAROFF_MENU) {
770     TkpSetMainMenubar(menuPtr->interp, menuPtr->tkwin, NULL);
771     }
772     } else if (eventPtr->type == DestroyNotify) {
773     if (menuPtr->tkwin != NULL) {
774     TkDestroyMenu(menuPtr);
775     menuPtr->tkwin = NULL;
776     Tcl_DeleteCommandFromToken(menuPtr->interp, menuPtr->widgetCmd);
777     }
778     if (menuPtr->menuFlags & REDRAW_PENDING) {
779     Tcl_CancelIdleCall(DisplayMenu, (ClientData) menuPtr);
780     }
781     if (menuPtr->menuFlags & RESIZE_PENDING) {
782     Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
783     }
784     Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC);
785     }
786     }
787    
788     /*
789     *----------------------------------------------------------------------
790     *
791     * TkMenuImageProc --
792     *
793     * This procedure is invoked by the image code whenever the manager
794     * for an image does something that affects the size of contents
795     * of an image displayed in a menu entry.
796     *
797     * Results:
798     * None.
799     *
800     * Side effects:
801     * Arranges for the menu to get redisplayed.
802     *
803     *----------------------------------------------------------------------
804     */
805    
806     void
807     TkMenuImageProc(clientData, x, y, width, height, imgWidth,
808     imgHeight)
809     ClientData clientData; /* Pointer to widget record. */
810     int x, y; /* Upper left pixel (within image)
811     * that must be redisplayed. */
812     int width, height; /* Dimensions of area to redisplay
813     * (may be <= 0). */
814     int imgWidth, imgHeight; /* New dimensions of image. */
815     {
816     register TkMenu *menuPtr = ((TkMenuEntry *)clientData)->menuPtr;
817    
818     if ((menuPtr->tkwin != NULL) && !(menuPtr->menuFlags
819     & RESIZE_PENDING)) {
820     menuPtr->menuFlags |= RESIZE_PENDING;
821     Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
822     }
823     }
824    
825     /*
826     *----------------------------------------------------------------------
827     *
828     * TkPostTearoffMenu --
829     *
830     * Posts a menu on the screen. Used to post tearoff menus. On Unix,
831     * all menus are posted this way. Adjusts the menu's position
832     * so that it fits on the screen, and maps and raises the menu.
833     *
834     * Results:
835     * Returns a standard Tcl Error.
836     *
837     * Side effects:
838     * The menu is posted.
839     *
840     *----------------------------------------------------------------------
841     */
842    
843     int
844     TkPostTearoffMenu(interp, menuPtr, x, y)
845     Tcl_Interp *interp; /* The interpreter of the menu */
846     TkMenu *menuPtr; /* The menu we are posting */
847     int x; /* The root X coordinate where we
848     * are posting */
849     int y; /* The root Y coordinate where we
850     * are posting */
851     {
852     int vRootX, vRootY, vRootWidth, vRootHeight;
853     int tmp, result;
854    
855     TkActivateMenuEntry(menuPtr, -1);
856     TkRecomputeMenu(menuPtr);
857     result = TkPostCommand(menuPtr);
858     if (result != TCL_OK) {
859     return result;
860     }
861    
862     /*
863     * The post commands could have deleted the menu, which means
864     * we are dead and should go away.
865     */
866    
867     if (menuPtr->tkwin == NULL) {
868     return TCL_OK;
869     }
870    
871     /*
872     * Adjust the position of the menu if necessary to keep it
873     * visible on the screen. There are two special tricks to
874     * make this work right:
875     *
876     * 1. If a virtual root window manager is being used then
877     * the coordinates are in the virtual root window of
878     * menuPtr's parent; since the menu uses override-redirect
879     * mode it will be in the *real* root window for the screen,
880     * so we have to map the coordinates from the virtual root
881     * (if any) to the real root. Can't get the virtual root
882     * from the menu itself (it will never be seen by the wm)
883     * so use its parent instead (it would be better to have an
884     * an option that names a window to use for this...).
885     * 2. The menu may not have been mapped yet, so its current size
886     * might be the default 1x1. To compute how much space it
887     * needs, use its requested size, not its actual size.
888     *
889     * Note that this code assumes square screen regions and all
890     * positive coordinates. This does not work on a Mac with
891     * multiple monitors. But then again, Tk has other problems
892     * with this.
893     */
894    
895     Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY,
896     &vRootWidth, &vRootHeight);
897     x += vRootX;
898     y += vRootY;
899     tmp = WidthOfScreen(Tk_Screen(menuPtr->tkwin))
900     - Tk_ReqWidth(menuPtr->tkwin);
901     if (x > tmp) {
902     x = tmp;
903     }
904     if (x < 0) {
905     x = 0;
906     }
907     tmp = HeightOfScreen(Tk_Screen(menuPtr->tkwin))
908     - Tk_ReqHeight(menuPtr->tkwin);
909     if (y > tmp) {
910     y = tmp;
911     }
912     if (y < 0) {
913     y = 0;
914     }
915     Tk_MoveToplevelWindow(menuPtr->tkwin, x, y);
916     if (!Tk_IsMapped(menuPtr->tkwin)) {
917     Tk_MapWindow(menuPtr->tkwin);
918     }
919     TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL);
920     return TCL_OK;
921     }
922    
923     /*
924     *--------------------------------------------------------------
925     *
926     * TkPostSubmenu --
927     *
928     * This procedure arranges for a particular submenu (i.e. the
929     * menu corresponding to a given cascade entry) to be
930     * posted.
931     *
932     * Results:
933     * A standard Tcl return result. Errors may occur in the
934     * Tcl commands generated to post and unpost submenus.
935     *
936     * Side effects:
937     * If there is already a submenu posted, it is unposted.
938     * The new submenu is then posted.
939     *
940     *--------------------------------------------------------------
941     */
942    
943     int
944     TkPostSubmenu(interp, menuPtr, mePtr)
945     Tcl_Interp *interp; /* Used for invoking sub-commands and
946     * reporting errors. */
947     register TkMenu *menuPtr; /* Information about menu as a whole. */
948     register TkMenuEntry *mePtr; /* Info about submenu that is to be
949     * posted. NULL means make sure that
950     * no submenu is posted. */
951     {
952     int result, x, y;
953    
954     if (mePtr == menuPtr->postedCascade) {
955     return TCL_OK;
956     }
957    
958     if (menuPtr->postedCascade != NULL) {
959     char *name = Tcl_GetStringFromObj(menuPtr->postedCascade->namePtr,
960     NULL);
961    
962     /*
963     * Note: when unposting a submenu, we have to redraw the entire
964     * parent menu. This is because of a combination of the following
965     * things:
966     * (a) the submenu partially overlaps the parent.
967     * (b) the submenu specifies "save under", which causes the X
968     * server to make a copy of the information under it when it
969     * is posted. When the submenu is unposted, the X server
970     * copies this data back and doesn't generate any Expose
971     * events for the parent.
972     * (c) the parent may have redisplayed itself after the submenu
973     * was posted, in which case the saved information is no
974     * longer correct.
975     * The simplest solution is just force a complete redisplay of
976     * the parent.
977     */
978    
979     TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
980     result = Tcl_VarEval(interp, name, " unpost", (char *) NULL);
981     menuPtr->postedCascade = NULL;
982     if (result != TCL_OK) {
983     return result;
984     }
985     }
986    
987     if ((mePtr != NULL) && (mePtr->namePtr != NULL)
988     && Tk_IsMapped(menuPtr->tkwin)) {
989     /*
990     * Position the cascade with its upper left corner slightly
991     * below and to the left of the upper right corner of the
992     * menu entry (this is an attempt to match Motif behavior).
993     *
994     * The menu has to redrawn so that the entry can change relief.
995     */
996    
997     char string[TCL_INTEGER_SPACE * 2];
998     char *name;
999    
1000     name = Tcl_GetStringFromObj(mePtr->namePtr, NULL);
1001     Tk_GetRootCoords(menuPtr->tkwin, &x, &y);
1002     AdjustMenuCoords(menuPtr, mePtr, &x, &y, string);
1003     result = Tcl_VarEval(interp, name, " post ", string, (char *) NULL);
1004     if (result != TCL_OK) {
1005     return result;
1006     }
1007     menuPtr->postedCascade = mePtr;
1008     TkEventuallyRedrawMenu(menuPtr, mePtr);
1009     }
1010     return TCL_OK;
1011     }
1012    
1013     /*
1014     *----------------------------------------------------------------------
1015     *
1016     * AdjustMenuCoords --
1017     *
1018     * Adjusts the given coordinates down and the left to give a Motif
1019     * look.
1020     *
1021     * Results:
1022     * None.
1023     *
1024     * Side effects:
1025     * The menu is eventually redrawn if necessary.
1026     *
1027     *----------------------------------------------------------------------
1028     */
1029    
1030     static void
1031     AdjustMenuCoords(menuPtr, mePtr, xPtr, yPtr, string)
1032     TkMenu *menuPtr;
1033     TkMenuEntry *mePtr;
1034     int *xPtr;
1035     int *yPtr;
1036     char *string;
1037     {
1038     if (menuPtr->menuType == MENUBAR) {
1039     *xPtr += mePtr->x;
1040     *yPtr += mePtr->y + mePtr->height;
1041     } else {
1042     int borderWidth, activeBorderWidth;
1043    
1044     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
1045     &borderWidth);
1046     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
1047     menuPtr->activeBorderWidthPtr, &activeBorderWidth);
1048     *xPtr += Tk_Width(menuPtr->tkwin) - borderWidth - activeBorderWidth
1049     - 2;
1050     *yPtr += mePtr->y + activeBorderWidth + 2;
1051     }
1052     sprintf(string, "%d %d", *xPtr, *yPtr);
1053     }
1054    
1055    
1056     /* $History: tkMenuDraw.c $
1057     *
1058     * ***************** Version 1 *****************
1059     * User: Dtashley Date: 1/02/01 Time: 2:57a
1060     * Created in $/IjuScripter, IjuConsole/Source/Tk Base
1061     * Initial check-in.
1062     */
1063    
1064     /* End of TKMENUDRAW.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25