OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkMenuDraw.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.