mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-21 05:18:06 +01:00
The color well contains two views: view, consisting of the outer "button", and colorView, consisting of the color itself. Previously, only clicking on view would bring up the corresponding color panel, resulting in nonintuitive behavior.
419 lines
10 KiB
C
419 lines
10 KiB
C
|
|
#include "WINGsP.h"
|
|
|
|
#define XDND_COLOR_DATA_TYPE "application/X-color"
|
|
|
|
char *WMColorWellDidChangeNotification = "WMColorWellDidChangeNotification";
|
|
|
|
typedef struct W_ColorWell {
|
|
W_Class widgetClass;
|
|
WMView *view;
|
|
|
|
WMView *colorView;
|
|
|
|
WMColor *color;
|
|
|
|
WMAction *action;
|
|
void *clientData;
|
|
|
|
WMPoint ipoint;
|
|
|
|
struct {
|
|
unsigned int active:1;
|
|
unsigned int bordered:1;
|
|
} flags;
|
|
|
|
WMArray *xdndTypes;
|
|
} ColorWell;
|
|
|
|
static char *_ColorWellActivatedNotification = "_ColorWellActivatedNotification";
|
|
|
|
static void destroyColorWell(ColorWell * cPtr);
|
|
static void paintColorWell(ColorWell * cPtr);
|
|
|
|
static void handleEvents(XEvent * event, void *data);
|
|
|
|
static void handleDragEvents(XEvent * event, void *data);
|
|
|
|
static void handleActionEvents(XEvent * event, void *data);
|
|
|
|
static void willResizeColorWell(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height);
|
|
|
|
W_ViewDelegate _ColorWellViewDelegate = {
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
willResizeColorWell
|
|
};
|
|
|
|
static WMArray *dropDataTypes(WMView * self);
|
|
static WMDragOperationType wantedDropOperation(WMView * self);
|
|
static Bool acceptDropOperation(WMView * self, WMDragOperationType operation);
|
|
static WMData *fetchDragData(WMView * self, char *type);
|
|
|
|
static WMDragSourceProcs _DragSourceProcs = {
|
|
dropDataTypes,
|
|
wantedDropOperation,
|
|
NULL,
|
|
acceptDropOperation,
|
|
NULL,
|
|
NULL,
|
|
fetchDragData
|
|
};
|
|
|
|
static WMArray *requiredDataTypes(WMView * self,
|
|
WMDragOperationType requestedOperation, WMArray * sourceDataTypes);
|
|
static WMDragOperationType allowedOperation(WMView * self,
|
|
WMDragOperationType requestedOperation, WMArray * sourceDataTypes);
|
|
static void performDragOperation(WMView * self, WMArray * dropDatas,
|
|
WMArray * operationsList, WMPoint * dropLocation);
|
|
|
|
static WMDragDestinationProcs _DragDestinationProcs = {
|
|
NULL,
|
|
requiredDataTypes,
|
|
allowedOperation,
|
|
NULL,
|
|
performDragOperation,
|
|
NULL
|
|
};
|
|
|
|
#define DEFAULT_WIDTH 60
|
|
#define DEFAULT_HEIGHT 30
|
|
#define DEFAULT_BORDER_WIDTH 6
|
|
|
|
#define MIN_WIDTH 16
|
|
#define MIN_HEIGHT 8
|
|
|
|
static void colorChangedObserver(void *data, WMNotification * notification)
|
|
{
|
|
WMColorPanel *panel = (WMColorPanel *) WMGetNotificationObject(notification);
|
|
WMColorWell *cPtr = (WMColorWell *) data;
|
|
WMColor *color;
|
|
|
|
if (!cPtr->flags.active)
|
|
return;
|
|
|
|
color = WMGetColorPanelColor(panel);
|
|
|
|
WMSetColorWellColor(cPtr, color);
|
|
WMPostNotificationName(WMColorWellDidChangeNotification, cPtr, NULL);
|
|
}
|
|
|
|
static void updateColorCallback(void *self, void *data)
|
|
{
|
|
WMColorPanel *panel = (WMColorPanel *) self;
|
|
WMColorWell *cPtr = (ColorWell *) data;
|
|
WMColor *color;
|
|
|
|
color = WMGetColorPanelColor(panel);
|
|
WMSetColorWellColor(cPtr, color);
|
|
WMPostNotificationName(WMColorWellDidChangeNotification, cPtr, NULL);
|
|
}
|
|
|
|
static WMArray *getXdndTypeArray(void)
|
|
{
|
|
WMArray *types = WMCreateArray(1);
|
|
WMAddToArray(types, XDND_COLOR_DATA_TYPE);
|
|
return types;
|
|
}
|
|
|
|
WMColorWell *WMCreateColorWell(WMWidget * parent)
|
|
{
|
|
ColorWell *cPtr;
|
|
|
|
cPtr = wmalloc(sizeof(ColorWell));
|
|
|
|
cPtr->widgetClass = WC_ColorWell;
|
|
|
|
cPtr->view = W_CreateView(W_VIEW(parent));
|
|
if (!cPtr->view) {
|
|
wfree(cPtr);
|
|
return NULL;
|
|
}
|
|
cPtr->view->self = cPtr;
|
|
|
|
cPtr->view->delegate = &_ColorWellViewDelegate;
|
|
|
|
cPtr->colorView = W_CreateView(cPtr->view);
|
|
if (!cPtr->colorView) {
|
|
W_DestroyView(cPtr->view);
|
|
wfree(cPtr);
|
|
return NULL;
|
|
}
|
|
cPtr->colorView->self = cPtr;
|
|
|
|
WMCreateEventHandler(cPtr->view, ExposureMask | StructureNotifyMask
|
|
| ClientMessageMask, handleEvents, cPtr);
|
|
|
|
WMCreateEventHandler(cPtr->colorView, ExposureMask, handleEvents, cPtr);
|
|
|
|
WMCreateDragHandler(cPtr->colorView, handleDragEvents, cPtr);
|
|
|
|
WMCreateEventHandler(cPtr->view, ButtonPressMask, handleActionEvents, cPtr);
|
|
WMCreateEventHandler(cPtr->colorView, ButtonPressMask, handleActionEvents, cPtr);
|
|
|
|
cPtr->colorView->flags.mapWhenRealized = 1;
|
|
|
|
cPtr->flags.bordered = 1;
|
|
|
|
W_ResizeView(cPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
|
|
|
cPtr->color = WMBlackColor(WMWidgetScreen(cPtr));
|
|
|
|
WMAddNotificationObserver(colorChangedObserver, cPtr, WMColorPanelColorChangedNotification, NULL);
|
|
|
|
WMSetViewDragSourceProcs(cPtr->colorView, &_DragSourceProcs);
|
|
WMSetViewDragDestinationProcs(cPtr->colorView, &_DragDestinationProcs);
|
|
|
|
cPtr->xdndTypes = getXdndTypeArray();
|
|
WMRegisterViewForDraggedTypes(cPtr->colorView, cPtr->xdndTypes);
|
|
|
|
return cPtr;
|
|
}
|
|
|
|
void WMSetColorWellColor(WMColorWell * cPtr, WMColor * color)
|
|
{
|
|
if (cPtr->color)
|
|
WMReleaseColor(cPtr->color);
|
|
|
|
cPtr->color = WMRetainColor(color);
|
|
|
|
if (cPtr->colorView->flags.realized && cPtr->colorView->flags.mapped)
|
|
paintColorWell(cPtr);
|
|
}
|
|
|
|
WMColor *WMGetColorWellColor(WMColorWell * cPtr)
|
|
{
|
|
return cPtr->color;
|
|
}
|
|
|
|
void WSetColorWellBordered(WMColorWell * cPtr, Bool flag)
|
|
{
|
|
flag = ((flag == 0) ? 0 : 1);
|
|
if (cPtr->flags.bordered != flag) {
|
|
cPtr->flags.bordered = flag;
|
|
W_ResizeView(cPtr->view, cPtr->view->size.width, cPtr->view->size.height);
|
|
}
|
|
}
|
|
|
|
static void willResizeColorWell(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
|
|
{
|
|
WMColorWell *cPtr = (WMColorWell *) view->self;
|
|
int bw;
|
|
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) self;
|
|
|
|
if (cPtr->flags.bordered) {
|
|
|
|
if (*width < MIN_WIDTH)
|
|
*width = MIN_WIDTH;
|
|
if (*height < MIN_HEIGHT)
|
|
*height = MIN_HEIGHT;
|
|
|
|
bw = (int)((float)WMIN(*width, *height) * 0.24);
|
|
|
|
W_ResizeView(cPtr->colorView, *width - 2 * bw, *height - 2 * bw);
|
|
|
|
if (cPtr->colorView->pos.x != bw || cPtr->colorView->pos.y != bw)
|
|
W_MoveView(cPtr->colorView, bw, bw);
|
|
} else {
|
|
W_ResizeView(cPtr->colorView, *width, *height);
|
|
|
|
W_MoveView(cPtr->colorView, 0, 0);
|
|
}
|
|
}
|
|
|
|
static void paintColorWell(ColorWell * cPtr)
|
|
{
|
|
W_Screen *scr = cPtr->view->screen;
|
|
|
|
W_DrawRelief(scr, cPtr->view->window, 0, 0, cPtr->view->size.width, cPtr->view->size.height, WRRaised);
|
|
|
|
W_DrawRelief(scr, cPtr->colorView->window, 0, 0,
|
|
cPtr->colorView->size.width, cPtr->colorView->size.height, WRSunken);
|
|
|
|
if (cPtr->color)
|
|
WMPaintColorSwatch(cPtr->color, cPtr->colorView->window,
|
|
2, 2, cPtr->colorView->size.width - 4, cPtr->colorView->size.height - 4);
|
|
}
|
|
|
|
static void handleEvents(XEvent * event, void *data)
|
|
{
|
|
ColorWell *cPtr = (ColorWell *) data;
|
|
|
|
CHECK_CLASS(data, WC_ColorWell);
|
|
|
|
switch (event->type) {
|
|
case Expose:
|
|
if (event->xexpose.count != 0)
|
|
break;
|
|
paintColorWell(cPtr);
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
destroyColorWell(cPtr);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
static WMArray *dropDataTypes(WMView * self)
|
|
{
|
|
return ((ColorWell *) self->self)->xdndTypes;
|
|
}
|
|
|
|
static WMDragOperationType wantedDropOperation(WMView * self)
|
|
{
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) self;
|
|
|
|
return WDOperationCopy;
|
|
}
|
|
|
|
static Bool acceptDropOperation(WMView * self, WMDragOperationType operation)
|
|
{
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) self;
|
|
|
|
return (operation == WDOperationCopy);
|
|
}
|
|
|
|
static WMData *fetchDragData(WMView * self, char *type)
|
|
{
|
|
char *color = WMGetColorRGBDescription(((WMColorWell *) self->self)->color);
|
|
WMData *data;
|
|
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) type;
|
|
|
|
data = WMCreateDataWithBytes(color, strlen(color) + 1);
|
|
wfree(color);
|
|
|
|
return data;
|
|
}
|
|
|
|
static WMPixmap *makeDragPixmap(WMColorWell * cPtr)
|
|
{
|
|
WMScreen *scr = cPtr->view->screen;
|
|
Pixmap pix;
|
|
|
|
pix = XCreatePixmap(scr->display, W_DRAWABLE(scr), 16, 16, scr->depth);
|
|
|
|
XFillRectangle(scr->display, pix, WMColorGC(cPtr->color), 0, 0, 15, 15);
|
|
|
|
XDrawRectangle(scr->display, pix, WMColorGC(scr->black), 0, 0, 15, 15);
|
|
|
|
return WMCreatePixmapFromXPixmaps(scr, pix, None, 16, 16, scr->depth);
|
|
}
|
|
|
|
static void handleDragEvents(XEvent * event, void *data)
|
|
{
|
|
WMColorWell *cPtr = (ColorWell *) data;
|
|
|
|
if (event->type == ButtonPress && event->xbutton.button == Button1) {
|
|
/* initialise drag icon */
|
|
WMSetViewDragImage(cPtr->colorView, makeDragPixmap(cPtr));
|
|
}
|
|
|
|
WMDragImageFromView(cPtr->colorView, event);
|
|
}
|
|
|
|
static void handleActionEvents(XEvent * event, void *data)
|
|
{
|
|
WMColorWell *cPtr = (ColorWell *) data;
|
|
WMScreen *scr = WMWidgetScreen(cPtr);
|
|
WMColorPanel *cpanel;
|
|
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) event;
|
|
|
|
if (cPtr->flags.active)
|
|
W_SetViewBackgroundColor(cPtr->view, scr->gray);
|
|
else
|
|
W_SetViewBackgroundColor(cPtr->view, scr->white);
|
|
paintColorWell(cPtr);
|
|
|
|
cPtr->flags.active ^= 1;
|
|
|
|
if (cPtr->flags.active) {
|
|
WMPostNotificationName(_ColorWellActivatedNotification, cPtr, NULL);
|
|
}
|
|
cpanel = WMGetColorPanel(scr);
|
|
|
|
WMSetColorPanelAction(cpanel, updateColorCallback, cPtr);
|
|
|
|
if (cPtr->color)
|
|
WMSetColorPanelColor(cpanel, cPtr->color);
|
|
WMShowColorPanel(cpanel);
|
|
}
|
|
|
|
static void destroyColorWell(ColorWell * cPtr)
|
|
{
|
|
WMRemoveNotificationObserver(cPtr);
|
|
|
|
if (cPtr->color)
|
|
WMReleaseColor(cPtr->color);
|
|
|
|
WMFreeArray(cPtr->xdndTypes);
|
|
|
|
wfree(cPtr);
|
|
}
|
|
|
|
static Bool dropIsOk(WMDragOperationType request, WMArray * sourceDataTypes)
|
|
{
|
|
WMArrayIterator iter;
|
|
char *type;
|
|
|
|
if (request == WDOperationCopy) {
|
|
WM_ITERATE_ARRAY(sourceDataTypes, type, iter) {
|
|
if (type != NULL && strcmp(type, XDND_COLOR_DATA_TYPE) == 0) {
|
|
return True;
|
|
}
|
|
}
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static WMArray *requiredDataTypes(WMView * self, WMDragOperationType request, WMArray * sourceDataTypes)
|
|
{
|
|
if (dropIsOk(request, sourceDataTypes))
|
|
return ((ColorWell *) self->self)->xdndTypes;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static WMDragOperationType allowedOperation(WMView * self, WMDragOperationType request, WMArray * sourceDataTypes)
|
|
{
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) self;
|
|
|
|
if (dropIsOk(request, sourceDataTypes))
|
|
return WDOperationCopy;
|
|
else
|
|
return WDOperationNone;
|
|
}
|
|
|
|
static void performDragOperation(WMView * self, WMArray * dropData, WMArray * operations, WMPoint * dropLocation)
|
|
{
|
|
char *colorName;
|
|
WMColor *color;
|
|
WMData *data;
|
|
|
|
/* Parameter not used, but tell the compiler that it is ok */
|
|
(void) operations;
|
|
(void) dropLocation;
|
|
|
|
/* only one operation requested (WDOperationCopy) implies only one data */
|
|
data = (WMData *) WMGetFromArray(dropData, 0);
|
|
|
|
if (data != NULL) {
|
|
colorName = (char *)WMDataBytes(data);
|
|
color = WMCreateNamedColor(W_VIEW_SCREEN(self), colorName, True);
|
|
WMSetColorWellColor(self->self, color);
|
|
WMReleaseColor(color);
|
|
}
|
|
}
|