Files
wmaker/WPrefs.app/editmenu.c
T

1343 lines
30 KiB
C
Raw Normal View History

/* editmenu.c - editable menus
2004-10-12 21:28:27 +00:00
*
* WPrefs - Window Maker Preferences Program
2004-10-12 21:28:27 +00:00
*
2003-01-16 23:30:45 +00:00
* Copyright (c) 2000-2003 Alfredo K. Kojima
2004-10-12 21:28:27 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <WINGs/WINGsP.h>
#include <WINGs/WUtil.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <ctype.h>
#include "editmenu.h"
typedef struct W_EditMenuItem {
2009-08-20 00:59:40 +02:00
W_Class widgetClass;
WMView *view;
2009-08-20 00:59:40 +02:00
struct W_EditMenu *parent;
2009-08-20 00:59:40 +02:00
char *label;
WMPixmap *pixmap; /* pixmap to show at left */
2009-08-20 00:59:40 +02:00
void *data;
WMCallback *destroyData;
2009-08-20 00:59:40 +02:00
struct W_EditMenu *submenu; /* if it's a cascade, NULL otherwise */
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
struct {
unsigned isTitle:1;
unsigned isHighlighted:1;
} flags;
} EditMenuItem;
typedef struct W_EditMenu {
2009-08-20 00:59:40 +02:00
W_Class widgetClass;
WMView *view;
2009-08-20 00:59:40 +02:00
struct W_EditMenu *parent;
2009-08-20 00:59:40 +02:00
WMArray *items; /* EditMenuItem */
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
EditMenuItem *selectedItem;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMTextField *tfield;
2009-08-20 00:59:40 +02:00
WMButton *closeB;
2000-07-14 15:16:46 +00:00
2009-08-20 00:59:40 +02:00
int titleHeight;
int itemHeight;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WEditMenuDelegate *delegate;
2009-08-20 00:59:40 +02:00
WMTextFieldDelegate *tdelegate;
2000-07-16 04:05:49 +00:00
2009-08-20 00:59:40 +02:00
/* item dragging */
int draggedItem;
int dragX, dragY;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
/* only for non-standalone menu */
WMSize maxSize;
WMSize minSize;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
struct {
unsigned standalone:1;
unsigned isTitled:1;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
unsigned acceptsDrop:1;
unsigned isFactory:1;
unsigned isSelectable:1;
unsigned isEditable:1;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
unsigned isTornOff:1;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
unsigned isDragging:1;
unsigned isEditing:1;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
unsigned wasMapped:1;
} flags;
} EditMenu;
/******************** WEditMenuItem ********************/
2009-08-20 00:59:40 +02:00
static void destroyEditMenuItem(WEditMenuItem * iPtr);
static void paintEditMenuItem(WEditMenuItem * iPtr);
static void handleItemEvents(XEvent * event, void *data);
2009-08-20 00:59:40 +02:00
static void handleItemClick(XEvent * event, void *data);
static W_Class EditMenuItemClass = 0;
W_Class InitEditMenuItem(void)
{
2009-08-20 00:59:40 +02:00
/* register our widget with WINGs and get our widget class ID */
if (!EditMenuItemClass) {
EditMenuItemClass = W_RegisterUserWidget();
}
2009-08-20 00:59:40 +02:00
return EditMenuItemClass;
}
WEditMenuItem *WCreateEditMenuItem(WMWidget * parent, const char *title, Bool isTitle)
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *iPtr;
WMScreen *scr = WMWidgetScreen(parent);
2009-08-20 00:59:40 +02:00
if (!EditMenuItemClass)
InitEditMenuItem();
2009-08-20 00:59:40 +02:00
iPtr = wmalloc(sizeof(WEditMenuItem));
2009-08-20 00:59:40 +02:00
iPtr->widgetClass = EditMenuItemClass;
2009-08-20 00:59:40 +02:00
iPtr->view = W_CreateView(W_VIEW(parent));
if (!iPtr->view) {
wfree(iPtr);
return NULL;
}
iPtr->view->self = iPtr;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
iPtr->parent = parent;
2009-08-20 00:59:40 +02:00
iPtr->label = wstrdup(title);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
iPtr->flags.isTitle = isTitle;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (isTitle) {
WMSetWidgetBackgroundColor(iPtr, WMBlackColor(scr));
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMCreateEventHandler(iPtr->view, ExposureMask | StructureNotifyMask, handleItemEvents, iPtr);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMCreateEventHandler(iPtr->view, ButtonPressMask | ButtonReleaseMask
| ButtonMotionMask, handleItemClick, iPtr);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return iPtr;
}
2009-08-20 00:59:40 +02:00
char *WGetEditMenuItemTitle(WEditMenuItem * item)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
return item->label;
2000-07-14 05:48:35 +00:00
}
2009-08-20 00:59:40 +02:00
void *WGetEditMenuItemData(WEditMenuItem * item)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
return item->data;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuItemData(WEditMenuItem * item, void *data, WMCallback * destroyer)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
item->data = data;
item->destroyData = destroyer;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuItemImage(WEditMenuItem * item, WMPixmap * pixmap)
2000-07-15 22:00:41 +00:00
{
2009-08-20 00:59:40 +02:00
if (item->pixmap)
WMReleasePixmap(item->pixmap);
item->pixmap = WMRetainPixmap(pixmap);
2000-07-15 22:00:41 +00:00
}
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
static void paintEditMenuItem(WEditMenuItem * iPtr)
{
2009-08-20 00:59:40 +02:00
WMScreen *scr = WMWidgetScreen(iPtr);
WMColor *color;
Window win = W_VIEW(iPtr)->window;
int w = W_VIEW(iPtr)->size.width;
int h = W_VIEW(iPtr)->size.height;
WMFont *font = (iPtr->flags.isTitle ? scr->boldFont : scr->normalFont);
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
if (!iPtr->view->flags.realized)
return;
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
color = scr->black;
if (iPtr->flags.isTitle && !iPtr->flags.isHighlighted) {
color = scr->white;
}
2009-08-20 00:59:40 +02:00
XClearWindow(scr->display, win);
2009-08-20 00:59:40 +02:00
W_DrawRelief(scr, win, 0, 0, w + 1, h, WRRaised);
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
WMDrawString(scr, win, color, font, 5, 3, iPtr->label, strlen(iPtr->label));
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
if (iPtr->pixmap) {
WMSize size = WMGetPixmapSize(iPtr->pixmap);
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
WMDrawPixmap(iPtr->pixmap, win, w - size.width - 5, (h - size.height) / 2);
} else if (iPtr->submenu) {
/* draw the cascade indicator */
XDrawLine(scr->display, win, WMColorGC(scr->darkGray), w - 11, 6, w - 6, h / 2 - 1);
XDrawLine(scr->display, win, WMColorGC(scr->white), w - 11, h - 8, w - 6, h / 2 - 1);
XDrawLine(scr->display, win, WMColorGC(scr->black), w - 12, 6, w - 12, h - 8);
}
}
2009-08-20 00:59:40 +02:00
static void highlightItem(WEditMenuItem * iPtr, Bool high)
{
if (iPtr->flags.isTitle)
return;
iPtr->flags.isHighlighted = high;
if (high) {
WMSetWidgetBackgroundColor(iPtr, WMWhiteColor(WMWidgetScreen(iPtr)));
} else {
if (!iPtr->flags.isTitle) {
WMSetWidgetBackgroundColor(iPtr, WMGrayColor(WMWidgetScreen(iPtr)));
} else {
WMSetWidgetBackgroundColor(iPtr, WMBlackColor(WMWidgetScreen(iPtr)));
}
}
}
2009-08-20 00:59:40 +02:00
static int getItemTextWidth(WEditMenuItem * iPtr)
{
2009-08-20 00:59:40 +02:00
WMScreen *scr = WMWidgetScreen(iPtr);
if (iPtr->flags.isTitle) {
return WMWidthOfString(scr->boldFont, iPtr->label, strlen(iPtr->label));
} else {
return WMWidthOfString(scr->normalFont, iPtr->label, strlen(iPtr->label));
}
}
2009-08-20 00:59:40 +02:00
static void handleItemEvents(XEvent * event, void *data)
{
WEditMenuItem *iPtr = (WEditMenuItem *) data;
switch (event->type) {
case Expose:
if (event->xexpose.count != 0)
break;
paintEditMenuItem(iPtr);
break;
case DestroyNotify:
destroyEditMenuItem(iPtr);
break;
}
}
2009-08-20 00:59:40 +02:00
static void destroyEditMenuItem(WEditMenuItem * iPtr)
{
if (iPtr->label)
wfree(iPtr->label);
if (iPtr->data && iPtr->destroyData)
(*iPtr->destroyData) (iPtr->data);
if (iPtr->submenu)
WMDestroyWidget(iPtr->submenu);
wfree(iPtr);
}
/******************** WEditMenu *******************/
2009-08-20 00:59:40 +02:00
static void destroyEditMenu(WEditMenu * mPtr);
2009-08-20 00:59:40 +02:00
static void updateMenuContents(WEditMenu * mPtr);
2009-08-20 00:59:40 +02:00
static void handleEvents(XEvent * event, void *data);
2009-08-20 00:59:40 +02:00
static void editItemLabel(WEditMenuItem * item);
2009-08-20 00:59:40 +02:00
static void stopEditItem(WEditMenu * menu, Bool apply);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
static void deselectItem(WEditMenu * menu);
2000-07-14 05:48:35 +00:00
static W_Class EditMenuClass = 0;
W_Class InitEditMenu(void)
{
2009-08-20 00:59:40 +02:00
/* register our widget with WINGs and get our widget class ID */
if (!EditMenuClass) {
2009-08-20 00:59:40 +02:00
EditMenuClass = W_RegisterUserWidget();
}
2009-08-20 00:59:40 +02:00
return EditMenuClass;
}
typedef struct {
2009-08-20 00:59:40 +02:00
int flags;
int window_style;
int window_level;
int reserved;
Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
Pixmap close_pixmap; /* pixmap for close button */
Pixmap miniaturize_mask; /* miniaturize pixmap mask */
Pixmap close_mask; /* close pixmap mask */
int extra_flags;
} GNUstepWMAttributes;
#define GSWindowStyleAttr (1<<0)
#define GSWindowLevelAttr (1<<1)
2009-08-20 00:59:40 +02:00
static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
{
2009-08-20 00:59:40 +02:00
unsigned long data[9];
/* handle idiot compilers where array of CARD32 != struct of CARD32 */
data[0] = attr->flags;
data[1] = attr->window_style;
data[2] = attr->window_level;
data[3] = 0; /* reserved */
/* The X protocol says XIDs are 32bit */
data[4] = attr->miniaturize_pixmap;
data[5] = attr->close_pixmap;
data[6] = attr->miniaturize_mask;
data[7] = attr->close_mask;
data[8] = attr->extra_flags;
XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
32, PropModeReplace, (unsigned char *)data, 9);
}
2009-08-20 00:59:40 +02:00
static void realizeObserver(void *self, WMNotification * not)
{
2009-08-20 00:59:40 +02:00
WEditMenu *menu = (WEditMenu *) self;
GNUstepWMAttributes attribs;
2000-07-16 04:05:49 +00:00
/* Parameter not used, but tell the compiler that it is ok */
(void) not;
2009-08-20 00:59:40 +02:00
memset(&attribs, 0, sizeof(GNUstepWMAttributes));
attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr;
attribs.window_style = WMBorderlessWindowMask;
attribs.window_level = WMSubmenuWindowLevel;
2009-08-20 00:59:40 +02:00
writeGNUstepWMAttr(WMWidgetScreen(menu), menu->view->window, &attribs);
}
2009-08-20 00:59:40 +02:00
static void itemSelectObserver(void *self, WMNotification * notif)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenu *menu = (WEditMenu *) self;
WEditMenu *rmenu;
rmenu = (WEditMenu *) WMGetNotificationObject(notif);
/* check whether rmenu is from the same hierarchy of menu? */
if (rmenu == menu) {
return;
}
if (menu->selectedItem) {
if (!menu->selectedItem->submenu)
deselectItem(menu);
if (menu->flags.isEditing)
stopEditItem(menu, False);
}
2000-07-14 05:48:35 +00:00
}
static WEditMenu *makeEditMenu(WMScreen * scr, WMWidget * parent, const char *title)
{
2009-08-20 00:59:40 +02:00
WEditMenu *mPtr;
WEditMenuItem *item;
2009-08-20 00:59:40 +02:00
if (!EditMenuClass)
InitEditMenu();
2009-08-20 00:59:40 +02:00
mPtr = wmalloc(sizeof(WEditMenu));
2009-08-20 00:59:40 +02:00
mPtr->widgetClass = EditMenuClass;
2009-08-20 00:59:40 +02:00
if (parent) {
mPtr->view = W_CreateView(W_VIEW(parent));
mPtr->flags.standalone = 0;
} else {
mPtr->view = W_CreateTopView(scr);
mPtr->flags.standalone = 1;
}
if (!mPtr->view) {
wfree(mPtr);
return NULL;
}
mPtr->view->self = mPtr;
2009-08-20 00:59:40 +02:00
mPtr->flags.isSelectable = 1;
mPtr->flags.isEditable = 1;
2009-08-20 00:59:40 +02:00
W_SetViewBackgroundColor(mPtr->view, scr->darkGray);
2009-08-20 00:59:40 +02:00
WMAddNotificationObserver(realizeObserver, mPtr, WMViewRealizedNotification, mPtr->view);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
WMAddNotificationObserver(itemSelectObserver, mPtr, "EditMenuItemSelected", NULL);
2009-08-20 00:59:40 +02:00
mPtr->items = WMCreateArray(4);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMCreateEventHandler(mPtr->view, ExposureMask | StructureNotifyMask, handleEvents, mPtr);
2009-08-20 00:59:40 +02:00
if (title != NULL) {
item = WCreateEditMenuItem(mPtr, title, True);
2009-08-20 00:59:40 +02:00
WMMapWidget(item);
WMAddToArray(mPtr->items, item);
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
mPtr->flags.isTitled = 1;
}
2009-08-20 00:59:40 +02:00
mPtr->itemHeight = WMFontHeight(scr->normalFont) + 6;
mPtr->titleHeight = WMFontHeight(scr->boldFont) + 8;
2009-08-20 00:59:40 +02:00
updateMenuContents(mPtr);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return mPtr;
2000-07-10 22:49:07 +00:00
}
WEditMenu *WCreateEditMenu(WMScreen * scr, const char *title)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
return makeEditMenu(scr, NULL, title);
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
WEditMenu *WCreateEditMenuPad(WMWidget * parent)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
return makeEditMenu(WMWidgetScreen(parent), parent, NULL);
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuDelegate(WEditMenu * mPtr, WEditMenuDelegate * delegate)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
mPtr->delegate = delegate;
}
WEditMenuItem *WInsertMenuItemWithTitle(WEditMenu * mPtr, int index, const char *title)
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
2009-08-20 00:59:40 +02:00
item = WCreateEditMenuItem(mPtr, title, False);
2009-08-20 00:59:40 +02:00
WMMapWidget(item);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
if (index >= WMGetArrayItemCount(mPtr->items)) {
WMAddToArray(mPtr->items, item);
} else {
if (index < 0)
index = 0;
if (mPtr->flags.isTitled)
index++;
WMInsertInArray(mPtr->items, index, item);
}
2009-08-20 00:59:40 +02:00
updateMenuContents(mPtr);
2009-08-20 00:59:40 +02:00
return item;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
WEditMenuItem *WGetEditMenuItem(WEditMenu * mPtr, int index)
2000-07-15 22:00:41 +00:00
{
2009-08-20 00:59:40 +02:00
if (index >= WMGetArrayItemCount(mPtr->items))
return NULL;
2009-08-20 00:59:40 +02:00
return WMGetFromArray(mPtr->items, index + (mPtr->flags.isTitled ? 1 : 0));
2000-07-15 22:00:41 +00:00
}
WEditMenuItem *WAddMenuItemWithTitle(WEditMenu * mPtr, const char *title)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
return WInsertMenuItemWithTitle(mPtr, WMGetArrayItemCount(mPtr->items), title);
2000-07-10 22:49:07 +00:00
}
void WSetEditMenuTitle(WEditMenu * mPtr, const char *title)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
item = WMGetFromArray(mPtr->items, 0);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
wfree(item->label);
item->label = wstrdup(title);
2000-07-16 06:29:12 +00:00
2009-08-20 00:59:40 +02:00
updateMenuContents(mPtr);
2000-07-16 06:29:12 +00:00
2009-08-20 00:59:40 +02:00
WMRedisplayWidget(item);
2000-07-14 05:48:35 +00:00
}
2009-08-20 00:59:40 +02:00
char *WGetEditMenuTitle(WEditMenu * mPtr)
2000-07-15 22:00:41 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
item = WMGetFromArray(mPtr->items, 0);
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
return item->label;
2000-07-15 22:00:41 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuAcceptsDrop(WEditMenu * mPtr, Bool flag)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
mPtr->flags.acceptsDrop = flag;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuSubmenu(WEditMenu * mPtr, WEditMenuItem * item, WEditMenu * submenu)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
item->submenu = submenu;
submenu->parent = mPtr;
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
paintEditMenuItem(item);
2000-07-10 22:49:07 +00:00
}
WEditMenu *WGetEditMenuSubmenu(WEditMenuItem *item)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
return item->submenu;
2000-07-14 05:48:35 +00:00
}
2009-08-20 00:59:40 +02:00
void WRemoveEditMenuItem(WEditMenu * mPtr, WEditMenuItem * item)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
if (WMRemoveFromArray(mPtr->items, item) != 0) {
updateMenuContents(mPtr);
}
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuSelectable(WEditMenu * mPtr, Bool flag)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
mPtr->flags.isSelectable = flag;
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuEditable(WEditMenu * mPtr, Bool flag)
{
2009-08-20 00:59:40 +02:00
mPtr->flags.isEditable = flag;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuIsFactory(WEditMenu * mPtr, Bool flag)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
mPtr->flags.isFactory = flag;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuMinSize(WEditMenu * mPtr, WMSize size)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
mPtr->minSize.width = size.width;
mPtr->minSize.height = size.height;
}
2009-08-20 00:59:40 +02:00
void WSetEditMenuMaxSize(WEditMenu * mPtr, WMSize size)
{
2009-08-20 00:59:40 +02:00
mPtr->maxSize.width = size.width;
mPtr->maxSize.height = size.height;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
WMPoint WGetEditMenuLocationForSubmenu(WEditMenu * mPtr, WEditMenu * submenu)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WMArrayIterator iter;
WEditMenuItem *item;
int y;
if (mPtr->flags.isTitled)
y = -mPtr->titleHeight;
else
y = 0;
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
if (item->submenu == submenu) {
WMPoint pt = WMGetViewScreenPosition(mPtr->view);
return wmkpoint(pt.x + mPtr->view->size.width, pt.y + y);
}
y += W_VIEW_HEIGHT(item->view);
}
puts("invalid submenu passed to WGetEditMenuLocationForSubmenu()");
return wmkpoint(0, 0);
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static void closeMenuAction(WMWidget * w, void *data)
2000-07-14 15:16:46 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenu *menu = (WEditMenu *) data;
2000-07-14 15:16:46 +00:00
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
2009-08-20 00:59:40 +02:00
WMAddIdleHandler(WMDestroyWidget, menu->closeB);
menu->closeB = NULL;
2000-07-14 15:16:46 +00:00
2009-08-20 00:59:40 +02:00
WEditMenuHide(menu);
2000-07-14 15:16:46 +00:00
}
2009-08-20 00:59:40 +02:00
void WTearOffEditMenu(WEditMenu * menu, WEditMenu * submenu)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
submenu->flags.isTornOff = 1;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
item = (WEditMenuItem *) WMGetFromArray(submenu->items, 0);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
submenu->closeB = WMCreateCommandButton(item);
WMResizeWidget(submenu->closeB, 15, 15);
WMMoveWidget(submenu->closeB, W_VIEW(submenu)->size.width - 20, 3);
WMRealizeWidget(submenu->closeB);
WMSetButtonText(submenu->closeB, "X");
WMSetButtonAction(submenu->closeB, closeMenuAction, submenu);
WMMapWidget(submenu->closeB);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
if (menu->selectedItem && menu->selectedItem->submenu == submenu)
deselectItem(menu);
2000-07-14 05:48:35 +00:00
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
Bool WEditMenuIsTornOff(WEditMenu * mPtr)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
return mPtr->flags.isTornOff;
}
2009-08-20 00:59:40 +02:00
void WEditMenuHide(WEditMenu * mPtr)
2000-09-25 18:40:56 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
int i = 0;
if (WMWidgetIsMapped(mPtr)) {
WMUnmapWidget(mPtr);
mPtr->flags.wasMapped = 1;
} else {
mPtr->flags.wasMapped = 0;
}
while ((item = WGetEditMenuItem(mPtr, i++))) {
WEditMenu *submenu;
submenu = WGetEditMenuSubmenu(item);
2009-08-20 00:59:40 +02:00
if (submenu) {
WEditMenuHide(submenu);
}
}
2000-09-25 18:40:56 +00:00
}
2009-08-20 00:59:40 +02:00
void WEditMenuUnhide(WEditMenu * mPtr)
2000-09-25 18:40:56 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item;
int i = 0;
if (mPtr->flags.wasMapped) {
WMMapWidget(mPtr);
}
while ((item = WGetEditMenuItem(mPtr, i++))) {
WEditMenu *submenu;
submenu = WGetEditMenuSubmenu(item);
2009-08-20 00:59:40 +02:00
if (submenu) {
WEditMenuUnhide(submenu);
}
}
2000-09-25 18:40:56 +00:00
}
2009-08-20 00:59:40 +02:00
void WEditMenuShowAt(WEditMenu * menu, int x, int y)
2000-09-25 18:40:56 +00:00
{
2009-08-20 00:59:40 +02:00
XSizeHints *hints;
2000-09-25 18:40:56 +00:00
2009-08-20 00:59:40 +02:00
hints = XAllocSizeHints();
2000-09-25 18:40:56 +00:00
2009-08-20 00:59:40 +02:00
hints->flags = USPosition;
hints->x = x;
hints->y = y;
2000-09-25 18:40:56 +00:00
2009-08-20 00:59:40 +02:00
WMMoveWidget(menu, x, y);
XSetWMNormalHints(W_VIEW_DISPLAY(menu->view), W_VIEW_DRAWABLE(menu->view), hints);
XFree(hints);
2000-09-26 00:35:33 +00:00
2009-08-20 00:59:40 +02:00
WMMapWidget(menu);
2000-09-25 18:40:56 +00:00
}
2009-08-20 00:59:40 +02:00
static void updateMenuContents(WEditMenu * mPtr)
{
2009-08-20 00:59:40 +02:00
int newW, newH;
int w;
int i;
int iheight = mPtr->itemHeight;
int offs = 1;
WMArrayIterator iter;
WEditMenuItem *item;
newW = 0;
newH = offs;
i = 0;
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
w = getItemTextWidth(item);
newW = WMAX(w, newW);
WMMoveWidget(item, offs, newH);
if (i == 0 && mPtr->flags.isTitled) {
newH += mPtr->titleHeight;
} else {
newH += iheight;
}
i = 1;
}
newW += iheight + 10;
newH--;
if (mPtr->minSize.width)
newW = WMAX(newW, mPtr->minSize.width);
if (mPtr->maxSize.width)
newW = WMIN(newW, mPtr->maxSize.width);
if (mPtr->minSize.height)
newH = WMAX(newH, mPtr->minSize.height);
if (mPtr->maxSize.height)
newH = WMIN(newH, mPtr->maxSize.height);
if (W_VIEW(mPtr)->size.width == newW && mPtr->view->size.height == newH + 1)
return;
W_ResizeView(mPtr->view, newW, newH + 1);
if (mPtr->closeB)
WMMoveWidget(mPtr->closeB, newW - 20, 3);
newW -= 2 * offs;
i = 0;
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
if (i == 0 && mPtr->flags.isTitled) {
WMResizeWidget(item, newW, mPtr->titleHeight);
} else {
WMResizeWidget(item, newW, iheight);
}
i = 1;
}
}
2009-08-20 00:59:40 +02:00
static void deselectItem(WEditMenu * menu)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenu *submenu;
WEditMenuItem *item = menu->selectedItem;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
highlightItem(item, False);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (menu->delegate && menu->delegate->itemDeselected) {
(*menu->delegate->itemDeselected) (menu->delegate, menu, item);
}
submenu = item->submenu;
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
if (submenu && !WEditMenuIsTornOff(submenu)) {
WEditMenuHide(submenu);
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
menu->selectedItem = NULL;
2000-07-14 05:48:35 +00:00
}
2009-08-20 00:59:40 +02:00
static void selectItem(WEditMenu * menu, WEditMenuItem * item)
{
2009-08-20 00:59:40 +02:00
if (!menu->flags.isSelectable || menu->selectedItem == item) {
return;
}
if (menu->selectedItem) {
deselectItem(menu);
}
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
if (menu->flags.isEditing) {
stopEditItem(menu, False);
}
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
if (item && !item->flags.isTitle) {
highlightItem(item, True);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (item->submenu && !W_VIEW_MAPPED(item->submenu->view)) {
WMPoint pt;
2009-08-20 00:59:40 +02:00
pt = WGetEditMenuLocationForSubmenu(menu, item->submenu);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
WEditMenuShowAt(item->submenu, pt.x, pt.y);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
item->submenu->flags.isTornOff = 0;
}
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
WMPostNotificationName("EditMenuItemSelected", menu, NULL);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (menu->delegate && menu->delegate->itemSelected) {
(*menu->delegate->itemSelected) (menu->delegate, menu, item);
}
}
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
menu->selectedItem = item;
}
2009-08-20 00:59:40 +02:00
static void paintMenu(WEditMenu * mPtr)
{
2009-08-20 00:59:40 +02:00
W_View *view = mPtr->view;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
W_DrawRelief(W_VIEW_SCREEN(view), W_VIEW_DRAWABLE(view), 0, 0,
W_VIEW_WIDTH(view), W_VIEW_HEIGHT(view), WRSimple);
}
2009-08-20 00:59:40 +02:00
static void handleEvents(XEvent * event, void *data)
{
2009-08-20 00:59:40 +02:00
WEditMenu *mPtr = (WEditMenu *) data;
switch (event->type) {
case DestroyNotify:
destroyEditMenu(mPtr);
break;
case Expose:
if (event->xexpose.count == 0)
paintMenu(mPtr);
break;
}
}
2000-07-10 22:49:07 +00:00
/* -------------------------- Menu Label Editing ------------------------ */
2009-08-20 00:59:40 +02:00
static void stopEditItem(WEditMenu * menu, Bool apply)
{
2009-08-20 00:59:40 +02:00
if (apply) {
wfree(menu->selectedItem->label);
menu->selectedItem->label = WMGetTextFieldText(menu->tfield);
2009-08-20 00:59:40 +02:00
updateMenuContents(menu);
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
if (menu->delegate && menu->delegate->itemEdited) {
(*menu->delegate->itemEdited) (menu->delegate, menu, menu->selectedItem);
}
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
}
WMUnmapWidget(menu->tfield);
menu->flags.isEditing = 0;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static void textEndedEditing(struct WMTextFieldDelegate *self, WMNotification * notif)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenu *menu = (WEditMenu *) self->data;
2009-09-14 15:57:52 +02:00
uintptr_t reason;
2009-08-20 00:59:40 +02:00
int i;
WEditMenuItem *item;
if (!menu->flags.isEditing)
return;
2009-09-14 15:57:52 +02:00
reason = (uintptr_t)WMGetNotificationClientData(notif);
2009-08-20 00:59:40 +02:00
switch (reason) {
case WMEscapeTextMovement:
stopEditItem(menu, False);
break;
case WMReturnTextMovement:
stopEditItem(menu, True);
break;
case WMTabTextMovement:
stopEditItem(menu, True);
i = WMGetFirstInArray(menu->items, menu->selectedItem);
item = WMGetFromArray(menu->items, i + 1);
if (item != NULL) {
selectItem(menu, item);
editItemLabel(item);
}
break;
case WMBacktabTextMovement:
stopEditItem(menu, True);
i = WMGetFirstInArray(menu->items, menu->selectedItem);
item = WMGetFromArray(menu->items, i - 1);
if (item != NULL) {
selectItem(menu, item);
editItemLabel(item);
}
break;
}
}
2000-07-10 22:49:07 +00:00
static WMTextFieldDelegate textFieldDelegate = {
2009-08-20 00:59:40 +02:00
NULL,
NULL,
NULL,
textEndedEditing,
NULL,
NULL
2000-07-10 22:49:07 +00:00
};
2009-08-20 00:59:40 +02:00
static void editItemLabel(WEditMenuItem * item)
{
2009-08-20 00:59:40 +02:00
WEditMenu *mPtr = item->parent;
WMTextField *tf;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (!mPtr->flags.isEditable) {
return;
}
2009-08-20 00:59:40 +02:00
if (!mPtr->tfield) {
mPtr->tfield = WMCreateTextField(mPtr);
WMSetTextFieldBeveled(mPtr->tfield, False);
WMRealizeWidget(mPtr->tfield);
2000-07-16 04:05:49 +00:00
2009-08-20 00:59:40 +02:00
mPtr->tdelegate = wmalloc(sizeof(WMTextFieldDelegate));
memcpy(mPtr->tdelegate, &textFieldDelegate, sizeof(WMTextFieldDelegate));
2009-08-20 00:59:40 +02:00
mPtr->tdelegate->data = mPtr;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMSetTextFieldDelegate(mPtr->tfield, mPtr->tdelegate);
}
tf = mPtr->tfield;
2009-08-20 00:59:40 +02:00
WMSetTextFieldText(tf, item->label);
WMSelectTextFieldRange(tf, wmkrange(0, strlen(item->label)));
WMResizeWidget(tf, mPtr->view->size.width, mPtr->itemHeight);
WMMoveWidget(tf, 0, item->view->pos.y);
WMMapWidget(tf);
WMSetFocusToWidget(tf);
2000-07-16 04:05:49 +00:00
2009-08-20 00:59:40 +02:00
mPtr->flags.isEditing = 1;
2000-07-10 22:49:07 +00:00
}
/* -------------------------------------------------- */
2009-08-20 00:59:40 +02:00
static void slideWindow(Display * dpy, Window win, int srcX, int srcY, int dstX, int dstY)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
double x, y, dx, dy;
int i;
int iterations;
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
iterations = WMIN(25, WMAX(abs(dstX - srcX), abs(dstY - srcY)));
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
x = srcX;
y = srcY;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
dx = (double)(dstX - srcX) / iterations;
dy = (double)(dstY - srcY) / iterations;
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
for (i = 0; i <= iterations; i++) {
XMoveWindow(dpy, win, x, y);
XFlush(dpy);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
wusleep(800);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
x += dx;
y += dy;
}
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static int errorHandler(Display * d, XErrorEvent * ev)
2000-07-10 22:49:07 +00:00
{
/* Parameter not used, but tell the compiler that it is ok */
(void) d;
(void) ev;
2009-08-20 00:59:40 +02:00
/* just ignore */
return 0;
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static WEditMenu *findMenuInWindow(Display * dpy, Window toplevel, int x, int y)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
Window foo, bar;
Window *children;
unsigned nchildren;
int i;
WEditMenu *menu;
WMView *view;
int (*oldHandler) (Display *, XErrorEvent *);
view = W_GetViewForXWindow(dpy, toplevel);
if (view && view->self && WMWidgetClass(view->self) == EditMenuClass) {
menu = (WEditMenu *) view->self;
if (menu->flags.acceptsDrop) {
return menu;
}
}
if (!XQueryTree(dpy, toplevel, &foo, &bar, &children, &nchildren) || children == NULL) {
return NULL;
}
oldHandler = XSetErrorHandler(errorHandler);
/* first window that contains the point is the one */
for (i = nchildren - 1; i >= 0; i--) {
XWindowAttributes attr;
if (XGetWindowAttributes(dpy, children[i], &attr)
&& attr.map_state == IsViewable
&& x >= attr.x && y >= attr.y && x < attr.x + attr.width && y < attr.y + attr.height) {
Window tmp;
tmp = children[i];
menu = findMenuInWindow(dpy, tmp, x - attr.x, y - attr.y);
if (menu) {
XFree(children);
return menu;
}
}
}
XSetErrorHandler(oldHandler);
XFree(children);
return NULL;
2000-07-10 22:49:07 +00:00
}
static void handleDragOver(WEditMenu *menu, WMView *view, WEditMenuItem *item, int y)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WMScreen *scr = W_VIEW_SCREEN(menu->view);
Window blaw;
int mx, my;
int offs;
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view), scr->rootWin, 0, 0, &mx, &my, &blaw);
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
offs = menu->flags.standalone ? 0 : 1;
W_MoveView(view, mx + offs, y);
if (view->size.width != menu->view->size.width) {
W_ResizeView(view, menu->view->size.width - 2 * offs, menu->itemHeight);
W_ResizeView(item->view, menu->view->size.width - 2 * offs, menu->itemHeight);
}
2000-07-10 22:49:07 +00:00
}
static void handleItemDrop(WEditMenu *menu, WEditMenuItem *item, int y)
2009-08-20 00:59:40 +02:00
{
WMScreen *scr = W_VIEW_SCREEN(menu->view);
Window blaw;
int mx, my;
int index;
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view), scr->rootWin, 0, 0, &mx, &my, &blaw);
index = y - my;
if (menu->flags.isTitled) {
index -= menu->titleHeight;
}
index = (index + menu->itemHeight / 2) / menu->itemHeight;
if (index < 0)
index = 0;
if (menu->flags.isTitled) {
index++;
}
if (index > WMGetArrayItemCount(menu->items)) {
WMAddToArray(menu->items, item);
} else {
WMInsertInArray(menu->items, index, item);
}
W_ReparentView(item->view, menu->view, 0, index * menu->itemHeight);
item->parent = menu;
if (item->submenu) {
item->submenu->parent = menu;
}
updateMenuContents(menu);
}
2009-08-20 00:59:40 +02:00
static void dragMenu(WEditMenu * menu)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WMScreen *scr = W_VIEW_SCREEN(menu->view);
XEvent ev;
Bool done = False;
int dx, dy;
unsigned blau;
Window blaw;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
XGetGeometry(scr->display, W_VIEW_DRAWABLE(menu->view), &blaw, &dx, &dy, &blau, &blau, &blau, &blau);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view), scr->rootWin, dx, dy, &dx, &dy, &blaw);
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
dx = menu->dragX - dx;
dy = menu->dragY - dy;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
XGrabPointer(scr->display, scr->rootWin, False,
ButtonReleaseMask | ButtonMotionMask,
GrabModeAsync, GrabModeAsync, None, scr->defaultCursor, CurrentTime);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (menu->parent)
WTearOffEditMenu(menu->parent, menu);
2009-08-20 00:59:40 +02:00
while (!done) {
WMNextEvent(scr->display, &ev);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
switch (ev.type) {
case ButtonRelease:
done = True;
break;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
case MotionNotify:
while (XCheckMaskEvent(scr->display, ButtonMotionMask, &ev)) ;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WMMoveWidget(menu, ev.xmotion.x_root - dx, ev.xmotion.y_root - dy);
break;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
default:
WMHandleEvent(&ev);
break;
}
}
2000-07-10 22:49:07 +00:00
2009-08-20 00:59:40 +02:00
XUngrabPointer(scr->display, CurrentTime);
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static WEditMenuItem *duplicateItem(WEditMenuItem * item)
2000-07-16 04:05:49 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *nitem;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
nitem = WCreateEditMenuItem(item->parent, item->label, False);
if (item->pixmap)
nitem->pixmap = WMRetainPixmap(item->pixmap);
2000-07-16 04:05:49 +00:00
2009-08-20 00:59:40 +02:00
return nitem;
2000-07-16 04:05:49 +00:00
}
2009-08-20 00:59:40 +02:00
static WEditMenu *duplicateMenu(WEditMenu * menu)
2000-07-14 05:48:35 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenu *nmenu;
WEditMenuItem *item;
WMArrayIterator iter;
Bool first = menu->flags.isTitled;
2000-07-16 04:05:49 +00:00
2009-08-20 00:59:40 +02:00
nmenu = WCreateEditMenu(WMWidgetScreen(menu), WGetEditMenuTitle(menu));
2000-07-14 05:48:35 +00:00
2009-08-20 00:59:40 +02:00
memcpy(&nmenu->flags, &menu->flags, sizeof(menu->flags));
nmenu->delegate = menu->delegate;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
WM_ITERATE_ARRAY(menu->items, item, iter) {
WEditMenuItem *nitem;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (first) {
first = False;
continue;
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
nitem = WAddMenuItemWithTitle(nmenu, item->label);
if (item->pixmap)
WSetEditMenuItemImage(nitem, item->pixmap);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (menu->delegate && menu->delegate->itemCloned) {
(*menu->delegate->itemCloned) (menu->delegate, menu, item, nitem);
}
}
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
WMRealizeWidget(nmenu);
2000-07-15 22:00:41 +00:00
2009-08-20 00:59:40 +02:00
return nmenu;
2000-07-15 22:00:41 +00:00
}
2009-08-20 00:59:40 +02:00
static void dragItem(WEditMenu * menu, WEditMenuItem * item, Bool copy)
2000-07-10 22:49:07 +00:00
{
2010-04-12 11:46:23 +02:00
static XColor black = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue, 0 };
static XColor green = { 0x0045b045, 0x4500, 0xb000, 0x4500, DoRed | DoGreen | DoBlue, 0 };
static XColor back = { 0, 0xffff, 0xffff, 0xffff, DoRed | DoGreen | DoBlue, 0 };
2009-08-20 00:59:40 +02:00
Display *dpy = W_VIEW_DISPLAY(menu->view);
WMScreen *scr = W_VIEW_SCREEN(menu->view);
int x, y;
int dx, dy;
Bool done = False;
Window blaw;
int blai;
unsigned blau;
Window win;
WMView *dview;
int orix, oriy;
Bool enteredMenu = False;
WMSize oldSize = item->view->size;
WEditMenuItem *dritem = item;
WEditMenu *dmenu = NULL;
if (item->flags.isTitle) {
WMRaiseWidget(menu);
dragMenu(menu);
return;
}
selectItem(menu, NULL);
win = scr->rootWin;
XTranslateCoordinates(dpy, W_VIEW_DRAWABLE(item->view), win, 0, 0, &orix, &oriy, &blaw);
dview = W_CreateUnmanagedTopView(scr);
W_SetViewBackgroundColor(dview, scr->black);
W_ResizeView(dview, W_VIEW_WIDTH(item->view), W_VIEW_HEIGHT(item->view));
W_MoveView(dview, orix, oriy);
W_RealizeView(dview);
if (menu->flags.isFactory || copy) {
dritem = duplicateItem(item);
W_ReparentView(dritem->view, dview, 0, 0);
WMResizeWidget(dritem, oldSize.width, oldSize.height);
WMRealizeWidget(dritem);
WMMapWidget(dritem);
} else {
W_ReparentView(item->view, dview, 0, 0);
}
W_MapView(dview);
dx = menu->dragX - orix;
dy = menu->dragY - oriy;
XGrabPointer(dpy, scr->rootWin, False,
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
GrabModeAsync, GrabModeAsync, None, scr->defaultCursor, CurrentTime);
if (menu->flags.acceptsDrop)
XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
while (!done) {
XEvent ev;
WMNextEvent(dpy, &ev);
switch (ev.type) {
case MotionNotify:
while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
XQueryPointer(dpy, win, &blaw, &blaw, &blai, &blai, &x, &y, &blau);
dmenu = findMenuInWindow(dpy, win, x, y);
if (dmenu) {
handleDragOver(dmenu, dview, dritem, y - dy);
2009-08-20 00:59:40 +02:00
if (!enteredMenu) {
enteredMenu = True;
XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
}
} else {
if (enteredMenu) {
W_ResizeView(dview, oldSize.width, oldSize.height);
W_ResizeView(dritem->view, oldSize.width, oldSize.height);
enteredMenu = False;
XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
}
W_MoveView(dview, x - dx, y - dy);
}
break;
case ButtonRelease:
done = True;
break;
default:
WMHandleEvent(&ev);
break;
}
}
XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
XUngrabPointer(dpy, CurrentTime);
if (!enteredMenu) {
Bool rem = True;
if (!menu->flags.isFactory && !copy) {
W_UnmapView(dview);
if (menu->delegate && menu->delegate->shouldRemoveItem) {
rem = (*menu->delegate->shouldRemoveItem) (menu->delegate, menu, item);
}
W_MapView(dview);
}
if (!rem || menu->flags.isFactory || copy) {
slideWindow(dpy, W_VIEW_DRAWABLE(dview), x - dx, y - dy, orix, oriy);
if (!menu->flags.isFactory && !copy) {
WRemoveEditMenuItem(menu, dritem);
handleItemDrop(dmenu ? dmenu : menu, dritem, oriy);
2009-08-20 00:59:40 +02:00
}
} else {
WRemoveEditMenuItem(menu, dritem);
}
} else {
WRemoveEditMenuItem(menu, dritem);
if (menu->delegate && menu->delegate->itemCloned && (menu->flags.isFactory || copy)) {
(*menu->delegate->itemCloned) (menu->delegate, menu, item, dritem);
}
handleItemDrop(dmenu, dritem, y - dy);
2009-08-20 00:59:40 +02:00
if (item->submenu && (menu->flags.isFactory || copy)) {
WEditMenu *submenu;
submenu = duplicateMenu(item->submenu);
WSetEditMenuSubmenu(dmenu, dritem, submenu);
}
}
/* can't destroy now because we're being called from
* the event handler of the item. and destroying now,
* would mean destroying the item too in some cases.
*/
WMAddIdleHandler((WMCallback *) W_DestroyView, dview);
2000-07-10 22:49:07 +00:00
}
2009-08-20 00:59:40 +02:00
static void handleItemClick(XEvent * event, void *data)
2000-07-10 22:49:07 +00:00
{
2009-08-20 00:59:40 +02:00
WEditMenuItem *item = (WEditMenuItem *) data;
WEditMenu *menu = item->parent;
switch (event->type) {
case ButtonPress:
selectItem(menu, item);
if (WMIsDoubleClick(event)) {
editItemLabel(item);
}
menu->flags.isDragging = 1;
menu->dragX = event->xbutton.x_root;
menu->dragY = event->xbutton.y_root;
break;
case ButtonRelease:
menu->flags.isDragging = 0;
break;
case MotionNotify:
if (menu->flags.isDragging) {
if (abs(event->xbutton.x_root - menu->dragX) > 5
|| abs(event->xbutton.y_root - menu->dragY) > 5) {
menu->flags.isDragging = 0;
dragItem(menu, item, event->xbutton.state & ControlMask);
}
}
break;
}
}
2009-08-20 00:59:40 +02:00
static void destroyEditMenu(WEditMenu * mPtr)
{
2009-08-20 00:59:40 +02:00
WMRemoveNotificationObserver(mPtr);
2009-08-20 00:59:40 +02:00
WMFreeArray(mPtr->items);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
wfree(mPtr->tdelegate);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
wfree(mPtr);
}