1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* tkUnixMenubu.c -- |
5 |
* |
6 |
* This file implements the Unix specific portion of the |
7 |
* menubutton widget. |
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: tkunixmenubu.c,v 1.1.1.1 2001/06/13 05:11:20 dtashley Exp $ |
15 |
*/ |
16 |
|
17 |
#include "tkMenubutton.h" |
18 |
|
19 |
/* |
20 |
* The structure below defines menubutton class behavior by means of |
21 |
* procedures that can be invoked from generic window code. |
22 |
*/ |
23 |
|
24 |
TkClassProcs tkpMenubuttonClass = { |
25 |
NULL, /* createProc. */ |
26 |
TkMenuButtonWorldChanged, /* geometryProc. */ |
27 |
NULL /* modalProc. */ |
28 |
}; |
29 |
|
30 |
/* |
31 |
*---------------------------------------------------------------------- |
32 |
* |
33 |
* TkpCreateMenuButton -- |
34 |
* |
35 |
* Allocate a new TkMenuButton structure. |
36 |
* |
37 |
* Results: |
38 |
* Returns a newly allocated TkMenuButton structure. |
39 |
* |
40 |
* Side effects: |
41 |
* Registers an event handler for the widget. |
42 |
* |
43 |
*---------------------------------------------------------------------- |
44 |
*/ |
45 |
|
46 |
TkMenuButton * |
47 |
TkpCreateMenuButton(tkwin) |
48 |
Tk_Window tkwin; |
49 |
{ |
50 |
return (TkMenuButton *)ckalloc(sizeof(TkMenuButton)); |
51 |
} |
52 |
|
53 |
/* |
54 |
*---------------------------------------------------------------------- |
55 |
* |
56 |
* TkpDisplayMenuButton -- |
57 |
* |
58 |
* This procedure is invoked to display a menubutton widget. |
59 |
* |
60 |
* Results: |
61 |
* None. |
62 |
* |
63 |
* Side effects: |
64 |
* Commands are output to X to display the menubutton in its |
65 |
* current mode. |
66 |
* |
67 |
*---------------------------------------------------------------------- |
68 |
*/ |
69 |
|
70 |
void |
71 |
TkpDisplayMenuButton(clientData) |
72 |
ClientData clientData; /* Information about widget. */ |
73 |
{ |
74 |
register TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
75 |
GC gc; |
76 |
Tk_3DBorder border; |
77 |
Pixmap pixmap; |
78 |
int x = 0; /* Initialization needed only to stop |
79 |
* compiler warning. */ |
80 |
int y; |
81 |
register Tk_Window tkwin = mbPtr->tkwin; |
82 |
int width, height; |
83 |
|
84 |
mbPtr->flags &= ~REDRAW_PENDING; |
85 |
if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { |
86 |
return; |
87 |
} |
88 |
|
89 |
if ((mbPtr->state == STATE_DISABLED) && (mbPtr->disabledFg != NULL)) { |
90 |
gc = mbPtr->disabledGC; |
91 |
border = mbPtr->normalBorder; |
92 |
} else if ((mbPtr->state == STATE_ACTIVE) |
93 |
&& !Tk_StrictMotif(mbPtr->tkwin)) { |
94 |
gc = mbPtr->activeTextGC; |
95 |
border = mbPtr->activeBorder; |
96 |
} else { |
97 |
gc = mbPtr->normalTextGC; |
98 |
border = mbPtr->normalBorder; |
99 |
} |
100 |
|
101 |
/* |
102 |
* In order to avoid screen flashes, this procedure redraws |
103 |
* the menu button in a pixmap, then copies the pixmap to the |
104 |
* screen in a single operation. This means that there's no |
105 |
* point in time where the on-sreen image has been cleared. |
106 |
*/ |
107 |
|
108 |
pixmap = Tk_GetPixmap(mbPtr->display, Tk_WindowId(tkwin), |
109 |
Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); |
110 |
Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin), |
111 |
Tk_Height(tkwin), 0, TK_RELIEF_FLAT); |
112 |
|
113 |
/* |
114 |
* Display image or bitmap or text for button. |
115 |
*/ |
116 |
|
117 |
if (mbPtr->image != None) { |
118 |
Tk_SizeOfImage(mbPtr->image, &width, &height); |
119 |
|
120 |
imageOrBitmap: |
121 |
TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0, |
122 |
width + mbPtr->indicatorWidth, height, &x, &y); |
123 |
if (mbPtr->image != NULL) { |
124 |
Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap, |
125 |
x, y); |
126 |
} else { |
127 |
XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap, |
128 |
gc, 0, 0, (unsigned) width, (unsigned) height, x, y, 1); |
129 |
} |
130 |
} else if (mbPtr->bitmap != None) { |
131 |
Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); |
132 |
goto imageOrBitmap; |
133 |
} else { |
134 |
TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY, |
135 |
mbPtr->textWidth + mbPtr->indicatorWidth, |
136 |
mbPtr->textHeight, &x, &y); |
137 |
Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, x, y, |
138 |
0, -1); |
139 |
Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, |
140 |
x, y, mbPtr->underline); |
141 |
} |
142 |
|
143 |
/* |
144 |
* If the menu button is disabled with a stipple rather than a special |
145 |
* foreground color, generate the stippled effect. |
146 |
*/ |
147 |
|
148 |
if ((mbPtr->state == STATE_DISABLED) |
149 |
&& ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) { |
150 |
XFillRectangle(mbPtr->display, pixmap, mbPtr->disabledGC, |
151 |
mbPtr->inset, mbPtr->inset, |
152 |
(unsigned) (Tk_Width(tkwin) - 2*mbPtr->inset), |
153 |
(unsigned) (Tk_Height(tkwin) - 2*mbPtr->inset)); |
154 |
} |
155 |
|
156 |
/* |
157 |
* Draw the cascade indicator for the menu button on the |
158 |
* right side of the window, if desired. |
159 |
*/ |
160 |
|
161 |
if (mbPtr->indicatorOn) { |
162 |
int borderWidth; |
163 |
|
164 |
borderWidth = (mbPtr->indicatorHeight+1)/3; |
165 |
if (borderWidth < 1) { |
166 |
borderWidth = 1; |
167 |
} |
168 |
/*y += mbPtr->textHeight / 2;*/ |
169 |
Tk_Fill3DRectangle(tkwin, pixmap, border, |
170 |
Tk_Width(tkwin) - mbPtr->inset - mbPtr->indicatorWidth |
171 |
+ mbPtr->indicatorHeight, |
172 |
((int) (Tk_Height(tkwin) - mbPtr->indicatorHeight))/2, |
173 |
mbPtr->indicatorWidth - 2*mbPtr->indicatorHeight, |
174 |
mbPtr->indicatorHeight, borderWidth, TK_RELIEF_RAISED); |
175 |
} |
176 |
|
177 |
/* |
178 |
* Draw the border and traversal highlight last. This way, if the |
179 |
* menu button's contents overflow onto the border they'll be covered |
180 |
* up by the border. |
181 |
*/ |
182 |
|
183 |
if (mbPtr->relief != TK_RELIEF_FLAT) { |
184 |
Tk_Draw3DRectangle(tkwin, pixmap, border, |
185 |
mbPtr->highlightWidth, mbPtr->highlightWidth, |
186 |
Tk_Width(tkwin) - 2*mbPtr->highlightWidth, |
187 |
Tk_Height(tkwin) - 2*mbPtr->highlightWidth, |
188 |
mbPtr->borderWidth, mbPtr->relief); |
189 |
} |
190 |
if (mbPtr->highlightWidth != 0) { |
191 |
GC gc; |
192 |
|
193 |
if (mbPtr->flags & GOT_FOCUS) { |
194 |
gc = Tk_GCForColor(mbPtr->highlightColorPtr, pixmap); |
195 |
} else { |
196 |
gc = Tk_GCForColor(mbPtr->highlightBgColorPtr, pixmap); |
197 |
} |
198 |
Tk_DrawFocusHighlight(tkwin, gc, mbPtr->highlightWidth, pixmap); |
199 |
} |
200 |
|
201 |
/* |
202 |
* Copy the information from the off-screen pixmap onto the screen, |
203 |
* then delete the pixmap. |
204 |
*/ |
205 |
|
206 |
XCopyArea(mbPtr->display, pixmap, Tk_WindowId(tkwin), |
207 |
mbPtr->normalTextGC, 0, 0, (unsigned) Tk_Width(tkwin), |
208 |
(unsigned) Tk_Height(tkwin), 0, 0); |
209 |
Tk_FreePixmap(mbPtr->display, pixmap); |
210 |
} |
211 |
|
212 |
/* |
213 |
*---------------------------------------------------------------------- |
214 |
* |
215 |
* TkpDestroyMenuButton -- |
216 |
* |
217 |
* Free data structures associated with the menubutton control. |
218 |
* |
219 |
* Results: |
220 |
* None. |
221 |
* |
222 |
* Side effects: |
223 |
* Restores the default control state. |
224 |
* |
225 |
*---------------------------------------------------------------------- |
226 |
*/ |
227 |
|
228 |
void |
229 |
TkpDestroyMenuButton(mbPtr) |
230 |
TkMenuButton *mbPtr; |
231 |
{ |
232 |
} |
233 |
|
234 |
/* |
235 |
*---------------------------------------------------------------------- |
236 |
* |
237 |
* TkpComputeMenuButtonGeometry -- |
238 |
* |
239 |
* After changes in a menu button's text or bitmap, this procedure |
240 |
* recomputes the menu button's geometry and passes this information |
241 |
* along to the geometry manager for the window. |
242 |
* |
243 |
* Results: |
244 |
* None. |
245 |
* |
246 |
* Side effects: |
247 |
* The menu button's window may change size. |
248 |
* |
249 |
*---------------------------------------------------------------------- |
250 |
*/ |
251 |
|
252 |
void |
253 |
TkpComputeMenuButtonGeometry(mbPtr) |
254 |
TkMenuButton *mbPtr; /* Widget record for menu button. */ |
255 |
{ |
256 |
int width, height, mm, pixels; |
257 |
|
258 |
mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth; |
259 |
if (mbPtr->image != None) { |
260 |
Tk_SizeOfImage(mbPtr->image, &width, &height); |
261 |
if (mbPtr->width > 0) { |
262 |
width = mbPtr->width; |
263 |
} |
264 |
if (mbPtr->height > 0) { |
265 |
height = mbPtr->height; |
266 |
} |
267 |
} else if (mbPtr->bitmap != None) { |
268 |
Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); |
269 |
if (mbPtr->width > 0) { |
270 |
width = mbPtr->width; |
271 |
} |
272 |
if (mbPtr->height > 0) { |
273 |
height = mbPtr->height; |
274 |
} |
275 |
} else { |
276 |
Tk_FreeTextLayout(mbPtr->textLayout); |
277 |
mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text, |
278 |
-1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth, |
279 |
&mbPtr->textHeight); |
280 |
width = mbPtr->textWidth; |
281 |
height = mbPtr->textHeight; |
282 |
if (mbPtr->width > 0) { |
283 |
width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1); |
284 |
} |
285 |
if (mbPtr->height > 0) { |
286 |
Tk_FontMetrics fm; |
287 |
|
288 |
Tk_GetFontMetrics(mbPtr->tkfont, &fm); |
289 |
height = mbPtr->height * fm.linespace; |
290 |
} |
291 |
width += 2*mbPtr->padX; |
292 |
height += 2*mbPtr->padY; |
293 |
} |
294 |
|
295 |
if (mbPtr->indicatorOn) { |
296 |
mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin)); |
297 |
pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin)); |
298 |
mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm); |
299 |
mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm) |
300 |
+ 2*mbPtr->indicatorHeight; |
301 |
width += mbPtr->indicatorWidth; |
302 |
} else { |
303 |
mbPtr->indicatorHeight = 0; |
304 |
mbPtr->indicatorWidth = 0; |
305 |
} |
306 |
|
307 |
Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset), |
308 |
(int) (height + 2*mbPtr->inset)); |
309 |
Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset); |
310 |
} |
311 |
|
312 |
/* End of tkunixmenubu.c */ |