1 /*
2 * Copyright (C) 1995, 1996 Karl-Johan Johnsson.
3 */
4
5 #include <X11/IntrinsicP.h>
6 #include <X11/StringDefs.h>
7 #include <stdio.h>
8
9 #include "Compat.h"
10
11 #include "MenuI.h"
12 #include "PullRightP.h"
13
14 static XtResource resources[] = {
15 #define offset(field) XtOffsetOf(PullRightGadgetRec, pull_right.field)
16 {XtNmenuName, XtCMenuName, XtRString, sizeof(String),
17 offset(menu_name), XtRImmediate, (XtPointer)NULL},
18 {XtNarrowSize, XtCArrowSize, XtRDimension, sizeof(Dimension),
19 offset(arrow_size), XtRImmediate, (XtPointer)6},
20 {XtNarrowOffset, XtCArrowOffset, XtRDimension, sizeof(Dimension),
21 offset(arrow_offset), XtRImmediate, (XtPointer)8},
22 {XtNarrowShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
23 offset(arrow_shadow_width), XtRImmediate, (XtPointer)1},
24 #undef offset
25 };
26
27 static void Initialize(Widget, Widget, ArgList, Cardinal*);
28 static void Destroy(Widget);
29 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal*);
30 static void Redisplay(Widget, XEvent*, Region);
31 static void ChangeHl(MenuGadget);
32 static void Popdown(MenuGadget);
33 static int Notify(MenuGadget);
34 static int PostNotify(MenuGadget);
35 static void SetActive(MenuGadget, int);
36
37 PullRightGadgetClassRec pullRightGadgetClassRec = {
38 { /* rectObj fields */
39 (WidgetClass) &stringGadgetClassRec, /* superclass */
40 "PullRightGadget", /* class_name */
41 sizeof(PullRightGadgetRec), /* widget_size */
42 NULL, /* class_initialize */
43 NULL, /* class_part_initialize */
44 FALSE, /* class_inited */
45 Initialize, /* initialize */
46 NULL, /* initialize_hook */
47 NULL, /* rect1 */
48 NULL, /* rect2 */
49 0, /* rect3 */
50 resources, /* resources */
51 XtNumber(resources), /* num_resources */
52 NULLQUARK, /* xrm_class */
53 FALSE, /* rect4 */
54 FALSE, /* rect5 */
55 FALSE, /* rect6 */
56 FALSE, /* rect7 */
57 Destroy, /* destroy */
58 NULL, /* resize */
59 Redisplay, /* expose */
60 SetValues, /* set_values */
61 NULL, /* set_values_hook */
62 XtInheritSetValuesAlmost, /* set_values_almost */
63 NULL, /* get_values_hook */
64 NULL, /* rect9 */
65 XtVersion, /* version */
66 NULL, /* callback_private */
67 NULL, /* rect10 */
68 NULL, /* query_geometry */
69 NULL, /* rect11 */
70 NULL, /* extension */
71 },
72 { /* menu_g fields */
73 ChangeHl, /* change_highlighted */
74 Popdown, /* popdown */
75 Notify, /* notify */
76 PostNotify, /* post_notify */
77 SetActive, /* set_active */
78 True, /* ignore_leave */
79 NULL, /* extension */
80 },
81 { /* menu_str_g fields */
82 NULL, /* extension */
83 },
84 { /* pull_right fields */
85 NULL, /* extension */
86 },
87 };
88
89 WidgetClass pullRightGadgetClass = (WidgetClass)&pullRightGadgetClassRec;
90
91 /*************************************************************************/
92
draw_arrow(PullRightGadget g)93 static void draw_arrow(PullRightGadget g)
94 {
95 MenuWidget parent = (MenuWidget)g->object.parent;
96 Display *disp = XtDisplay(parent);
97 Window win = XtWindow(parent);
98 int s = g->pull_right.arrow_size;
99 int x, y;
100
101 if (s <= 0)
102 return;
103
104 x = g->rectangle.x + g->rectangle.width -
105 g->pull_right.arrow_offset - parent->shadow.shadow_width;
106 y = g->rectangle.y + g->rectangle.height/2;
107
108 if (parent->shadow.line_mode) {
109 short sw = parent->shadow.shadow_width;
110 XPoint point[4];
111
112 XClearArea(disp, win, x - s - sw, y - s/2 - sw,
113 s + 2 * sw, s + 2 * sw, False);
114
115 if (!g->menu_g.hl)
116 sw = 0;
117 else {
118 sw /= 2;
119 s -= sw;
120 }
121
122 point[0].x = point[3].x = x - sw/2;
123 point[1].x = point[2].x = x - s;
124
125 point[0].y = point[3].y = y;
126 point[1].y = y - s/2;
127 point[2].y = y + s/2;
128
129 XDrawLines(disp, win,
130 !g->menu_g.hl ?
131 parent->shadow.light_gc : parent->shadow.dark_gc,
132 point, 4, CoordModeOrigin);
133 } else {
134 XPoint point[6];
135 short sw = g->pull_right.arrow_shadow_width;
136 GC light_gc, dark_gc;
137
138 if (g->menu_g.hl) {
139 light_gc = parent->shadow.dark_gc;
140 dark_gc = parent->shadow.light_gc;
141 } else {
142 light_gc = parent->shadow.light_gc;
143 dark_gc = parent->shadow.dark_gc;
144 }
145
146 if (sw == 0)
147 return;
148 else if (sw == 1) {
149 point[0].x = point[3].x = x;
150 point[1].x = point[2].x = x - s;
151
152 point[0].y = point[3].y = y;
153 point[1].y = y - s/2;
154 point[2].y = y + s/2;
155
156 if (!g->menu_g.hl && parent->shadow.arm_gc != 0)
157 XFillPolygon(disp, win, parent->shadow.arm_gc,
158 point, 3, Convex, CoordModeOrigin);
159
160 XDrawLines(disp, win, dark_gc, point, 3, CoordModeOrigin);
161 XDrawLines(disp, win, light_gc, &point[2], 2, CoordModeOrigin);
162 } else {
163 point[0].x = x;
164 point[1].x = point[2].x = x - s;
165 point[3].x = point[4].x = x - s + sw;
166 point[5].x = x - (9 * sw)/4;
167
168 point[0].y = point[5].y = y;
169 point[1].y = y - s/2;
170 point[2].y = y + s/2;
171 point[3].y = point[2].y - (3 * sw)/2;
172 point[4].y = point[1].y + (3 * sw)/2;
173
174 if (!g->menu_g.hl && parent->shadow.arm_gc != 0)
175 XFillPolygon(disp, win, parent->shadow.arm_gc,
176 &point[3], 3, Convex, CoordModeOrigin);
177
178 XFillPolygon(disp, win, dark_gc,
179 point, 6, Nonconvex, CoordModeOrigin);
180 point[1] = point[0];
181 point[4] = point[5];
182 XFillPolygon(disp, win, light_gc,
183 &point[1], 4, Convex, CoordModeOrigin);
184 }
185 }
186 }
187
find_menu(PullRightGadget g)188 static Widget find_menu(PullRightGadget g)
189 {
190 if (g->pull_right.menu_name) {
191 Widget loop;
192
193 for (loop = g->object.parent ; loop ; loop = XtParent(loop)) {
194 Widget temp = XtNameToWidget(loop, g->pull_right.menu_name);
195
196 if (temp && XtIsShell(temp))
197 return temp;
198 }
199 }
200
201 return NULL;
202 }
203
204 /*************************************************************************/
205
Initialize(Widget grequest,Widget gnew,ArgList args,Cardinal * no_args)206 static void Initialize(Widget grequest, Widget gnew,
207 ArgList args, Cardinal *no_args)
208 {
209 PullRightGadget g = (PullRightGadget)gnew;
210
211 if (!g->pull_right.menu_name)
212 g->pull_right.menu = NULL;
213 else {
214 g->pull_right.menu_name = XtNewString(g->pull_right.menu_name);
215 g->pull_right.menu = find_menu(g);
216 }
217 }
218
Destroy(Widget gw)219 static void Destroy(Widget gw)
220 {
221 PullRightGadget w = (PullRightGadget)gw;
222
223 XtFree(w->pull_right.menu_name);
224 }
225
Redisplay(Widget gw,XEvent * event,Region region)226 static void Redisplay(Widget gw, XEvent *event, Region region)
227 {
228 PullRightGadget w = (PullRightGadget)gw;
229
230 stringGadgetClass->core_class.expose((Widget)w, event, region);
231
232 draw_arrow(w);
233 }
234
SetValues(Widget gcurrent,Widget grequest,Widget gnew,ArgList args,Cardinal * num_args)235 static Boolean SetValues(Widget gcurrent,
236 Widget grequest,
237 Widget gnew,
238 ArgList args,
239 Cardinal *num_args)
240 {
241 Boolean redisplay = False;
242 PullRightGadget new = (PullRightGadget)gnew;
243 PullRightGadget current = (PullRightGadget)gcurrent;
244
245 if (new->pull_right.menu_name != current->pull_right.menu_name) {
246 XtFree(current->pull_right.menu_name);
247 if (!new->pull_right.menu_name)
248 new->pull_right.menu = NULL;
249 else {
250 new->pull_right.menu_name = XtNewString(new->pull_right.menu_name);
251 new->pull_right.menu = find_menu(new);
252 }
253 }
254
255 return redisplay;
256 }
257
ChangeHl(MenuGadget m)258 static void ChangeHl(MenuGadget m)
259 {
260 PullRightGadget g = (PullRightGadget)m;
261 Widget parent = g->object.parent;
262 Widget menu = g->pull_right.menu;
263 Screen *screen;
264 Arg args[2];
265 Position x, y;
266
267 Redisplay((Widget)g, NULL, NULL);
268
269 if (!menu && !(menu = g->pull_right.menu = find_menu(g))) {
270 fprintf(stderr, "PullRightGadget: Couldn't find menu: %s\n",
271 g->pull_right.menu_name);
272 return;
273 }
274
275 /*
276 * Unhighlight.
277 */
278 if (!g->menu_g.hl) {
279 PopdownMenuShell(menu);
280 return;
281 }
282
283 screen = XtScreen(menu);
284 if (!XtIsRealized(menu))
285 XtRealizeWidget(menu);
286 XtTranslateCoords(parent, parent->core.width, g->rectangle.y, &x, &y);
287 if (x < 0)
288 x = 0;
289 else {
290 int tmp = WidthOfScreen(screen) - menu->core.width;
291
292 if (tmp >= 0 && x > tmp)
293 x = tmp;
294 }
295 if (y < 0)
296 y = 0;
297 else {
298 int tmp = HeightOfScreen(screen) - menu->core.height;
299
300 if (tmp >= 0 && y > tmp)
301 y = tmp;
302 }
303 XtSetArg(args[0], XtNx, x);
304 XtSetArg(args[1], XtNy, y);
305 XtSetValues(menu, args, 2);
306 XtPopup(menu, XtGrabNone/*xclusive*/);
307 XtAddGrab(menu, False, False);
308 }
309
Popdown(MenuGadget m)310 static void Popdown(MenuGadget m)
311 {
312 PullRightGadget g = (PullRightGadget)m;
313
314 if (g->pull_right.menu)
315 PopdownMenuShell(g->pull_right.menu);
316 }
317
Notify(MenuGadget m)318 static int Notify(MenuGadget m)
319 {
320 PullRightGadget g = (PullRightGadget)m;
321
322 if (!g->pull_right.menu || g->menu_g.inside) {
323 XtCallCallbackList((Widget)g, g->menu_g.callback, NULL);
324 return True;
325 }
326
327 return NotifyMenuShell(g->pull_right.menu);
328 }
329
PostNotify(MenuGadget m)330 static int PostNotify(MenuGadget m)
331 {
332 PullRightGadget g = (PullRightGadget)m;
333
334 if (!g->pull_right.menu || g->menu_g.inside) {
335 XtCallCallbackList((Widget)g, g->menu_g.post_popdown_callback, NULL);
336 return True;
337 }
338
339 return PostNotifyMenuShell(g->pull_right.menu);
340 }
341
SetActive(MenuGadget m,int active)342 static void SetActive(MenuGadget m, int active)
343 {
344 PullRightGadget g = (PullRightGadget)m;
345
346 g->menu_g.active = active;
347 if (g->pull_right.menu)
348 SetActiveMenuShell(g->pull_right.menu, active);
349 }
350