Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wpopupbutton.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002#include "WINGsP.h"
3
9d2e6ef9 scottc1998-09-29 22:36:29 +00004typedef struct W_PopUpButton {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02005 W_Class widgetClass;
6 WMView *view;
6830b057 dan2004-10-12 21:28:27 +00007
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02008 void *clientData;
9 WMAction *action;
9d2e6ef9 scottc1998-09-29 22:36:29 +000010
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020011 char *caption;
9d2e6ef9 scottc1998-09-29 22:36:29 +000012
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020013 WMArray *items;
6830b057 dan2004-10-12 21:28:27 +000014
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020015 short selectedItemIndex;
6830b057 dan2004-10-12 21:28:27 +000016
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020017 short highlightedItem;
6830b057 dan2004-10-12 21:28:27 +000018
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020019 WMView *menuView; /* override redirect popup menu */
9d2e6ef9 scottc1998-09-29 22:36:29 +000020
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020021 WMHandlerID timer; /* for autoscroll */
0261c326 dan1999-01-06 15:22:33 +000022
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020023 /**/ int scrollStartY; /* for autoscroll */
6830b057 dan2004-10-12 21:28:27 +000024
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020025 struct {
26 unsigned int pullsDown:1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000027
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020028 unsigned int configured:1;
6830b057 dan2004-10-12 21:28:27 +000029
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020030 unsigned int insideMenu:1;
6830b057 dan2004-10-12 21:28:27 +000031
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020032 unsigned int enabled:1;
0261c326 dan1999-01-06 15:22:33 +000033
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020034 } flags;
9d2e6ef9 scottc1998-09-29 22:36:29 +000035} PopUpButton;
36
9d2e6ef9 scottc1998-09-29 22:36:29 +000037#define MENU_BLINK_DELAY 60000
38#define MENU_BLINK_COUNT 2
39
e1001cb0 dan1999-03-30 22:14:17 +000040#define SCROLL_DELAY 10
0261c326 dan1999-01-06 15:22:33 +000041
9d2e6ef9 scottc1998-09-29 22:36:29 +000042#define DEFAULT_WIDTH 60
43#define DEFAULT_HEIGHT 20
44#define DEFAULT_CAPTION ""
45
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020046static void destroyPopUpButton(PopUpButton * bPtr);
47static void paintPopUpButton(PopUpButton * bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000048
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020049static void handleEvents(XEvent * event, void *data);
50static void handleActionEvents(XEvent * event, void *data);
9d2e6ef9 scottc1998-09-29 22:36:29 +000051
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020052static void resizeMenu(PopUpButton * bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000053
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020054WMPopUpButton *WMCreatePopUpButton(WMWidget * parent)
9d2e6ef9 scottc1998-09-29 22:36:29 +000055{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020056 PopUpButton *bPtr;
57 W_Screen *scr = W_VIEW(parent)->screen;
6830b057 dan2004-10-12 21:28:27 +000058
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020059 bPtr = wmalloc(sizeof(PopUpButton));
60 memset(bPtr, 0, sizeof(PopUpButton));
9d2e6ef9 scottc1998-09-29 22:36:29 +000061
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020062 bPtr->widgetClass = WC_PopUpButton;
6830b057 dan2004-10-12 21:28:27 +000063
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020064 bPtr->view = W_CreateView(W_VIEW(parent));
65 if (!bPtr->view) {
66 wfree(bPtr);
67 return NULL;
68 }
69 bPtr->view->self = bPtr;
6830b057 dan2004-10-12 21:28:27 +000070
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020071 WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask
72 | ClientMessageMask, handleEvents, bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000073
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020074 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
75 bPtr->caption = wstrdup(DEFAULT_CAPTION);
9d2e6ef9 scottc1998-09-29 22:36:29 +000076
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020077 WMCreateEventHandler(bPtr->view, ButtonPressMask | ButtonReleaseMask, handleActionEvents, bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000078
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020079 bPtr->flags.enabled = 1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000080
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020081 bPtr->items = WMCreateArrayWithDestructor(4, (WMFreeDataProc *) WMDestroyMenuItem);
6830b057 dan2004-10-12 21:28:27 +000082
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020083 bPtr->selectedItemIndex = -1;
eb87c409 kojima1999-10-20 03:25:06 +000084
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020085 bPtr->menuView = W_CreateUnmanagedTopView(scr);
dba6e4d2 dan2000-01-05 22:02:22 +000086
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020087 W_ResizeView(bPtr->menuView, bPtr->view->size.width, 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +000088
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020089 WMCreateEventHandler(bPtr->menuView, ButtonPressMask | ButtonReleaseMask
90 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask
91 | ExposureMask, handleActionEvents, bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000092
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020093 return bPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +000094}
95
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020096void WMSetPopUpButtonAction(WMPopUpButton * bPtr, WMAction * action, void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +000097{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020098 CHECK_CLASS(bPtr, WC_PopUpButton);
6830b057 dan2004-10-12 21:28:27 +000099
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200100 bPtr->action = action;
6830b057 dan2004-10-12 21:28:27 +0000101
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200102 bPtr->clientData = clientData;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000103}
104
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200105WMMenuItem *WMAddPopUpButtonItem(WMPopUpButton * bPtr, char *title)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000106{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200107 WMMenuItem *item;
6830b057 dan2004-10-12 21:28:27 +0000108
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109 CHECK_CLASS(bPtr, WC_PopUpButton);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000110
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 item = WMCreateMenuItem();
112 WMSetMenuItemTitle(item, title);
eb87c409 kojima1999-10-20 03:25:06 +0000113
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200114 WMAddToArray(bPtr->items, item);
eb87c409 kojima1999-10-20 03:25:06 +0000115
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200116 if (bPtr->menuView && bPtr->menuView->flags.realized)
117 resizeMenu(bPtr);
eb87c409 kojima1999-10-20 03:25:06 +0000118
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200119 return item;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000120}
121
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200122WMMenuItem *WMInsertPopUpButtonItem(WMPopUpButton * bPtr, int index, char *title)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000123{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200124 WMMenuItem *item;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000125
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200126 CHECK_CLASS(bPtr, WC_PopUpButton);
6830b057 dan2004-10-12 21:28:27 +0000127
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200128 item = WMCreateMenuItem();
129 WMSetMenuItemTitle(item, title);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000130
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200131 WMInsertInArray(bPtr->items, index, item);
6830b057 dan2004-10-12 21:28:27 +0000132
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200133 /* if there is an selected item, update it's index to match the new
134 * position */
135 if (index < bPtr->selectedItemIndex)
136 bPtr->selectedItemIndex++;
6830b057 dan2004-10-12 21:28:27 +0000137
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200138 if (bPtr->menuView && bPtr->menuView->flags.realized)
139 resizeMenu(bPtr);
6830b057 dan2004-10-12 21:28:27 +0000140
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200141 return item;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000142}
143
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200144void WMRemovePopUpButtonItem(WMPopUpButton * bPtr, int index)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000145{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200146 CHECK_CLASS(bPtr, WC_PopUpButton);
147
148 wassertr(index >= 0 && index < WMGetArrayItemCount(bPtr->items));
149
150 WMDeleteFromArray(bPtr->items, index);
151
152 if (bPtr->selectedItemIndex >= 0 && !bPtr->flags.pullsDown) {
153 if (index < bPtr->selectedItemIndex)
154 bPtr->selectedItemIndex--;
155 else if (index == bPtr->selectedItemIndex) {
156 /* reselect first item if the removed item is the
157 * selected one */
158 bPtr->selectedItemIndex = 0;
159 if (bPtr->view->flags.mapped)
160 paintPopUpButton(bPtr);
161 }
162 }
163
164 if (bPtr->menuView && bPtr->menuView->flags.realized)
165 resizeMenu(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000166}
167
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200168void WMSetPopUpButtonEnabled(WMPopUpButton * bPtr, Bool flag)
0261c326 dan1999-01-06 15:22:33 +0000169{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200170 bPtr->flags.enabled = ((flag == 0) ? 0 : 1);
171 if (bPtr->view->flags.mapped)
172 paintPopUpButton(bPtr);
0261c326 dan1999-01-06 15:22:33 +0000173}
174
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200175Bool WMGetPopUpButtonEnabled(WMPopUpButton * bPtr)
adb74c68 dan1999-05-25 02:15:44 +0000176{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200177 return bPtr->flags.enabled;
adb74c68 dan1999-05-25 02:15:44 +0000178}
179
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200180void WMSetPopUpButtonSelectedItem(WMPopUpButton * bPtr, int index)
38807b65 dan1999-11-07 21:40:22 +0000181{
182
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200183 wassertr(index < WMGetArrayItemCount(bPtr->items));
38807b65 dan1999-11-07 21:40:22 +0000184
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200185 /* if (index >= WMGetArrayCount(bPtr->items))
186 index = -1; */
38807b65 dan1999-11-07 21:40:22 +0000187
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200188 bPtr->selectedItemIndex = index;
6830b057 dan2004-10-12 21:28:27 +0000189
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200190 if (bPtr->view->flags.mapped)
191 paintPopUpButton(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000192}
193
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200194int WMGetPopUpButtonSelectedItem(WMPopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000195{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200196 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
197 return -1;
198 else
199 return bPtr->selectedItemIndex;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000200}
201
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200202void WMSetPopUpButtonText(WMPopUpButton * bPtr, char *text)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000203{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200204 if (bPtr->caption)
205 wfree(bPtr->caption);
206 if (text)
207 bPtr->caption = wstrdup(text);
208 else
209 bPtr->caption = NULL;
210 if (bPtr->view->flags.realized) {
211 if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0) {
212 paintPopUpButton(bPtr);
213 }
214 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000215}
216
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200217void WMSetPopUpButtonItemEnabled(WMPopUpButton * bPtr, int index, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000218{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200219 WMSetMenuItemEnabled(WMGetFromArray(bPtr->items, index), (flag ? 1 : 0));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000220}
221
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200222Bool WMGetPopUpButtonItemEnabled(WMPopUpButton * bPtr, int index)
adb74c68 dan1999-05-25 02:15:44 +0000223{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200224 return WMGetMenuItemEnabled(WMGetFromArray(bPtr->items, index));
adb74c68 dan1999-05-25 02:15:44 +0000225}
226
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200227void WMSetPopUpButtonPullsDown(WMPopUpButton * bPtr, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000228{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200229 bPtr->flags.pullsDown = ((flag == 0) ? 0 : 1);
230 if (flag) {
231 bPtr->selectedItemIndex = -1;
232 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000233
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200234 if (bPtr->view->flags.mapped)
235 paintPopUpButton(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000236}
237
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200238int WMGetPopUpButtonNumberOfItems(WMPopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000239{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200240 return WMGetArrayItemCount(bPtr->items);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000241}
242
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200243char *WMGetPopUpButtonItem(WMPopUpButton * bPtr, int index)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000244{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200245 if (index >= WMGetArrayItemCount(bPtr->items) || index < 0)
246 return NULL;
eb87c409 kojima1999-10-20 03:25:06 +0000247
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200248 return WMGetMenuItemTitle(WMGetFromArray(bPtr->items, index));
eb87c409 kojima1999-10-20 03:25:06 +0000249}
250
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200251WMMenuItem *WMGetPopUpButtonMenuItem(WMPopUpButton * bPtr, int index)
252{
253 return WMGetFromArray(bPtr->items, index);
254}
eb87c409 kojima1999-10-20 03:25:06 +0000255
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200256static void paintPopUpButton(PopUpButton * bPtr)
eb87c409 kojima1999-10-20 03:25:06 +0000257{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200258 W_Screen *scr = bPtr->view->screen;
259 char *caption;
260 Pixmap pixmap;
261
262 if (bPtr->flags.pullsDown) {
263 caption = bPtr->caption;
264 } else {
265 if (bPtr->selectedItemIndex < 0) {
266 /* if no item selected, show the caption */
267 caption = bPtr->caption;
268 } else {
269 caption = WMGetPopUpButtonItem(bPtr, bPtr->selectedItemIndex);
270 }
271 }
272
273 pixmap = XCreatePixmap(scr->display, bPtr->view->window,
274 bPtr->view->size.width, bPtr->view->size.height, scr->depth);
275 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
276 bPtr->view->size.width, bPtr->view->size.height);
277
278 W_DrawRelief(scr, pixmap, 0, 0, bPtr->view->size.width, bPtr->view->size.height, WRRaised);
279
280 if (caption) {
281 W_PaintText(bPtr->view, pixmap, scr->normalFont, 6,
282 (bPtr->view->size.height - WMFontHeight(scr->normalFont)) / 2,
283 bPtr->view->size.width, WALeft,
284 bPtr->flags.enabled ? scr->black : scr->darkGray, False, caption, strlen(caption));
285 }
286
287 if (bPtr->flags.pullsDown) {
288 XCopyArea(scr->display, scr->pullDownIndicator->pixmap,
289 pixmap, scr->copyGC, 0, 0, scr->pullDownIndicator->width,
290 scr->pullDownIndicator->height,
291 bPtr->view->size.width - scr->pullDownIndicator->width - 4,
292 (bPtr->view->size.height - scr->pullDownIndicator->height) / 2);
293 } else {
294 int x, y;
295
296 x = bPtr->view->size.width - scr->popUpIndicator->width - 4;
297 y = (bPtr->view->size.height - scr->popUpIndicator->height) / 2;
298
299 XSetClipOrigin(scr->display, scr->clipGC, x, y);
300 XSetClipMask(scr->display, scr->clipGC, scr->popUpIndicator->mask);
301 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
302 scr->clipGC, 0, 0, scr->popUpIndicator->width, scr->popUpIndicator->height, x, y);
303 }
304
305 XCopyArea(scr->display, pixmap, bPtr->view->window, scr->copyGC, 0, 0,
306 bPtr->view->size.width, bPtr->view->size.height, 0, 0);
307
308 XFreePixmap(scr->display, pixmap);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000309}
310
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200311static void handleEvents(XEvent * event, void *data)
312{
313 PopUpButton *bPtr = (PopUpButton *) data;
314
315 CHECK_CLASS(data, WC_PopUpButton);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000316
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200317 switch (event->type) {
318 case Expose:
319 if (event->xexpose.count != 0)
320 break;
321 paintPopUpButton(bPtr);
322 break;
eb87c409 kojima1999-10-20 03:25:06 +0000323
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200324 case DestroyNotify:
325 destroyPopUpButton(bPtr);
326 break;
327 }
328}
329
330static void paintMenuEntry(PopUpButton * bPtr, int index, int highlight)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000331{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200332 W_Screen *scr = bPtr->view->screen;
333 int yo;
334 int width, height, itemHeight, itemCount;
335 char *title;
336
337 itemCount = WMGetArrayItemCount(bPtr->items);
338 if (index < 0 || index >= itemCount)
339 return;
340
341 itemHeight = bPtr->view->size.height;
342 width = bPtr->view->size.width;
343 height = itemHeight * itemCount;
344 yo = (itemHeight - WMFontHeight(scr->normalFont)) / 2;
345
346 if (!highlight) {
347 XClearArea(scr->display, bPtr->menuView->window, 0, index * itemHeight, width, itemHeight, False);
348 return;
349 } else if (index < 0 && bPtr->flags.pullsDown) {
350 return;
351 }
352
353 XFillRectangle(scr->display, bPtr->menuView->window, WMColorGC(scr->white),
354 1, index * itemHeight + 1, width - 3, itemHeight - 3);
355
356 title = WMGetPopUpButtonItem(bPtr, index);
357
358 W_DrawRelief(scr, bPtr->menuView->window, 0, index * itemHeight, width, itemHeight, WRRaised);
359
360 W_PaintText(bPtr->menuView, bPtr->menuView->window, scr->normalFont, 6,
361 index * itemHeight + yo, width, WALeft, scr->black, False, title, strlen(title));
362
363 if (!bPtr->flags.pullsDown && index == bPtr->selectedItemIndex) {
364 XCopyArea(scr->display, scr->popUpIndicator->pixmap,
365 bPtr->menuView->window, scr->copyGC, 0, 0,
366 scr->popUpIndicator->width, scr->popUpIndicator->height,
367 width - scr->popUpIndicator->width - 4,
368 index * itemHeight + (itemHeight - scr->popUpIndicator->height) / 2);
369 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000370}
371
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200372Pixmap makeMenuPixmap(PopUpButton * bPtr)
373{
374 Pixmap pixmap;
375 W_Screen *scr = bPtr->view->screen;
376 WMMenuItem *item;
377 WMArrayIterator iter;
378 int yo, i;
379 int width, height, itemHeight;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000380
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200381 itemHeight = bPtr->view->size.height;
382 width = bPtr->view->size.width;
383 height = itemHeight * WMGetArrayItemCount(bPtr->items);
384 yo = (itemHeight - WMFontHeight(scr->normalFont)) / 2;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000385
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200386 pixmap = XCreatePixmap(scr->display, bPtr->view->window, width, height, scr->depth);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000387
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200388 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0, width, height);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000389
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200390 i = 0;
391 WM_ITERATE_ARRAY(bPtr->items, item, iter) {
392 WMColor *color;
393 char *text;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000394
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200395 text = WMGetMenuItemTitle(item);
6830b057 dan2004-10-12 21:28:27 +0000396
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200397 W_DrawRelief(scr, pixmap, 0, i * itemHeight, width, itemHeight, WRRaised);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000398
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200399 if (!WMGetMenuItemEnabled(item))
400 color = scr->darkGray;
401 else
402 color = scr->black;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000403
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200404 W_PaintText(bPtr->menuView, pixmap, scr->normalFont, 6,
405 i * itemHeight + yo, width, WALeft, color, False, text, strlen(text));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000406
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200407 if (!bPtr->flags.pullsDown && i == bPtr->selectedItemIndex) {
408 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
409 scr->copyGC, 0, 0, scr->popUpIndicator->width,
410 scr->popUpIndicator->height,
411 width - scr->popUpIndicator->width - 4,
412 i * itemHeight + (itemHeight - scr->popUpIndicator->height) / 2);
413 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000414
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200415 i++;
416 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000417
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200418 return pixmap;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000419}
420
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200421static void resizeMenu(PopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000422{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200423 int height;
6830b057 dan2004-10-12 21:28:27 +0000424
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200425 height = WMGetArrayItemCount(bPtr->items) * bPtr->view->size.height;
426 if (height > 0)
427 W_ResizeView(bPtr->menuView, bPtr->view->size.width, height);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000428}
429
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200430static void popUpMenu(PopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000431{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200432 W_Screen *scr = bPtr->view->screen;
433 Window dummyW;
434 int x, y;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000435
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200436 if (!bPtr->flags.enabled)
437 return;
6830b057 dan2004-10-12 21:28:27 +0000438
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200439 if (!bPtr->menuView->flags.realized) {
440 W_RealizeView(bPtr->menuView);
441 resizeMenu(bPtr);
442 }
6830b057 dan2004-10-12 21:28:27 +0000443
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200444 if (WMGetArrayItemCount(bPtr->items) < 1)
445 return;
6830b057 dan2004-10-12 21:28:27 +0000446
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200447 XTranslateCoordinates(scr->display, bPtr->view->window, scr->rootWin, 0, 0, &x, &y, &dummyW);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000448
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200449 if (bPtr->flags.pullsDown) {
450 y += bPtr->view->size.height;
451 } else {
452 y -= bPtr->view->size.height * bPtr->selectedItemIndex;
453 }
454 W_MoveView(bPtr->menuView, x, y);
6830b057 dan2004-10-12 21:28:27 +0000455
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200456 XSetWindowBackgroundPixmap(scr->display, bPtr->menuView->window, makeMenuPixmap(bPtr));
457 XClearWindow(scr->display, bPtr->menuView->window);
6830b057 dan2004-10-12 21:28:27 +0000458
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200459 if (W_VIEW_WIDTH(bPtr->menuView) != W_VIEW_WIDTH(bPtr->view))
460 resizeMenu(bPtr);
6830b057 dan2004-10-12 21:28:27 +0000461
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200462 W_MapView(bPtr->menuView);
6830b057 dan2004-10-12 21:28:27 +0000463
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200464 bPtr->highlightedItem = 0;
465 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
466 paintMenuEntry(bPtr, bPtr->selectedItemIndex, True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000467}
468
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200469static void popDownMenu(PopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000470{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200471 W_UnmapView(bPtr->menuView);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000472}
473
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200474static void autoScroll(void *data)
0261c326 dan1999-01-06 15:22:33 +0000475{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200476 PopUpButton *bPtr = (PopUpButton *) data;
477 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
478 int repeat = 0;
479 int dy = 0;
480
481 if (bPtr->scrollStartY >= scrHeight - 1
482 && bPtr->menuView->pos.y + bPtr->menuView->size.height >= scrHeight - 1) {
483 repeat = 1;
484
485 if (bPtr->menuView->pos.y + bPtr->menuView->size.height - 5 <= scrHeight - 1) {
486 dy = scrHeight - 1 - (bPtr->menuView->pos.y + bPtr->menuView->size.height);
487 } else
488 dy = -5;
489
490 } else if (bPtr->scrollStartY <= 1 && bPtr->menuView->pos.y < 1) {
491 repeat = 1;
492
493 if (bPtr->menuView->pos.y + 5 > 1)
494 dy = 1 - bPtr->menuView->pos.y;
495 else
496 dy = 5;
497 }
498
499 if (repeat) {
500 int oldItem;
501
502 W_MoveView(bPtr->menuView, bPtr->menuView->pos.x, bPtr->menuView->pos.y + dy);
503
504 oldItem = bPtr->highlightedItem;
505 bPtr->highlightedItem = (bPtr->scrollStartY - bPtr->menuView->pos.y)
506 / bPtr->view->size.height;
507
508 if (oldItem != bPtr->highlightedItem) {
509 WMMenuItem *item;
510
511 paintMenuEntry(bPtr, oldItem, False);
512
513 if (bPtr->highlightedItem >= 0 && bPtr->highlightedItem < WMGetArrayItemCount(bPtr->items)) {
514 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
515 paintMenuEntry(bPtr, bPtr->highlightedItem, WMGetMenuItemEnabled(item));
516 } else {
517 bPtr->highlightedItem = -1;
518 }
519 }
520
521 bPtr->timer = WMAddTimerHandler(SCROLL_DELAY, autoScroll, bPtr);
522 } else {
523 bPtr->timer = NULL;
524 }
0261c326 dan1999-01-06 15:22:33 +0000525}
526
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200527static void wheelScrollUp(PopUpButton * bPtr)
5c761670 dan2000-04-13 21:24:28 +0000528{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200529 int testIndex = bPtr->selectedItemIndex - 1;
530
531 while (testIndex >= 0 && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
532 testIndex--;
533 if (testIndex != -1) {
534 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
535 if (bPtr->action)
536 (*bPtr->action) (bPtr, bPtr->clientData);
537 }
5c761670 dan2000-04-13 21:24:28 +0000538}
539
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200540static void wheelScrollDown(PopUpButton * bPtr)
5c761670 dan2000-04-13 21:24:28 +0000541{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200542 int itemCount = WMGetArrayItemCount(bPtr->items);
543 int testIndex = bPtr->selectedItemIndex + 1;
544
545 while (testIndex < itemCount && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
546 testIndex++;
547 if (testIndex != itemCount) {
548 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
549 if (bPtr->action)
550 (*bPtr->action) (bPtr, bPtr->clientData);
551 }
5c761670 dan2000-04-13 21:24:28 +0000552}
553
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200554static void handleActionEvents(XEvent * event, void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000555{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200556 PopUpButton *bPtr = (PopUpButton *) data;
557 int oldItem;
558 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
559
560 CHECK_CLASS(data, WC_PopUpButton);
561
562 if (WMGetArrayItemCount(bPtr->items) < 1)
563 return;
564
565 switch (event->type) {
566 /* called for menuView */
567 case Expose:
568 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
569 break;
570
571 case LeaveNotify:
572 bPtr->flags.insideMenu = 0;
573 if (bPtr->menuView->flags.mapped)
574 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
575 bPtr->highlightedItem = -1;
576 break;
577
578 case EnterNotify:
579 bPtr->flags.insideMenu = 1;
580 break;
581
582 case MotionNotify:
583 if (bPtr->flags.insideMenu) {
584 oldItem = bPtr->highlightedItem;
585 bPtr->highlightedItem = event->xmotion.y / bPtr->view->size.height;
586 if (oldItem != bPtr->highlightedItem) {
587 WMMenuItem *item;
588
589 paintMenuEntry(bPtr, oldItem, False);
590 if (bPtr->highlightedItem >= 0 &&
591 bPtr->highlightedItem < WMGetArrayItemCount(bPtr->items)) {
592 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
593 paintMenuEntry(bPtr, bPtr->highlightedItem, WMGetMenuItemEnabled(item));
594 } else {
595 bPtr->highlightedItem = -1;
596 }
597
598 }
599
600 if (event->xmotion.y_root >= scrHeight - 1 || event->xmotion.y_root <= 1) {
601 bPtr->scrollStartY = event->xmotion.y_root;
602 if (!bPtr->timer)
603 autoScroll(bPtr);
604 } else if (bPtr->timer) {
605 WMDeleteTimerHandler(bPtr->timer);
606 bPtr->timer = NULL;
607 }
608 }
609 break;
610
611 /* called for bPtr->view */
612 case ButtonPress:
613 if (!bPtr->flags.enabled)
614 break;
615
616 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
617 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
618 wheelScrollUp(bPtr);
619 }
620 break;
621 } else if (event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
622 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
623 wheelScrollDown(bPtr);
624 }
625 break;
626 }
627 popUpMenu(bPtr);
628 if (!bPtr->flags.pullsDown) {
629 bPtr->highlightedItem = bPtr->selectedItemIndex;
630 bPtr->flags.insideMenu = 1;
631 } else {
632 bPtr->highlightedItem = -1;
633 bPtr->flags.insideMenu = 0;
634 }
635 XGrabPointer(bPtr->view->screen->display, bPtr->menuView->window,
636 False, ButtonReleaseMask | ButtonMotionMask | EnterWindowMask
637 | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
638 break;
639
640 case ButtonRelease:
641 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp ||
642 event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
643 break;
644 }
645 XUngrabPointer(bPtr->view->screen->display, event->xbutton.time);
646 if (!bPtr->flags.pullsDown)
647 popDownMenu(bPtr);
648
649 if (bPtr->timer) {
650 WMDeleteTimerHandler(bPtr->timer);
651 bPtr->timer = NULL;
652 }
653
654 if (bPtr->flags.insideMenu && bPtr->highlightedItem >= 0) {
655 WMMenuItem *item;
656
657 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
658
659 if (WMGetMenuItemEnabled(item)) {
660 int i;
661 WMSetPopUpButtonSelectedItem(bPtr, bPtr->highlightedItem);
662
663 if (bPtr->flags.pullsDown) {
664 for (i = 0; i < MENU_BLINK_COUNT; i++) {
665 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
666 XSync(bPtr->view->screen->display, 0);
667 wusleep(MENU_BLINK_DELAY);
668 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
669 XSync(bPtr->view->screen->display, 0);
670 wusleep(MENU_BLINK_DELAY);
671 }
672 }
673 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
674 popDownMenu(bPtr);
675 if (bPtr->action)
676 (*bPtr->action) (bPtr, bPtr->clientData);
677 }
678 }
679 if (bPtr->menuView->flags.mapped)
680 popDownMenu(bPtr);
681 break;
682 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000683}
684
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200685static void destroyPopUpButton(PopUpButton * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000686{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200687 if (bPtr->timer) {
688 WMDeleteTimerHandler(bPtr->timer);
689 }
eb87c409 kojima1999-10-20 03:25:06 +0000690
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200691 WMFreeArray(bPtr->items);
eb87c409 kojima1999-10-20 03:25:06 +0000692
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200693 if (bPtr->caption)
694 wfree(bPtr->caption);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000695
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200696 /* have to destroy explicitly because the popup is a toplevel */
697 W_DestroyView(bPtr->menuView);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000698
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200699 wfree(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000700}