mirror of
https://github.com/gryf/wmaker.git
synced 2026-01-07 14:24:14 +01:00
0.51.1 pre snapshot. Be careful, it may be buggy. It fixes some bugs though.
This commit is contained in:
668
WPrefs.app/editmenu.c
Normal file
668
WPrefs.app/editmenu.c
Normal file
@@ -0,0 +1,668 @@
|
||||
/* editmenu.c - editable menus
|
||||
*
|
||||
* WPrefs - Window Maker Preferences Program
|
||||
*
|
||||
* Copyright (c) 1999 Alfredo K. Kojima
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <WINGsP.h>
|
||||
#include <WUtil.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "editmenu.h"
|
||||
|
||||
typedef struct W_EditMenuItem {
|
||||
W_Class widgetClass;
|
||||
WMView *view;
|
||||
|
||||
struct W_EditMenu *menu;
|
||||
|
||||
char *label;
|
||||
|
||||
WMTextField *textField;
|
||||
|
||||
struct W_EditMenu *submenu; /* if it's a cascade, NULL otherwise */
|
||||
} EditMenuItem;
|
||||
|
||||
|
||||
typedef struct W_EditMenu {
|
||||
W_Class widgetClass;
|
||||
WMView *view;
|
||||
|
||||
struct W_EditMenu *parent;
|
||||
|
||||
char *label;
|
||||
|
||||
int itemCount;
|
||||
int itemsAlloced;
|
||||
struct W_EditMenuItem **items;
|
||||
|
||||
int titleHeight;
|
||||
int itemHeight;
|
||||
|
||||
struct W_EditMenu *next;
|
||||
struct W_EditMenu *prev;
|
||||
|
||||
/* item dragging */
|
||||
int draggedItem;
|
||||
int dragX, dragY;
|
||||
} EditMenu;
|
||||
|
||||
|
||||
|
||||
/******************** WEditMenuItem ********************/
|
||||
|
||||
static void destroyEditMenuItem(WEditMenuItem *iPtr);
|
||||
static void paintEditMenuItem(WEditMenuItem *iPtr);
|
||||
|
||||
static void handleItemEvents(XEvent *event, void *data);
|
||||
static void handleItemActionEvents(XEvent *event, void *data);
|
||||
|
||||
|
||||
static W_ViewProcedureTable WEditMenuItemViewProcedures = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static W_Class EditMenuItemClass = 0;
|
||||
|
||||
|
||||
W_Class
|
||||
InitEditMenuItem(WMScreen *scr)
|
||||
{
|
||||
/* register our widget with WINGs and get our widget class ID */
|
||||
if (!EditMenuItemClass) {
|
||||
EditMenuItemClass = W_RegisterUserWidget(&WEditMenuItemViewProcedures);
|
||||
}
|
||||
|
||||
return EditMenuItemClass;
|
||||
}
|
||||
|
||||
|
||||
WEditMenuItem*
|
||||
WCreateEditMenuItem(WMWidget *parent, char *title)
|
||||
{
|
||||
WEditMenuItem *iPtr;
|
||||
|
||||
if (!EditMenuItemClass)
|
||||
InitEditMenuItem(WMWidgetScreen(parent));
|
||||
|
||||
|
||||
iPtr = wmalloc(sizeof(WEditMenuItem));
|
||||
|
||||
memset(iPtr, 0, sizeof(WEditMenuItem));
|
||||
|
||||
iPtr->widgetClass = EditMenuItemClass;
|
||||
|
||||
iPtr->view = W_CreateView(W_VIEW(parent));
|
||||
if (!iPtr->view) {
|
||||
free(iPtr);
|
||||
return NULL;
|
||||
}
|
||||
iPtr->view->self = iPtr;
|
||||
|
||||
iPtr->label = wstrdup(title);
|
||||
|
||||
WMCreateEventHandler(iPtr->view, ExposureMask|StructureNotifyMask,
|
||||
handleItemEvents, iPtr);
|
||||
|
||||
WMCreateEventHandler(iPtr->view, ButtonPressMask, handleItemActionEvents,
|
||||
iPtr);
|
||||
|
||||
return iPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
paintEditMenuItem(WEditMenuItem *iPtr)
|
||||
{
|
||||
WMScreen *scr = WMWidgetScreen(iPtr);
|
||||
WMColor *black = scr->black;
|
||||
Window win = W_VIEW(iPtr)->window;
|
||||
int w = W_VIEW(iPtr)->size.width;
|
||||
int h = WMFontHeight(scr->normalFont) + 6;
|
||||
|
||||
if (!iPtr->view->flags.realized)
|
||||
return;
|
||||
|
||||
XClearWindow(scr->display, win);
|
||||
|
||||
W_DrawRelief(scr, win, 0, 0, w+1, h, WRRaised);
|
||||
|
||||
WMDrawString(scr, win, W_GC(black), scr->normalFont, 5, 3, iPtr->label,
|
||||
strlen(iPtr->label));
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handleItemActionEvents(XEvent *event, void *data)
|
||||
{
|
||||
WEditMenuItem *iPtr = (WEditMenuItem*)data;
|
||||
|
||||
switch (event->type) {
|
||||
case ButtonPress:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
destroyEditMenuItem(WEditMenuItem *iPtr)
|
||||
{
|
||||
if (iPtr->label)
|
||||
free(iPtr->label);
|
||||
|
||||
free(iPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************** WEditMenu *******************/
|
||||
|
||||
|
||||
static WEditMenu *EditMenuList = NULL;
|
||||
|
||||
static void destroyEditMenu(WEditMenu *mPtr);
|
||||
static void paintEditMenu(WEditMenu *mPtr, int y);
|
||||
|
||||
static void updateMenuContents(WEditMenu *mPtr);
|
||||
|
||||
static void handleEvents(XEvent *event, void *data);
|
||||
static void handleActionEvents(XEvent *event, void *data);
|
||||
|
||||
static void handleItemDrag(XEvent *event, void *data);
|
||||
|
||||
|
||||
static W_ViewProcedureTable WEditMenuViewProcedures = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static W_Class EditMenuClass = 0;
|
||||
|
||||
|
||||
W_Class
|
||||
InitEditMenu(WMScreen *scr)
|
||||
{
|
||||
/* register our widget with WINGs and get our widget class ID */
|
||||
if (!EditMenuClass) {
|
||||
|
||||
EditMenuClass = W_RegisterUserWidget(&WEditMenuViewProcedures);
|
||||
}
|
||||
|
||||
return EditMenuClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
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)
|
||||
|
||||
|
||||
static void
|
||||
writeGNUstepWMAttr(WMScreen *scr, Window window, GNUstepWMAttributes *attr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
realizeObserver(void *self, WMNotification *not)
|
||||
{
|
||||
WEditMenu *menu = (WEditMenu*)self;
|
||||
GNUstepWMAttributes attribs;
|
||||
|
||||
memset(&attribs, 0, sizeof(GNUstepWMAttributes));
|
||||
attribs.flags = GSWindowStyleAttr|GSWindowLevelAttr;
|
||||
attribs.window_style = WMBorderlessWindowMask;
|
||||
attribs.window_level = WMSubmenuWindowLevel;
|
||||
|
||||
writeGNUstepWMAttr(WMWidgetScreen(menu), menu->view->window, &attribs);
|
||||
}
|
||||
|
||||
|
||||
WEditMenu*
|
||||
WCreateEditMenu(WMScreen *scr, char *title)
|
||||
{
|
||||
WEditMenu *mPtr;
|
||||
|
||||
if (!EditMenuClass)
|
||||
InitEditMenu(scr);
|
||||
|
||||
|
||||
mPtr = wmalloc(sizeof(WEditMenu));
|
||||
|
||||
memset(mPtr, 0, sizeof(WEditMenu));
|
||||
|
||||
mPtr->widgetClass = EditMenuClass;
|
||||
|
||||
mPtr->view = W_CreateTopView(scr);
|
||||
if (!mPtr->view) {
|
||||
free(mPtr);
|
||||
return NULL;
|
||||
}
|
||||
mPtr->view->self = mPtr;
|
||||
|
||||
WMAddNotificationObserver(realizeObserver, mPtr,
|
||||
WMViewRealizedNotification, mPtr->view);
|
||||
|
||||
W_SetViewBackgroundColor(mPtr->view, mPtr->view->screen->darkGray);
|
||||
|
||||
mPtr->label = wstrdup(title);
|
||||
|
||||
mPtr->itemsAlloced = 10;
|
||||
mPtr->items = wmalloc(sizeof(WEditMenuItem*)*mPtr->itemsAlloced);
|
||||
|
||||
WMCreateEventHandler(mPtr->view, ExposureMask|StructureNotifyMask,
|
||||
handleEvents, mPtr);
|
||||
|
||||
WMCreateEventHandler(mPtr->view, ButtonPressMask,handleActionEvents, mPtr);
|
||||
|
||||
updateMenuContents(mPtr);
|
||||
|
||||
|
||||
mPtr->itemHeight = WMFontHeight(scr->normalFont) + 6;
|
||||
mPtr->titleHeight = WMFontHeight(scr->boldFont) + 8;
|
||||
|
||||
mPtr->draggedItem = -1;
|
||||
|
||||
mPtr->next = EditMenuList;
|
||||
if (EditMenuList)
|
||||
EditMenuList->prev = mPtr;
|
||||
EditMenuList = mPtr;
|
||||
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
|
||||
WEditMenuItem*
|
||||
WInsertMenuItemWithTitle(WEditMenu *mPtr, char *title, int index)
|
||||
{
|
||||
WEditMenuItem *item;
|
||||
|
||||
item = WCreateEditMenuItem(mPtr, title);
|
||||
item->menu = mPtr;
|
||||
|
||||
WMCreateEventHandler(item->view, ButtonPressMask|ButtonReleaseMask
|
||||
|Button1MotionMask, handleItemDrag, item);
|
||||
|
||||
WMMapWidget(item);
|
||||
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
else if (index > mPtr->itemCount)
|
||||
index = mPtr->itemCount;
|
||||
|
||||
if (mPtr->itemCount == mPtr->itemsAlloced) {
|
||||
WEditMenuItem *newList;
|
||||
|
||||
newList = wmalloc(sizeof(WEditMenuItem*)*(mPtr->itemsAlloced+10));
|
||||
memset(newList, 0, sizeof(WEditMenuItem*)*(mPtr->itemsAlloced+10));
|
||||
|
||||
memcpy(newList, mPtr->items, mPtr->itemsAlloced*sizeof(WEditMenuItem*));
|
||||
|
||||
mPtr->itemsAlloced += 10;
|
||||
|
||||
free(mPtr->items);
|
||||
|
||||
mPtr->items = newList;
|
||||
}
|
||||
|
||||
if (index < mPtr->itemCount) {
|
||||
memmove(&mPtr->items[index+1], &mPtr->items[index],
|
||||
sizeof(WEditMenuItem*));
|
||||
mPtr->items[index] = item;
|
||||
mPtr->itemCount++;
|
||||
} else {
|
||||
mPtr->items[mPtr->itemCount++] = item;
|
||||
}
|
||||
|
||||
updateMenuContents(mPtr);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WSetMenuSubmenu(WEditMenu *mPtr, WEditMenu *submenu, WEditMenuItem *item)
|
||||
{
|
||||
item->submenu = submenu;
|
||||
submenu->parent = mPtr;
|
||||
|
||||
paintEditMenuItem(item);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WRemoveMenuItem(WEditMenu *mPtr, WEditMenuItem *item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
updateMenuContents(WEditMenu *mPtr)
|
||||
{
|
||||
WMScreen *scr = WMWidgetScreen(mPtr);
|
||||
int i;
|
||||
int newW, newH;
|
||||
int w;
|
||||
int iheight = mPtr->itemHeight;
|
||||
|
||||
newW = WMWidthOfString(scr->boldFont, mPtr->label,
|
||||
strlen(mPtr->label)) + 12 + iheight;
|
||||
|
||||
newH = mPtr->titleHeight;
|
||||
|
||||
for (i = 0; i < mPtr->itemCount; i++) {
|
||||
w = WMWidthOfString(scr->normalFont, mPtr->items[i]->label,
|
||||
strlen(mPtr->items[i]->label)) + 5;
|
||||
if (w > newW)
|
||||
newW = w;
|
||||
|
||||
W_MoveView(mPtr->items[i]->view, 0, newH);
|
||||
newH += iheight;
|
||||
}
|
||||
|
||||
newH--;
|
||||
|
||||
W_ResizeView(mPtr->view, newW, newH);
|
||||
|
||||
for (i = 0; i < mPtr->itemCount; i++) {
|
||||
W_ResizeView(mPtr->items[i]->view, newW, iheight);
|
||||
}
|
||||
|
||||
paintEditMenu(mPtr, -1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
paintMenuTitle(WEditMenu *mPtr)
|
||||
{
|
||||
WMScreen *scr = WMWidgetScreen(mPtr);
|
||||
WMColor *black = scr->black;
|
||||
WMColor *white = scr->white;
|
||||
Window win = W_VIEW(mPtr)->window;
|
||||
int w = W_VIEW(mPtr)->size.width;
|
||||
int h = mPtr->titleHeight;
|
||||
|
||||
XFillRectangle(scr->display, win, W_GC(black), 0, 0, w, h);
|
||||
|
||||
W_DrawRelief(scr, win, 0, 0, w+1, h, WRRaised);
|
||||
|
||||
WMDrawString(scr, win, W_GC(white), scr->boldFont, 5, 4, mPtr->label,
|
||||
strlen(mPtr->label));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
paintEditMenu(WEditMenu *mPtr, int y)
|
||||
{
|
||||
if (!mPtr->view->flags.realized)
|
||||
return;
|
||||
|
||||
if (y < mPtr->titleHeight || y < 0)
|
||||
paintMenuTitle(mPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handleEvents(XEvent *event, void *data)
|
||||
{
|
||||
WEditMenu *mPtr = (WEditMenu*)data;
|
||||
|
||||
|
||||
switch (event->type) {
|
||||
case Expose:
|
||||
paintEditMenu(mPtr, event->xexpose.y);
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
destroyEditMenu(mPtr);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handleActionEvents(XEvent *event, void *data)
|
||||
{
|
||||
WEditMenu *mPtr = (WEditMenu*)data;
|
||||
|
||||
switch (event->type) {
|
||||
case ButtonPress:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
editItemLabel(WEditMenuItem *iPtr)
|
||||
{
|
||||
WMTextField *tPtr;
|
||||
|
||||
tPtr = WMCreateTextField(iPtr);
|
||||
WMResizeWidget(tPtr, iPtr->view->size.width - 20,
|
||||
iPtr->view->size.height - 3);
|
||||
WMMoveWidget(tPtr, 4, 1);
|
||||
WMSetTextFieldBeveled(tPtr, False);
|
||||
WMMapWidget(tPtr);
|
||||
|
||||
WMRealizeWidget(tPtr);
|
||||
|
||||
iPtr->textField = tPtr;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handleItemDrag(XEvent *event, void *data)
|
||||
{
|
||||
WEditMenuItem *iPtr = (WEditMenuItem*)data;
|
||||
WEditMenu *mPtr = iPtr->menu;
|
||||
WMScreen *scr = WMWidgetScreen(mPtr);
|
||||
Bool done = False;
|
||||
int y;
|
||||
int i;
|
||||
int newIdx, oldIdx;
|
||||
int newY;
|
||||
|
||||
switch (event->type) {
|
||||
case ButtonPress:
|
||||
if (WMIsDoubleClick(event)) {
|
||||
|
||||
editItemLabel(iPtr);
|
||||
|
||||
} else if (event->xbutton.button == Button1) {
|
||||
mPtr->draggedItem = 1;
|
||||
mPtr->dragX = event->xbutton.x;
|
||||
mPtr->dragY = event->xbutton.y;
|
||||
}
|
||||
return;
|
||||
case ButtonRelease:
|
||||
if (event->xbutton.button == Button1) {
|
||||
mPtr->draggedItem = -1;
|
||||
}
|
||||
return;
|
||||
case MotionNotify:
|
||||
if (mPtr->draggedItem >= 0) {
|
||||
if (abs(event->xmotion.y - mPtr->dragY) > 3
|
||||
|| abs(event->xmotion.x - mPtr->dragX) > 3) {
|
||||
mPtr->draggedItem = -1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
XRaiseWindow(scr->display, iPtr->view->window);
|
||||
|
||||
XGrabPointer(scr->display, mPtr->view->window, False,
|
||||
PointerMotionMask|ButtonReleaseMask|ButtonPressMask
|
||||
|ButtonPressMask,
|
||||
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
||||
|
||||
y = iPtr->view->pos.y;
|
||||
|
||||
while (!done) {
|
||||
XEvent ev;
|
||||
|
||||
WMMaskEvent(scr->display, ButtonReleaseMask|PointerMotionMask
|
||||
|ExposureMask, &ev);
|
||||
|
||||
switch (ev.type) {
|
||||
case ButtonRelease:
|
||||
if (ev.xbutton.button == Button1)
|
||||
done = True;
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
y = ev.xbutton.y - mPtr->dragY;
|
||||
|
||||
if (y < mPtr->titleHeight)
|
||||
y = mPtr->titleHeight;
|
||||
else if (y > mPtr->view->size.height - mPtr->itemHeight + 1)
|
||||
y = mPtr->view->size.height - mPtr->itemHeight + 1;
|
||||
|
||||
W_MoveView(iPtr->view, 0, y);
|
||||
break;
|
||||
|
||||
default:
|
||||
WMHandleEvent(&ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XUngrabPointer(scr->display, CurrentTime);
|
||||
|
||||
for (oldIdx = 0; oldIdx < mPtr->itemCount; oldIdx++) {
|
||||
if (mPtr->items[oldIdx] == iPtr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(oldIdx < mPtr->itemCount);
|
||||
|
||||
newIdx = (y - mPtr->titleHeight + mPtr->itemHeight/2) / mPtr->itemHeight;
|
||||
|
||||
if (newIdx < 0)
|
||||
newIdx = 0;
|
||||
else if (newIdx >= mPtr->itemCount)
|
||||
newIdx = mPtr->itemCount - 1;
|
||||
|
||||
newY = mPtr->titleHeight + newIdx * mPtr->itemHeight;
|
||||
for (i = 0; i <= 15; i++) {
|
||||
W_MoveView(iPtr->view, 0, ((newY*i)/15 + (y - (y*i)/15)));
|
||||
XFlush(scr->display);
|
||||
}
|
||||
|
||||
if (oldIdx != newIdx) {
|
||||
WEditMenuItem *item;
|
||||
|
||||
item = mPtr->items[oldIdx];
|
||||
mPtr->items[oldIdx] = mPtr->items[newIdx];
|
||||
mPtr->items[newIdx] = item;
|
||||
|
||||
updateMenuContents(mPtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
destroyEditMenu(WEditMenu *mPtr)
|
||||
{
|
||||
WMRemoveNotificationObserver(mPtr);
|
||||
|
||||
if (mPtr->next)
|
||||
mPtr->next->prev = mPtr->prev;
|
||||
if (mPtr->prev)
|
||||
mPtr->prev->next = mPtr->next;
|
||||
if (EditMenuList == mPtr)
|
||||
EditMenuList = mPtr->next;
|
||||
|
||||
if (mPtr->label)
|
||||
free(mPtr->label);
|
||||
|
||||
if (mPtr->items)
|
||||
free(mPtr->items);
|
||||
|
||||
free(mPtr);
|
||||
}
|
||||
Reference in New Issue
Block a user