| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % % |
| % W W IIIII DDDD GGGG EEEEE TTTTT % |
| % W W I D D G E T % |
| % W W W I D D G GG EEE T % |
| % WW WW I D D G G E T % |
| % W W IIIII DDDD GGGG EEEEE T % |
| % % |
| % % |
| % MagickCore X11 User Interface Methods % |
| % % |
| % Software Design % |
| % John Cristy % |
| % September 1993 % |
| % % |
| % % |
| % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % |
| % dedicated to making software imaging solutions freely available. % |
| % % |
| % You may not use this file except in compliance with the License. You may % |
| % obtain a copy of the License at % |
| % % |
| % http://www.imagemagick.org/script/license.php % |
| % % |
| % Unless required by applicable law or agreed to in writing, software % |
| % distributed under the License is distributed on an "AS IS" BASIS, % |
| % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
| % See the License for the specific language governing permissions and % |
| % limitations under the License. % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % |
| */ |
| |
| /* |
| Include declarations. |
| */ |
| #include "magick/studio.h" |
| #include "magick/color.h" |
| #include "magick/color-private.h" |
| #include "magick/exception.h" |
| #include "magick/exception-private.h" |
| #include "magick/image.h" |
| #include "magick/magick.h" |
| #include "magick/memory_.h" |
| #include "magick/PreRvIcccm.h" |
| #include "magick/string_.h" |
| #include "magick/token.h" |
| #include "magick/utility.h" |
| #include "magick/xwindow-private.h" |
| #include "magick/widget.h" |
| |
| #if defined(MAGICKCORE_X11_DELEGATE) |
| |
| /* |
| Define declarations. |
| */ |
| #define AreaIsActive(matte_info,position) ( \ |
| ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \ |
| (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \ |
| ? MagickTrue : MagickFalse) |
| #define Extent(s) ((int) strlen(s)) |
| #define MatteIsActive(matte_info,position) ( \ |
| ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \ |
| (position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \ |
| (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) && \ |
| (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \ |
| ? MagickTrue : MagickFalse) |
| #define MaxTextWidth ((unsigned int) (255*XTextWidth(font_info,"_",1))) |
| #define MinTextWidth (26*XTextWidth(font_info,"_",1)) |
| #define QuantumMargin MagickMax(font_info->max_bounds.width,12) |
| #define WidgetTextWidth(font_info,text) \ |
| ((unsigned int) XTextWidth(font_info,text,Extent(text))) |
| #define WindowIsActive(window_info,position) ( \ |
| ((position.x >= 0) && (position.y >= 0) && \ |
| (position.x < (int) window_info.width) && \ |
| (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse) |
| |
| /* |
| Enum declarations. |
| */ |
| typedef enum |
| { |
| ControlState = 0x0001, |
| InactiveWidgetState = 0x0004, |
| JumpListState = 0x0008, |
| RedrawActionState = 0x0010, |
| RedrawListState = 0x0020, |
| RedrawWidgetState = 0x0040, |
| UpdateListState = 0x0100 |
| } WidgetState; |
| |
| /* |
| Typedef declarations. |
| */ |
| typedef struct _XWidgetInfo |
| { |
| char |
| *cursor, |
| *text, |
| *marker; |
| |
| int |
| id; |
| |
| unsigned int |
| bevel_width, |
| width, |
| height; |
| |
| int |
| x, |
| y, |
| min_y, |
| max_y; |
| |
| MagickStatusType |
| raised, |
| active, |
| center, |
| trough, |
| highlight; |
| } XWidgetInfo; |
| |
| /* |
| Variable declarations. |
| */ |
| static XWidgetInfo |
| monitor_info = |
| { |
| (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, |
| MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse |
| }, |
| submenu_info = |
| { |
| (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, |
| MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse |
| }, |
| *selection_info = (XWidgetInfo *) NULL, |
| toggle_info = |
| { |
| (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0, |
| MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse |
| }; |
| |
| /* |
| Constant declarations. |
| */ |
| static const int |
| BorderOffset = 4, |
| DoubleClick = 250; |
| |
| /* |
| Method prototypes. |
| */ |
| static void |
| XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *), |
| XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType), |
| XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType), |
| XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType); |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % D e s t r o y X W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % DestroyXWidget() destroys resources associated with the X widget. |
| % |
| % The format of the DestroyXWidget method is: |
| % |
| % void DestroyXWidget() |
| % |
| % A description of each parameter follows: |
| % |
| */ |
| MagickExport void DestroyXWidget(void) |
| { |
| if (selection_info != (XWidgetInfo *) NULL) |
| selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w B e v e l % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawBevel() "sets off" an area with a highlighted upper and left bevel and |
| % a shadowed lower and right bevel. The highlighted and shadowed bevels |
| % create a 3-D effect. |
| % |
| % The format of the XDrawBevel function is: |
| % |
| % XDrawBevel(display,window_info,bevel_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o bevel_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the bevel. |
| % |
| */ |
| static void XDrawBevel(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *bevel_info) |
| { |
| int |
| x1, |
| x2, |
| y1, |
| y2; |
| |
| unsigned int |
| bevel_width; |
| |
| XPoint |
| points[6]; |
| |
| /* |
| Draw upper and left beveled border. |
| */ |
| x1=bevel_info->x; |
| y1=bevel_info->y+bevel_info->height; |
| x2=bevel_info->x+bevel_info->width; |
| y2=bevel_info->y; |
| bevel_width=bevel_info->bevel_width; |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x1; |
| points[1].y=y2; |
| points[2].x=x2; |
| points[2].y=y2; |
| points[3].x=x2+bevel_width; |
| points[3].y=y2-bevel_width; |
| points[4].x=x1-bevel_width; |
| points[4].y=y2-bevel_width; |
| points[5].x=x1-bevel_width; |
| points[5].y=y1+bevel_width; |
| XSetBevelColor(display,window_info,bevel_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,6,Complex,CoordModeOrigin); |
| /* |
| Draw lower and right beveled border. |
| */ |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y1; |
| points[2].x=x2; |
| points[2].y=y2; |
| points[3].x=x2+bevel_width; |
| points[3].y=y2-bevel_width; |
| points[4].x=x2+bevel_width; |
| points[4].y=y1+bevel_width; |
| points[5].x=x1-bevel_width; |
| points[5].y=y1+bevel_width; |
| XSetBevelColor(display,window_info,!bevel_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,6,Complex,CoordModeOrigin); |
| (void) XSetFillStyle(display,window_info->widget_context,FillSolid); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w B e v e l e d B u t t o n % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawBeveledButton() draws a button with a highlighted upper and left bevel |
| % and a shadowed lower and right bevel. The highlighted and shadowed bevels |
| % create a 3-D effect. |
| % |
| % The format of the XDrawBeveledButton function is: |
| % |
| % XDrawBeveledButton(display,window_info,button_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o button_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the button. |
| % |
| */ |
| |
| static inline int MagickAbsoluteValue(const int x) |
| { |
| if (x < 0) |
| return(-x); |
| return(x); |
| } |
| |
| static inline int MagickMax(const int x,const int y) |
| { |
| if (x > y) |
| return(x); |
| return(y); |
| } |
| |
| static inline int MagickMin(const int x,const int y) |
| { |
| if (x < y) |
| return(x); |
| return(y); |
| } |
| |
| static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *button_info) |
| { |
| int |
| x, |
| y; |
| |
| unsigned int |
| width; |
| |
| XFontStruct |
| *font_info; |
| |
| XRectangle |
| crop_info; |
| |
| /* |
| Draw matte. |
| */ |
| XDrawBevel(display,window_info,button_info); |
| XSetMatteColor(display,window_info,button_info->raised); |
| (void) XFillRectangle(display,window_info->id,window_info->widget_context, |
| button_info->x,button_info->y,button_info->width,button_info->height); |
| x=button_info->x-button_info->bevel_width-1; |
| y=button_info->y-button_info->bevel_width-1; |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->trough_color.pixel); |
| if (button_info->raised || (window_info->depth == 1)) |
| (void) XDrawRectangle(display,window_info->id,window_info->widget_context, |
| x,y,button_info->width+(button_info->bevel_width << 1)+1, |
| button_info->height+(button_info->bevel_width << 1)+1); |
| if (button_info->text == (char *) NULL) |
| return; |
| /* |
| Set cropping region. |
| */ |
| crop_info.width=(unsigned short) button_info->width; |
| crop_info.height=(unsigned short) button_info->height; |
| crop_info.x=button_info->x; |
| crop_info.y=button_info->y; |
| /* |
| Draw text. |
| */ |
| font_info=window_info->font_info; |
| width=WidgetTextWidth(font_info,button_info->text); |
| x=button_info->x+(QuantumMargin >> 1); |
| if (button_info->center) |
| x=button_info->x+(button_info->width >> 1)-(width >> 1); |
| y=button_info->y+((button_info->height- |
| (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent; |
| if ((int) button_info->width == (QuantumMargin >> 1)) |
| { |
| /* |
| Option button-- write label to right of button. |
| */ |
| XSetTextColor(display,window_info,MagickTrue); |
| x=button_info->x+button_info->width+button_info->bevel_width+ |
| (QuantumMargin >> 1); |
| (void) XDrawString(display,window_info->id,window_info->widget_context, |
| x,y,button_info->text,Extent(button_info->text)); |
| return; |
| } |
| (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info, |
| 1,Unsorted); |
| XSetTextColor(display,window_info,button_info->raised); |
| (void) XDrawString(display,window_info->id,window_info->widget_context,x,y, |
| button_info->text,Extent(button_info->text)); |
| (void) XSetClipMask(display,window_info->widget_context,None); |
| if (button_info->raised == MagickFalse) |
| XDelay(display,SuspendTime << 2); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w B e v e l e d M a t t e % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and |
| % a highlighted lower and right bevel. The highlighted and shadowed bevels |
| % create a 3-D effect. |
| % |
| % The format of the XDrawBeveledMatte function is: |
| % |
| % XDrawBeveledMatte(display,window_info,matte_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o matte_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the matte. |
| % |
| */ |
| static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *matte_info) |
| { |
| /* |
| Draw matte. |
| */ |
| XDrawBevel(display,window_info,matte_info); |
| XDrawMatte(display,window_info,matte_info); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w M a t t e % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawMatte() fills a rectangular area with the matte color. |
| % |
| % The format of the XDrawMatte function is: |
| % |
| % XDrawMatte(display,window_info,matte_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o matte_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the matte. |
| % |
| */ |
| static void XDrawMatte(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *matte_info) |
| { |
| /* |
| Draw matte. |
| */ |
| if ((matte_info->trough == MagickFalse) || (window_info->depth == 1)) |
| (void) XFillRectangle(display,window_info->id, |
| window_info->highlight_context,matte_info->x,matte_info->y, |
| matte_info->width,matte_info->height); |
| else |
| { |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->trough_color.pixel); |
| (void) XFillRectangle(display,window_info->id,window_info->widget_context, |
| matte_info->x,matte_info->y,matte_info->width,matte_info->height); |
| } |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w M a t t e T e x t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawMatteText() draws a matte with text. If the text exceeds the extents |
| % of the text, a portion of the text relative to the cursor is displayed. |
| % |
| % The format of the XDrawMatteText function is: |
| % |
| % XDrawMatteText(display,window_info,text_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o text_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the text. |
| % |
| */ |
| static void XDrawMatteText(Display *display,const XWindowInfo *window_info, |
| XWidgetInfo *text_info) |
| { |
| const char |
| *text; |
| |
| int |
| n, |
| x, |
| y; |
| |
| register int |
| i; |
| |
| unsigned int |
| height, |
| width; |
| |
| XFontStruct |
| *font_info; |
| |
| XRectangle |
| crop_info; |
| |
| /* |
| Clear the text area. |
| */ |
| XSetMatteColor(display,window_info,MagickFalse); |
| (void) XFillRectangle(display,window_info->id,window_info->widget_context, |
| text_info->x,text_info->y,text_info->width,text_info->height); |
| if (text_info->text == (char *) NULL) |
| return; |
| XSetTextColor(display,window_info,text_info->highlight); |
| font_info=window_info->font_info; |
| x=text_info->x+(QuantumMargin >> 2); |
| y=text_info->y+font_info->ascent+(text_info->height >> 2); |
| width=text_info->width-(QuantumMargin >> 1); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| if (*text_info->text == '\0') |
| { |
| /* |
| No text-- just draw cursor. |
| */ |
| (void) XDrawLine(display,window_info->id,window_info->annotate_context, |
| x,y+3,x,y-height+3); |
| return; |
| } |
| /* |
| Set cropping region. |
| */ |
| crop_info.width=(unsigned short) text_info->width; |
| crop_info.height=(unsigned short) text_info->height; |
| crop_info.x=text_info->x; |
| crop_info.y=text_info->y; |
| /* |
| Determine beginning of the visible text. |
| */ |
| if (text_info->cursor < text_info->marker) |
| text_info->marker=text_info->cursor; |
| else |
| { |
| text=text_info->marker; |
| if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) > |
| (int) width) |
| { |
| text=text_info->text; |
| for (i=0; i < Extent(text); i++) |
| { |
| n=XTextWidth(font_info,(char *) text+i,(int) |
| (text_info->cursor-text-i)); |
| if (n <= (int) width) |
| break; |
| } |
| text_info->marker=(char *) text+i; |
| } |
| } |
| /* |
| Draw text and cursor. |
| */ |
| if (text_info->highlight == MagickFalse) |
| { |
| (void) XSetClipRectangles(display,window_info->widget_context,0,0, |
| &crop_info,1,Unsorted); |
| (void) XDrawString(display,window_info->id,window_info->widget_context, |
| x,y,text_info->marker,Extent(text_info->marker)); |
| (void) XSetClipMask(display,window_info->widget_context,None); |
| } |
| else |
| { |
| (void) XSetClipRectangles(display,window_info->annotate_context,0,0, |
| &crop_info,1,Unsorted); |
| width=WidgetTextWidth(font_info,text_info->marker); |
| (void) XFillRectangle(display,window_info->id, |
| window_info->annotate_context,x,y-font_info->ascent,width,height); |
| (void) XSetClipMask(display,window_info->annotate_context,None); |
| (void) XSetClipRectangles(display,window_info->highlight_context,0,0, |
| &crop_info,1,Unsorted); |
| (void) XDrawString(display,window_info->id, |
| window_info->highlight_context,x,y,text_info->marker, |
| Extent(text_info->marker)); |
| (void) XSetClipMask(display,window_info->highlight_context,None); |
| } |
| x+=XTextWidth(font_info,text_info->marker,(int) |
| (text_info->cursor-text_info->marker)); |
| (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3, |
| x,y-height+3); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w T r i a n g l e E a s t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawTriangleEast() draws a triangle with a highlighted left bevel and a |
| % shadowed right and lower bevel. The highlighted and shadowed bevels create |
| % a 3-D effect. |
| % |
| % The format of the XDrawTriangleEast function is: |
| % |
| % XDrawTriangleEast(display,window_info,triangle_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the triangle. |
| % |
| */ |
| static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *triangle_info) |
| { |
| int |
| x1, |
| x2, |
| x3, |
| y1, |
| y2, |
| y3; |
| |
| unsigned int |
| bevel_width; |
| |
| XFontStruct |
| *font_info; |
| |
| XPoint |
| points[4]; |
| |
| /* |
| Draw triangle matte. |
| */ |
| x1=triangle_info->x; |
| y1=triangle_info->y; |
| x2=triangle_info->x+triangle_info->width; |
| y2=triangle_info->y+(triangle_info->height >> 1); |
| x3=triangle_info->x; |
| y3=triangle_info->y+triangle_info->height; |
| bevel_width=triangle_info->bevel_width; |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x3; |
| points[2].y=y3; |
| XSetMatteColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,3,Complex,CoordModeOrigin); |
| /* |
| Draw bottom bevel. |
| */ |
| points[0].x=x2; |
| points[0].y=y2; |
| points[1].x=x3; |
| points[1].y=y3; |
| points[2].x=x3-bevel_width; |
| points[2].y=y3+bevel_width; |
| points[3].x=x2+bevel_width; |
| points[3].y=y2; |
| XSetBevelColor(display,window_info,!triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw Left bevel. |
| */ |
| points[0].x=x3; |
| points[0].y=y3; |
| points[1].x=x1; |
| points[1].y=y1; |
| points[2].x=x1-bevel_width+1; |
| points[2].y=y1-bevel_width; |
| points[3].x=x3-bevel_width+1; |
| points[3].y=y3+bevel_width; |
| XSetBevelColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw top bevel. |
| */ |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x2+bevel_width; |
| points[2].y=y2; |
| points[3].x=x1-bevel_width; |
| points[3].y=y1-bevel_width; |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| (void) XSetFillStyle(display,window_info->widget_context,FillSolid); |
| if (triangle_info->text == (char *) NULL) |
| return; |
| /* |
| Write label to right of triangle. |
| */ |
| font_info=window_info->font_info; |
| XSetTextColor(display,window_info,MagickTrue); |
| x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+ |
| (QuantumMargin >> 1); |
| y1=triangle_info->y+((triangle_info->height- |
| (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent; |
| (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1, |
| triangle_info->text,Extent(triangle_info->text)); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w T r i a n g l e N o r t h % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a |
| % shadowed right and lower bevel. The highlighted and shadowed bevels create |
| % a 3-D effect. |
| % |
| % The format of the XDrawTriangleNorth function is: |
| % |
| % XDrawTriangleNorth(display,window_info,triangle_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the triangle. |
| % |
| */ |
| static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *triangle_info) |
| { |
| int |
| x1, |
| x2, |
| x3, |
| y1, |
| y2, |
| y3; |
| |
| unsigned int |
| bevel_width; |
| |
| XPoint |
| points[4]; |
| |
| /* |
| Draw triangle matte. |
| */ |
| x1=triangle_info->x; |
| y1=triangle_info->y+triangle_info->height; |
| x2=triangle_info->x+(triangle_info->width >> 1); |
| y2=triangle_info->y; |
| x3=triangle_info->x+triangle_info->width; |
| y3=triangle_info->y+triangle_info->height; |
| bevel_width=triangle_info->bevel_width; |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x3; |
| points[2].y=y3; |
| XSetMatteColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,3,Complex,CoordModeOrigin); |
| /* |
| Draw left bevel. |
| */ |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x2; |
| points[2].y=y2-bevel_width-2; |
| points[3].x=x1-bevel_width-1; |
| points[3].y=y1+bevel_width; |
| XSetBevelColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw right bevel. |
| */ |
| points[0].x=x2; |
| points[0].y=y2; |
| points[1].x=x3; |
| points[1].y=y3; |
| points[2].x=x3+bevel_width; |
| points[2].y=y3+bevel_width; |
| points[3].x=x2; |
| points[3].y=y2-bevel_width; |
| XSetBevelColor(display,window_info,!triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw lower bevel. |
| */ |
| points[0].x=x3; |
| points[0].y=y3; |
| points[1].x=x1; |
| points[1].y=y1; |
| points[2].x=x1-bevel_width; |
| points[2].y=y1+bevel_width; |
| points[3].x=x3+bevel_width; |
| points[3].y=y3+bevel_width; |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| (void) XSetFillStyle(display,window_info->widget_context,FillSolid); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w T r i a n g l e S o u t h % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawTriangleSouth() draws a border with a highlighted left and right bevel |
| % and a shadowed lower bevel. The highlighted and shadowed bevels create a |
| % 3-D effect. |
| % |
| % The format of the XDrawTriangleSouth function is: |
| % |
| % XDrawTriangleSouth(display,window_info,triangle_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o triangle_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the triangle. |
| % |
| */ |
| static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info, |
| const XWidgetInfo *triangle_info) |
| { |
| int |
| x1, |
| x2, |
| x3, |
| y1, |
| y2, |
| y3; |
| |
| unsigned int |
| bevel_width; |
| |
| XPoint |
| points[4]; |
| |
| /* |
| Draw triangle matte. |
| */ |
| x1=triangle_info->x; |
| y1=triangle_info->y; |
| x2=triangle_info->x+(triangle_info->width >> 1); |
| y2=triangle_info->y+triangle_info->height; |
| x3=triangle_info->x+triangle_info->width; |
| y3=triangle_info->y; |
| bevel_width=triangle_info->bevel_width; |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x3; |
| points[2].y=y3; |
| XSetMatteColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,3,Complex,CoordModeOrigin); |
| /* |
| Draw top bevel. |
| */ |
| points[0].x=x3; |
| points[0].y=y3; |
| points[1].x=x1; |
| points[1].y=y1; |
| points[2].x=x1-bevel_width; |
| points[2].y=y1-bevel_width; |
| points[3].x=x3+bevel_width; |
| points[3].y=y3-bevel_width; |
| XSetBevelColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw right bevel. |
| */ |
| points[0].x=x2; |
| points[0].y=y2; |
| points[1].x=x3+1; |
| points[1].y=y3-bevel_width; |
| points[2].x=x3+bevel_width; |
| points[2].y=y3-bevel_width; |
| points[3].x=x2; |
| points[3].y=y2+bevel_width; |
| XSetBevelColor(display,window_info,!triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| /* |
| Draw left bevel. |
| */ |
| points[0].x=x1; |
| points[0].y=y1; |
| points[1].x=x2; |
| points[1].y=y2; |
| points[2].x=x2; |
| points[2].y=y2+bevel_width; |
| points[3].x=x1-bevel_width; |
| points[3].y=y1-bevel_width; |
| XSetBevelColor(display,window_info,triangle_info->raised); |
| (void) XFillPolygon(display,window_info->id,window_info->widget_context, |
| points,4,Complex,CoordModeOrigin); |
| (void) XSetFillStyle(display,window_info->widget_context,FillSolid); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X D r a w W i d g e t T e x t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDrawWidgetText() first clears the widget and draws a text string justifed |
| % left (or center) in the x-direction and centered within the y-direction. |
| % |
| % The format of the XDrawWidgetText function is: |
| % |
| % XDrawWidgetText(display,window_info,text_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a XWindowText structure. |
| % |
| % o text_info: Specifies a pointer to XWidgetInfo structure. |
| % |
| */ |
| static void XDrawWidgetText(Display *display,const XWindowInfo *window_info, |
| XWidgetInfo *text_info) |
| { |
| GC |
| widget_context; |
| |
| int |
| x, |
| y; |
| |
| unsigned int |
| height, |
| width; |
| |
| XFontStruct |
| *font_info; |
| |
| XRectangle |
| crop_info; |
| |
| /* |
| Clear the text area. |
| */ |
| widget_context=window_info->annotate_context; |
| if (text_info->raised) |
| (void) XClearArea(display,window_info->id,text_info->x,text_info->y, |
| text_info->width,text_info->height,MagickFalse); |
| else |
| { |
| (void) XFillRectangle(display,window_info->id,widget_context,text_info->x, |
| text_info->y,text_info->width,text_info->height); |
| widget_context=window_info->highlight_context; |
| } |
| if (text_info->text == (char *) NULL) |
| return; |
| if (*text_info->text == '\0') |
| return; |
| /* |
| Set cropping region. |
| */ |
| font_info=window_info->font_info; |
| crop_info.width=(unsigned short) text_info->width; |
| crop_info.height=(unsigned short) text_info->height; |
| crop_info.x=text_info->x; |
| crop_info.y=text_info->y; |
| /* |
| Draw text. |
| */ |
| width=WidgetTextWidth(font_info,text_info->text); |
| x=text_info->x+(QuantumMargin >> 1); |
| if (text_info->center) |
| x=text_info->x+(text_info->width >> 1)-(width >> 1); |
| if (text_info->raised) |
| if (width > (text_info->width-QuantumMargin)) |
| x+=(text_info->width-QuantumMargin-width); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent; |
| (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted); |
| (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text, |
| Extent(text_info->text)); |
| (void) XSetClipMask(display,widget_context,None); |
| if (x < text_info->x) |
| (void) XDrawLine(display,window_info->id,window_info->annotate_context, |
| text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X E d i t T e x t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XEditText() edits a text string as indicated by the key symbol. |
| % |
| % The format of the XEditText function is: |
| % |
| % XEditText(display,text_info,key_symbol,text,state) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o text_info: Specifies a pointer to a XWidgetInfo structure. It |
| % contains the extents of the text. |
| % |
| % o key_symbol: A X11 KeySym that indicates what editing function to |
| % perform to the text. |
| % |
| % o text: A character string to insert into the text. |
| % |
| % o state: An size_t that indicates whether the key symbol is a |
| % control character or not. |
| % |
| */ |
| static void XEditText(Display *display,XWidgetInfo *text_info, |
| const KeySym key_symbol,char *text,const size_t state) |
| { |
| switch ((int) key_symbol) |
| { |
| case XK_BackSpace: |
| case XK_Delete: |
| { |
| if (text_info->highlight) |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *text_info->text='\0'; |
| text_info->cursor=text_info->text; |
| text_info->marker=text_info->text; |
| text_info->highlight=MagickFalse; |
| } |
| /* |
| Erase one character. |
| */ |
| if (text_info->cursor != text_info->text) |
| { |
| text_info->cursor--; |
| (void) CopyMagickString(text_info->cursor,text_info->cursor+1, |
| MaxTextExtent); |
| text_info->highlight=MagickFalse; |
| break; |
| } |
| } |
| case XK_Left: |
| case XK_KP_Left: |
| { |
| /* |
| Move cursor one position left. |
| */ |
| if (text_info->cursor == text_info->text) |
| break; |
| text_info->cursor--; |
| break; |
| } |
| case XK_Right: |
| case XK_KP_Right: |
| { |
| /* |
| Move cursor one position right. |
| */ |
| if (text_info->cursor == (text_info->text+Extent(text_info->text))) |
| break; |
| text_info->cursor++; |
| break; |
| } |
| default: |
| { |
| register char |
| *p, |
| *q; |
| |
| register int |
| i; |
| |
| if (state & ControlState) |
| break; |
| if (*text == '\0') |
| break; |
| if ((Extent(text_info->text)+1) >= (int) MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| if (text_info->highlight) |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *text_info->text='\0'; |
| text_info->cursor=text_info->text; |
| text_info->marker=text_info->text; |
| text_info->highlight=MagickFalse; |
| } |
| /* |
| Insert a string into the text. |
| */ |
| q=text_info->text+Extent(text_info->text)+strlen(text); |
| for (i=0; i <= Extent(text_info->cursor); i++) |
| { |
| *q=(*(q-Extent(text))); |
| q--; |
| } |
| p=text; |
| for (i=0; i < Extent(text); i++) |
| *text_info->cursor++=(*p++); |
| } |
| break; |
| } |
| } |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X G e t W i d g e t I n f o % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XGetWidgetInfo() initializes the XWidgetInfo structure. |
| % |
| % The format of the XGetWidgetInfo function is: |
| % |
| % XGetWidgetInfo(text,widget_info) |
| % |
| % A description of each parameter follows: |
| % |
| % o text: A string of characters associated with the widget. |
| % |
| % o widget_info: Specifies a pointer to a X11 XWidgetInfo structure. |
| % |
| */ |
| static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info) |
| { |
| /* |
| Initialize widget info. |
| */ |
| widget_info->id=(~0); |
| widget_info->bevel_width=3; |
| widget_info->width=1; |
| widget_info->height=1; |
| widget_info->x=0; |
| widget_info->y=0; |
| widget_info->min_y=0; |
| widget_info->max_y=0; |
| widget_info->raised=MagickTrue; |
| widget_info->active=MagickFalse; |
| widget_info->center=MagickTrue; |
| widget_info->trough=MagickFalse; |
| widget_info->highlight=MagickFalse; |
| widget_info->text=(char *) text; |
| widget_info->cursor=(char *) text; |
| if (text != (char *) NULL) |
| widget_info->cursor+=Extent(text); |
| widget_info->marker=(char *) text; |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X H i g h l i g h t W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XHighlightWidget() draws a highlighted border around a window. |
| % |
| % The format of the XHighlightWidget function is: |
| % |
| % XHighlightWidget(display,window_info,x,y) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o x: Specifies an integer representing the rectangle offset in the |
| % x-direction. |
| % |
| % o y: Specifies an integer representing the rectangle offset in the |
| % y-direction. |
| % |
| */ |
| static void XHighlightWidget(Display *display,const XWindowInfo *window_info, |
| const int x,const int y) |
| { |
| /* |
| Draw the widget highlighting rectangle. |
| */ |
| XSetBevelColor(display,window_info,MagickTrue); |
| (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y, |
| window_info->width-(x << 1),window_info->height-(y << 1)); |
| (void) XDrawRectangle(display,window_info->id,window_info->widget_context, |
| x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1); |
| XSetBevelColor(display,window_info,MagickFalse); |
| (void) XDrawRectangle(display,window_info->id,window_info->widget_context, |
| x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1)); |
| (void) XSetFillStyle(display,window_info->widget_context,FillSolid); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X S c r e e n E v e n t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XScreenEvent() returns MagickTrue if the any event on the X server queue is |
| % associated with the widget window. |
| % |
| % The format of the XScreenEvent function is: |
| % |
| % int XScreenEvent(Display *display,XEvent *event,char *data) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o event: Specifies a pointer to a X11 XEvent structure. |
| % |
| % o data: Specifies a pointer to a XWindows structure. |
| % |
| */ |
| |
| #if defined(__cplusplus) || defined(c_plusplus) |
| extern "C" { |
| #endif |
| |
| static int XScreenEvent(Display *display,XEvent *event,char *data) |
| { |
| XWindows |
| *windows; |
| |
| windows=(XWindows *) data; |
| if (event->xany.window == windows->popup.id) |
| { |
| if (event->type == MapNotify) |
| windows->popup.mapped=MagickTrue; |
| if (event->type == UnmapNotify) |
| windows->popup.mapped=MagickFalse; |
| return(MagickTrue); |
| } |
| if (event->xany.window == windows->widget.id) |
| { |
| if (event->type == MapNotify) |
| windows->widget.mapped=MagickTrue; |
| if (event->type == UnmapNotify) |
| windows->widget.mapped=MagickFalse; |
| return(MagickTrue); |
| } |
| switch (event->type) |
| { |
| case ButtonPress: |
| { |
| if ((event->xbutton.button == Button3) && |
| (event->xbutton.state & Mod1Mask)) |
| { |
| /* |
| Convert Alt-Button3 to Button2. |
| */ |
| event->xbutton.button=Button2; |
| event->xbutton.state&=(~Mod1Mask); |
| } |
| return(MagickTrue); |
| } |
| case Expose: |
| { |
| if (event->xexpose.window == windows->image.id) |
| { |
| XRefreshWindow(display,&windows->image,event); |
| break; |
| } |
| if (event->xexpose.window == windows->magnify.id) |
| if (event->xexpose.count == 0) |
| if (windows->magnify.mapped) |
| { |
| XMakeMagnifyImage(display,windows); |
| break; |
| } |
| if (event->xexpose.window == windows->command.id) |
| if (event->xexpose.count == 0) |
| { |
| (void) XCommandWidget(display,windows,(const char **) NULL,event); |
| break; |
| } |
| break; |
| } |
| case FocusOut: |
| { |
| /* |
| Set input focus for backdrop window. |
| */ |
| if (event->xfocus.window == windows->image.id) |
| (void) XSetInputFocus(display,windows->image.id,RevertToNone, |
| CurrentTime); |
| return(MagickTrue); |
| } |
| case ButtonRelease: |
| case KeyPress: |
| case KeyRelease: |
| case MotionNotify: |
| case SelectionNotify: |
| return(MagickTrue); |
| default: |
| break; |
| } |
| return(MagickFalse); |
| } |
| |
| #if defined(__cplusplus) || defined(c_plusplus) |
| } |
| #endif |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X S e t B e v e l C o l o r % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XSetBevelColor() sets the graphic context for drawing a beveled border. |
| % |
| % The format of the XSetBevelColor function is: |
| % |
| % XSetBevelColor(display,window_info,raised) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o raised: A value other than zero indicates the color show be a |
| % "highlight" color, otherwise the "shadow" color is set. |
| % |
| */ |
| static void XSetBevelColor(Display *display,const XWindowInfo *window_info, |
| const MagickStatusType raised) |
| { |
| if (window_info->depth == 1) |
| { |
| Pixmap |
| stipple; |
| |
| /* |
| Monochrome window. |
| */ |
| (void) XSetBackground(display,window_info->widget_context, |
| XBlackPixel(display,window_info->screen)); |
| (void) XSetForeground(display,window_info->widget_context, |
| XWhitePixel(display,window_info->screen)); |
| (void) XSetFillStyle(display,window_info->widget_context, |
| FillOpaqueStippled); |
| stipple=window_info->highlight_stipple; |
| if (raised == MagickFalse) |
| stipple=window_info->shadow_stipple; |
| (void) XSetStipple(display,window_info->widget_context,stipple); |
| } |
| else |
| if (raised) |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->highlight_color.pixel); |
| else |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->shadow_color.pixel); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X S e t M a t t e C o l o r % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XSetMatteColor() sets the graphic context for drawing the matte. |
| % |
| % The format of the XSetMatteColor function is: |
| % |
| % XSetMatteColor(display,window_info,raised) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o raised: A value other than zero indicates the matte is active. |
| % |
| */ |
| static void XSetMatteColor(Display *display,const XWindowInfo *window_info, |
| const MagickStatusType raised) |
| { |
| if (window_info->depth == 1) |
| { |
| /* |
| Monochrome window. |
| */ |
| if (raised) |
| (void) XSetForeground(display,window_info->widget_context, |
| XWhitePixel(display,window_info->screen)); |
| else |
| (void) XSetForeground(display,window_info->widget_context, |
| XBlackPixel(display,window_info->screen)); |
| } |
| else |
| if (raised) |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->matte_color.pixel); |
| else |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->depth_color.pixel); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| + X S e t T e x t C o l o r % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XSetTextColor() sets the graphic context for drawing text on a matte. |
| % |
| % The format of the XSetTextColor function is: |
| % |
| % XSetTextColor(display,window_info,raised) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a pointer to the Display structure; returned from |
| % XOpenDisplay. |
| % |
| % o window_info: Specifies a pointer to a X11 XWindowInfo structure. |
| % |
| % o raised: A value other than zero indicates the color show be a |
| % "highlight" color, otherwise the "shadow" color is set. |
| % |
| */ |
| static void XSetTextColor(Display *display,const XWindowInfo *window_info, |
| const MagickStatusType raised) |
| { |
| ssize_t |
| foreground, |
| matte; |
| |
| if (window_info->depth == 1) |
| { |
| /* |
| Monochrome window. |
| */ |
| if (raised) |
| (void) XSetForeground(display,window_info->widget_context, |
| XBlackPixel(display,window_info->screen)); |
| else |
| (void) XSetForeground(display,window_info->widget_context, |
| XWhitePixel(display,window_info->screen)); |
| return; |
| } |
| foreground=(ssize_t) XPixelIntensity( |
| &window_info->pixel_info->foreground_color); |
| matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color); |
| if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3)) |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->foreground_color.pixel); |
| else |
| (void) XSetForeground(display,window_info->widget_context, |
| window_info->pixel_info->background_color.pixel); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X C o l o r B r o w s e r W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XColorBrowserWidget() displays a Color Browser widget with a color query |
| % to the user. The user keys a reply and presses the Action or Cancel button |
| % to exit. The typed text is returned as the reply function parameter. |
| % |
| % The format of the XColorBrowserWidget method is: |
| % |
| % void XColorBrowserWidget(Display *display,XWindows *windows, |
| % const char *action,char *reply) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o action: Specifies a pointer to the action of this widget. |
| % |
| % o reply: the response from the user is returned in this parameter. |
| % |
| */ |
| MagickExport void XColorBrowserWidget(Display *display,XWindows *windows, |
| const char *action,char *reply) |
| { |
| #define CancelButtonText "Cancel" |
| #define ColornameText "Name:" |
| #define ColorPatternText "Pattern:" |
| #define GrabButtonText "Grab" |
| #define ResetButtonText "Reset" |
| |
| char |
| **colorlist, |
| primary_selection[MaxTextExtent], |
| reset_pattern[MaxTextExtent], |
| text[MaxTextExtent]; |
| |
| ExceptionInfo |
| *exception; |
| |
| int |
| x, |
| y; |
| |
| register int |
| i; |
| |
| static char |
| glob_pattern[MaxTextExtent] = "*"; |
| |
| static MagickStatusType |
| mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); |
| |
| Status |
| status; |
| |
| unsigned int |
| height, |
| text_width, |
| visible_colors, |
| width; |
| |
| size_t |
| colors, |
| delay, |
| state; |
| |
| XColor |
| color; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| action_info, |
| cancel_info, |
| expose_info, |
| grab_info, |
| list_info, |
| mode_info, |
| north_info, |
| reply_info, |
| reset_info, |
| scroll_info, |
| selection_info, |
| slider_info, |
| south_info, |
| text_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Get color list and sort in ascending order. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(action != (char *) NULL); |
| assert(reply != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| (void) CopyMagickString(reset_pattern,"*",MaxTextExtent); |
| exception=AcquireExceptionInfo(); |
| colorlist=GetColorList(glob_pattern,&colors,exception); |
| if (colorlist == (char **) NULL) |
| { |
| /* |
| Pattern failed, obtain all the colors. |
| */ |
| (void) CopyMagickString(glob_pattern,"*",MaxTextExtent); |
| colorlist=GetColorList(glob_pattern,&colors,exception); |
| if (colorlist == (char **) NULL) |
| { |
| XNoticeWidget(display,windows,"Unable to obtain colors names:", |
| glob_pattern); |
| (void) XDialogWidget(display,windows,action,"Enter color name:", |
| reply); |
| return; |
| } |
| } |
| /* |
| Determine Color Browser widget attributes. |
| */ |
| font_info=windows->widget.font_info; |
| text_width=0; |
| for (i=0; i < (int) colors; i++) |
| if (WidgetTextWidth(font_info,colorlist[i]) > text_width) |
| text_width=WidgetTextWidth(font_info,colorlist[i]); |
| width=WidgetTextWidth(font_info,(char *) action); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| if (WidgetTextWidth(font_info,ResetButtonText) > width) |
| width=WidgetTextWidth(font_info,ResetButtonText); |
| if (WidgetTextWidth(font_info,GrabButtonText) > width) |
| width=WidgetTextWidth(font_info,GrabButtonText); |
| width+=QuantumMargin; |
| if (WidgetTextWidth(font_info,ColorPatternText) > width) |
| width=WidgetTextWidth(font_info,ColorPatternText); |
| if (WidgetTextWidth(font_info,ColornameText) > width) |
| width=WidgetTextWidth(font_info,ColornameText); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Color Browser widget. |
| */ |
| windows->widget.width=(unsigned int) |
| (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin); |
| windows->widget.min_width=(unsigned int) |
| (width+MinTextWidth+4*QuantumMargin); |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) |
| ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4; |
| windows->widget.min_height=(unsigned int) |
| (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Color Browser widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Browse and Select a Color", |
| MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| mask,&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| XGetWidgetInfo((char *) NULL,&slider_info); |
| XGetWidgetInfo((char *) NULL,&north_info); |
| XGetWidgetInfo((char *) NULL,&south_info); |
| XGetWidgetInfo((char *) NULL,&expose_info); |
| visible_colors=0; |
| delay=SuspendTime << 2; |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| int |
| id; |
| |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) |
| (windows->widget.width-cancel_info.width-QuantumMargin-2); |
| cancel_info.y=(int) |
| (windows->widget.height-cancel_info.height-QuantumMargin); |
| XGetWidgetInfo(action,&action_info); |
| action_info.width=width; |
| action_info.height=(unsigned int) ((3*height) >> 1); |
| action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ |
| (action_info.bevel_width << 1)); |
| action_info.y=cancel_info.y; |
| XGetWidgetInfo(GrabButtonText,&grab_info); |
| grab_info.width=width; |
| grab_info.height=(unsigned int) ((3*height) >> 1); |
| grab_info.x=QuantumMargin; |
| grab_info.y=((5*QuantumMargin) >> 1)+height; |
| XGetWidgetInfo(ResetButtonText,&reset_info); |
| reset_info.width=width; |
| reset_info.height=(unsigned int) ((3*height) >> 1); |
| reset_info.x=QuantumMargin; |
| reset_info.y=grab_info.y+grab_info.height+QuantumMargin; |
| /* |
| Initialize reply information. |
| */ |
| XGetWidgetInfo(reply,&reply_info); |
| reply_info.raised=MagickFalse; |
| reply_info.bevel_width--; |
| reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); |
| reply_info.height=height << 1; |
| reply_info.x=(int) (width+(QuantumMargin << 1)); |
| reply_info.y=action_info.y-reply_info.height-QuantumMargin; |
| /* |
| Initialize mode information. |
| */ |
| XGetWidgetInfo((char *) NULL,&mode_info); |
| mode_info.active=MagickTrue; |
| mode_info.bevel_width=0; |
| mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1)); |
| mode_info.height=action_info.height; |
| mode_info.x=QuantumMargin; |
| mode_info.y=action_info.y; |
| /* |
| Initialize scroll information. |
| */ |
| XGetWidgetInfo((char *) NULL,&scroll_info); |
| scroll_info.bevel_width--; |
| scroll_info.width=height; |
| scroll_info.height=(unsigned int) (reply_info.y-grab_info.y- |
| (QuantumMargin >> 1)); |
| scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); |
| scroll_info.y=grab_info.y-reply_info.bevel_width; |
| scroll_info.raised=MagickFalse; |
| scroll_info.trough=MagickTrue; |
| north_info=scroll_info; |
| north_info.raised=MagickTrue; |
| north_info.width-=(north_info.bevel_width << 1); |
| north_info.height=north_info.width-1; |
| north_info.x+=north_info.bevel_width; |
| north_info.y+=north_info.bevel_width; |
| south_info=north_info; |
| south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- |
| south_info.height; |
| id=slider_info.id; |
| slider_info=north_info; |
| slider_info.id=id; |
| slider_info.width-=2; |
| slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ |
| slider_info.bevel_width+2; |
| slider_info.height=scroll_info.height-((slider_info.min_y- |
| scroll_info.y+1) << 1)+4; |
| visible_colors=scroll_info.height/(height+(height >> 3)); |
| if (colors > visible_colors) |
| slider_info.height=(unsigned int) |
| ((visible_colors*slider_info.height)/colors); |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.x=scroll_info.x+slider_info.bevel_width+1; |
| slider_info.y=slider_info.min_y; |
| expose_info=scroll_info; |
| expose_info.y=slider_info.y; |
| /* |
| Initialize list information. |
| */ |
| XGetWidgetInfo((char *) NULL,&list_info); |
| list_info.raised=MagickFalse; |
| list_info.bevel_width--; |
| list_info.width=(unsigned int) |
| (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); |
| list_info.height=scroll_info.height; |
| list_info.x=reply_info.x; |
| list_info.y=scroll_info.y; |
| if (windows->widget.mapped == MagickFalse) |
| state|=JumpListState; |
| /* |
| Initialize text information. |
| */ |
| *text='\0'; |
| XGetWidgetInfo(text,&text_info); |
| text_info.center=MagickFalse; |
| text_info.width=reply_info.width; |
| text_info.height=height; |
| text_info.x=list_info.x-(QuantumMargin >> 1); |
| text_info.y=QuantumMargin; |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=list_info.width; |
| selection_info.height=(unsigned int) ((9*height) >> 3); |
| selection_info.x=list_info.x; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Color Browser window. |
| */ |
| x=QuantumMargin; |
| y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,ColorPatternText, |
| Extent(ColorPatternText)); |
| (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawBeveledButton(display,&windows->widget,&grab_info); |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| XDrawBeveledMatte(display,&windows->widget,&list_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| x=QuantumMargin; |
| y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,ColornameText, |
| Extent(ColornameText)); |
| XDrawBeveledMatte(display,&windows->widget,&reply_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| selection_info.id=(~0); |
| state|=RedrawActionState; |
| state|=RedrawListState; |
| state&=(~RedrawWidgetState); |
| } |
| if (state & UpdateListState) |
| { |
| char |
| **checklist; |
| |
| size_t |
| number_colors; |
| |
| status=XParseColor(display,windows->widget.map_info->colormap, |
| glob_pattern,&color); |
| if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL)) |
| { |
| /* |
| Reply is a single color name-- exit. |
| */ |
| (void) CopyMagickString(reply,glob_pattern,MaxTextExtent); |
| (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent); |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| /* |
| Update color list. |
| */ |
| checklist=GetColorList(glob_pattern,&number_colors,exception); |
| if (number_colors == 0) |
| { |
| (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent); |
| (void) XBell(display,0); |
| } |
| else |
| { |
| for (i=0; i < (int) colors; i++) |
| colorlist[i]=DestroyString(colorlist[i]); |
| if (colorlist != (char **) NULL) |
| colorlist=(char **) RelinquishMagickMemory(colorlist); |
| colorlist=checklist; |
| colors=number_colors; |
| } |
| /* |
| Sort color list in ascending order. |
| */ |
| slider_info.height= |
| scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; |
| if (colors > visible_colors) |
| slider_info.height=(unsigned int) |
| ((visible_colors*slider_info.height)/colors); |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| expose_info.y=slider_info.y; |
| selection_info.id=(~0); |
| list_info.id=(~0); |
| state|=RedrawListState; |
| /* |
| Redraw color name & reply. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~UpdateListState); |
| } |
| if (state & JumpListState) |
| { |
| /* |
| Jump scroll to match user color. |
| */ |
| list_info.id=(~0); |
| for (i=0; i < (int) colors; i++) |
| if (LocaleCompare(colorlist[i],reply) >= 0) |
| { |
| list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0; |
| break; |
| } |
| if ((i < slider_info.id) || |
| (i >= (int) (slider_info.id+visible_colors))) |
| slider_info.id=i-(visible_colors >> 1); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| state&=(~JumpListState); |
| } |
| if (state & RedrawListState) |
| { |
| /* |
| Determine slider id and position. |
| */ |
| if (slider_info.id >= (int) (colors-visible_colors)) |
| slider_info.id=(int) (colors-visible_colors); |
| if ((slider_info.id < 0) || (colors <= visible_colors)) |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| if (colors != 0) |
| slider_info.y+=(int) (slider_info.id*(slider_info.max_y- |
| slider_info.min_y+1)/colors); |
| if (slider_info.id != selection_info.id) |
| { |
| /* |
| Redraw scroll bar and file names. |
| */ |
| selection_info.id=slider_info.id; |
| selection_info.y=list_info.y+(height >> 3)+2; |
| for (i=0; i < (int) visible_colors; i++) |
| { |
| selection_info.raised=(slider_info.id+i) != list_info.id ? |
| MagickTrue : MagickFalse; |
| selection_info.text=(char *) NULL; |
| if ((slider_info.id+i) < (int) colors) |
| selection_info.text=colorlist[slider_info.id+i]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| /* |
| Update slider. |
| */ |
| if (slider_info.y > expose_info.y) |
| { |
| expose_info.height=(unsigned int) slider_info.y-expose_info.y; |
| expose_info.y=slider_info.y-expose_info.height- |
| slider_info.bevel_width-1; |
| } |
| else |
| { |
| expose_info.height=(unsigned int) expose_info.y-slider_info.y; |
| expose_info.y=slider_info.y+slider_info.height+ |
| slider_info.bevel_width+1; |
| } |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawMatte(display,&windows->widget,&expose_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| expose_info.y=slider_info.y; |
| } |
| state&=(~RedrawListState); |
| } |
| if (state & RedrawActionState) |
| { |
| static char |
| colorname[MaxTextExtent]; |
| |
| /* |
| Display the selected color in a drawing area. |
| */ |
| color=windows->widget.pixel_info->matte_color; |
| (void) XParseColor(display,windows->widget.map_info->colormap, |
| reply_info.text,&windows->widget.pixel_info->matte_color); |
| XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL, |
| (unsigned int) windows->widget.visual_info->colormap_size, |
| &windows->widget.pixel_info->matte_color); |
| mode_info.text=colorname; |
| (void) FormatMagickString(mode_info.text,MaxTextExtent,"#%02x%02x%02x", |
| windows->widget.pixel_info->matte_color.red, |
| windows->widget.pixel_info->matte_color.green, |
| windows->widget.pixel_info->matte_color.blue); |
| XDrawBeveledButton(display,&windows->widget,&mode_info); |
| windows->widget.pixel_info->matte_color=color; |
| state&=(~RedrawActionState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (north_info.raised && south_info.raised) |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| else |
| { |
| /* |
| Brief delay before advancing scroll bar. |
| */ |
| XDelay(display,delay); |
| delay=SuspendTime; |
| (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); |
| if (north_info.raised == MagickFalse) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| slider_info.id--; |
| state|=RedrawListState; |
| } |
| if (south_info.raised == MagickFalse) |
| if (slider_info.id < (int) colors) |
| { |
| /* |
| Move slider down. |
| */ |
| slider_info.id++; |
| state|=RedrawListState; |
| } |
| if (event.type != ButtonRelease) |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(slider_info,event.xbutton)) |
| { |
| /* |
| Track slider. |
| */ |
| slider_info.active=MagickTrue; |
| break; |
| } |
| if (MatteIsActive(north_info,event.xbutton)) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| north_info.raised=MagickFalse; |
| slider_info.id--; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(south_info,event.xbutton)) |
| if (slider_info.id < (int) colors) |
| { |
| /* |
| Move slider down. |
| */ |
| south_info.raised=MagickFalse; |
| slider_info.id++; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(scroll_info,event.xbutton)) |
| { |
| /* |
| Move slider. |
| */ |
| if (event.xbutton.y < slider_info.y) |
| slider_info.id-=(visible_colors-1); |
| else |
| slider_info.id+=(visible_colors-1); |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(list_info,event.xbutton)) |
| { |
| int |
| id; |
| |
| /* |
| User pressed list matte. |
| */ |
| id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ |
| selection_info.height; |
| if (id >= (int) colors) |
| break; |
| (void) CopyMagickString(reply_info.text,colorlist[id], |
| MaxTextExtent); |
| reply_info.highlight=MagickFalse; |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=RedrawActionState; |
| if (id == list_info.id) |
| { |
| (void) CopyMagickString(glob_pattern,reply_info.text, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| selection_info.id=(~0); |
| list_info.id=id; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(grab_info,event.xbutton)) |
| { |
| /* |
| User pressed Grab button. |
| */ |
| grab_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&grab_info); |
| break; |
| } |
| if (MatteIsActive(reset_info,event.xbutton)) |
| { |
| /* |
| User pressed Reset button. |
| */ |
| reset_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| break; |
| } |
| if (MatteIsActive(mode_info,event.xbutton)) |
| { |
| /* |
| User pressed mode button. |
| */ |
| (void) CopyMagickString(reply_info.text,mode_info.text, |
| MaxTextExtent); |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| windows->widget.id ? MagickTrue : MagickFalse; |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| /* |
| User pressed action button. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| if (event.xbutton.button != Button2) |
| { |
| static Time |
| click_time; |
| |
| /* |
| Move text cursor to position of button press. |
| */ |
| x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); |
| for (i=1; i <= Extent(reply_info.marker); i++) |
| if (XTextWidth(font_info,reply_info.marker,i) > x) |
| break; |
| reply_info.cursor=reply_info.marker+i-1; |
| if (event.xbutton.time > (click_time+DoubleClick)) |
| reply_info.highlight=MagickFalse; |
| else |
| { |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| windows->widget.id ? MagickTrue : MagickFalse; |
| } |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| click_time=event.xbutton.time; |
| break; |
| } |
| /* |
| Request primary selection. |
| */ |
| (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, |
| windows->widget.id,event.xbutton.time); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (north_info.raised == MagickFalse) |
| { |
| /* |
| User released up button. |
| */ |
| delay=SuspendTime << 2; |
| north_info.raised=MagickTrue; |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| } |
| if (south_info.raised == MagickFalse) |
| { |
| /* |
| User released down button. |
| */ |
| delay=SuspendTime << 2; |
| south_info.raised=MagickTrue; |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| } |
| if (slider_info.active) |
| { |
| /* |
| Stop tracking slider. |
| */ |
| slider_info.active=MagickFalse; |
| break; |
| } |
| if (grab_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(grab_info,event.xbutton)) |
| { |
| /* |
| Select a pen color from the X server. |
| */ |
| (void) XGetWindowColor(display,windows,reply_info.text); |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=RedrawActionState; |
| } |
| grab_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&grab_info); |
| } |
| if (reset_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(reset_info,event.xbutton)) |
| { |
| (void) CopyMagickString(glob_pattern,reset_pattern, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| reset_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| } |
| if (action_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| { |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| if (*reply_info.text == '\0') |
| (void) XBell(display,0); |
| else |
| state|=ExitState; |
| } |
| } |
| action_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if (AreaIsActive(scroll_info,event.xkey)) |
| { |
| /* |
| Move slider. |
| */ |
| switch ((int) key_symbol) |
| { |
| case XK_Home: |
| case XK_KP_Home: |
| { |
| slider_info.id=0; |
| break; |
| } |
| case XK_Up: |
| case XK_KP_Up: |
| { |
| slider_info.id--; |
| break; |
| } |
| case XK_Down: |
| case XK_KP_Down: |
| { |
| slider_info.id++; |
| break; |
| } |
| case XK_Prior: |
| case XK_KP_Prior: |
| { |
| slider_info.id-=visible_colors; |
| break; |
| } |
| case XK_Next: |
| case XK_KP_Next: |
| { |
| slider_info.id+=visible_colors; |
| break; |
| } |
| case XK_End: |
| case XK_KP_End: |
| { |
| slider_info.id=(int) colors; |
| break; |
| } |
| } |
| state|=RedrawListState; |
| break; |
| } |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| /* |
| Read new color or glob patterm. |
| */ |
| if (*reply_info.text == '\0') |
| break; |
| (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent); |
| state|=UpdateListState; |
| break; |
| } |
| if (key_symbol == XK_Control_L) |
| { |
| state|=ControlState; |
| break; |
| } |
| if (state & ControlState) |
| switch ((int) key_symbol) |
| { |
| case XK_u: |
| case XK_U: |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| reply_info.marker=reply_info.text; |
| reply_info.highlight=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| XEditText(display,&reply_info,key_symbol,command,state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| status=XParseColor(display,windows->widget.map_info->colormap, |
| reply_info.text,&color); |
| if (status != False) |
| state|=RedrawActionState; |
| break; |
| } |
| case KeyRelease: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key release. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if (key_symbol == XK_Control_L) |
| state&=(~ControlState); |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MapNotify: |
| { |
| mask&=(~CWX); |
| mask&=(~CWY); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (slider_info.active) |
| { |
| /* |
| Move slider matte. |
| */ |
| slider_info.y=event.xmotion.y- |
| ((slider_info.height+slider_info.bevel_width) >> 1)+1; |
| if (slider_info.y < slider_info.min_y) |
| slider_info.y=slider_info.min_y; |
| if (slider_info.y > slider_info.max_y) |
| slider_info.y=slider_info.max_y; |
| slider_info.id=0; |
| if (slider_info.y != slider_info.min_y) |
| slider_info.id=(int) ((colors*(slider_info.y- |
| slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1)); |
| state|=RedrawListState; |
| break; |
| } |
| if (state & InactiveWidgetState) |
| break; |
| if (grab_info.raised == MatteIsActive(grab_info,event.xmotion)) |
| { |
| /* |
| Grab button status changed. |
| */ |
| grab_info.raised=!grab_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&grab_info); |
| break; |
| } |
| if (reset_info.raised == MatteIsActive(reset_info,event.xmotion)) |
| { |
| /* |
| Reset button status changed. |
| */ |
| reset_info.raised=!reset_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| break; |
| } |
| if (action_info.raised == MatteIsActive(action_info,event.xmotion)) |
| { |
| /* |
| Action button status changed. |
| */ |
| action_info.raised=action_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| reply_info.highlight=MagickFalse; |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| case SelectionNotify: |
| { |
| Atom |
| type; |
| |
| int |
| format; |
| |
| unsigned char |
| *data; |
| |
| unsigned long |
| after, |
| length; |
| |
| /* |
| Obtain response from primary selection. |
| */ |
| if (event.xselection.property == (Atom) None) |
| break; |
| status=XGetWindowProperty(display,event.xselection.requestor, |
| event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, |
| &format,&length,&after,&data); |
| if ((status != Success) || (type != XA_STRING) || (format == 32) || |
| (length == 0)) |
| break; |
| if ((Extent(reply_info.text)+length) >= MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| /* |
| Insert primary selection in reply text. |
| */ |
| *(data+length)='\0'; |
| XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, |
| state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| state|=RedrawActionState; |
| } |
| (void) XFree((void *) data); |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| if (reply_info.highlight == MagickFalse) |
| break; |
| /* |
| Set primary selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.send_event=MagickTrue; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False, |
| NoEventMask,(XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| /* |
| Free color list. |
| */ |
| for (i=0; i < (int) colors; i++) |
| colorlist[i]=DestroyString(colorlist[i]); |
| if (colorlist != (char **) NULL) |
| colorlist=(char **) RelinquishMagickMemory(colorlist); |
| exception=DestroyExceptionInfo(exception); |
| if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL)) |
| return; |
| status=XParseColor(display,windows->widget.map_info->colormap,reply,&color); |
| if (status != False) |
| return; |
| XNoticeWidget(display,windows,"Color is unknown to X server:",reply); |
| (void) CopyMagickString(reply,"gray",MaxTextExtent); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X C o m m a n d W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XCommandWidget() maps a menu and returns the command pointed to by the user |
| % when the button is released. |
| % |
| % The format of the XCommandWidget method is: |
| % |
| % int XCommandWidget(Display *display,XWindows *windows, |
| % const char **selections,XEvent *event) |
| % |
| % A description of each parameter follows: |
| % |
| % o selection_number: Specifies the number of the selection that the |
| % user choose. |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o selections: Specifies a pointer to one or more strings that comprise |
| % the choices in the menu. |
| % |
| % o event: Specifies a pointer to a X11 XEvent structure. |
| % |
| */ |
| MagickExport int XCommandWidget(Display *display,XWindows *windows, |
| const char **selections,XEvent *event) |
| { |
| #define tile_width 112 |
| #define tile_height 70 |
| |
| static const unsigned char |
| tile_bits[]= |
| { |
| 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0, |
| 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f, |
| 0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f, |
| 0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, |
| 0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00, |
| 0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00, |
| 0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c, |
| 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f, |
| 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, |
| 0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, |
| 0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78, |
| 0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00, |
| 0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00, |
| 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8, |
| 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8, |
| 0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef, |
| 0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78, |
| 0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, |
| 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, |
| 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf, |
| 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00, |
| 0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c, |
| 0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, |
| 0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0, |
| 0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f, |
| 0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00, |
| 0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc, |
| 0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f, |
| 0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00, |
| 0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e, |
| 0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07, |
| 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e, |
| 0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03, |
| 0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00, |
| 0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f, |
| 0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00, |
| 0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e, |
| 0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc, |
| 0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7, |
| 0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03, |
| 0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, |
| 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| int |
| id, |
| y; |
| |
| register int |
| i; |
| |
| static unsigned int |
| number_selections; |
| |
| unsigned int |
| height; |
| |
| size_t |
| state; |
| |
| XFontStruct |
| *font_info; |
| |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| font_info=windows->command.font_info; |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| id=(~0); |
| state=DefaultState; |
| if (event == (XEvent *) NULL) |
| { |
| unsigned int |
| width; |
| |
| XTextProperty |
| window_name; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine command window attributes. |
| */ |
| assert(selections != (const char **) NULL); |
| windows->command.width=0; |
| for (i=0; selections[i] != (char *) NULL; i++) |
| { |
| width=WidgetTextWidth(font_info,(char *) selections[i]); |
| if (width > windows->command.width) |
| windows->command.width=width; |
| } |
| number_selections=(unsigned int) i; |
| windows->command.width+=3*QuantumMargin+10; |
| if ((int) windows->command.width < (tile_width+QuantumMargin+10)) |
| windows->command.width=(unsigned int) (tile_width+QuantumMargin+10); |
| windows->command.height=(unsigned int) (number_selections* |
| (((3*height) >> 1)+10)+tile_height+20); |
| windows->command.min_width=windows->command.width; |
| windows->command.min_height=windows->command.height; |
| XConstrainWindowPosition(display,&windows->command); |
| if (windows->command.id != (Window) NULL) |
| { |
| Status |
| status; |
| |
| /* |
| Reconfigure command window. |
| */ |
| status=XStringListToTextProperty(&windows->command.name,1, |
| &window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->command.id,&window_name); |
| XSetWMIconName(display,windows->command.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->command.width; |
| window_changes.height=(int) windows->command.height; |
| (void) XReconfigureWMWindow(display,windows->command.id, |
| windows->command.screen,(unsigned int) (CWWidth | CWHeight), |
| &window_changes); |
| } |
| /* |
| Allocate selection info memory. |
| */ |
| if (selection_info != (XWidgetInfo *) NULL) |
| selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info); |
| selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections, |
| sizeof(*selection_info)); |
| if (selection_info == (XWidgetInfo *) NULL) |
| { |
| ThrowXWindowFatalException(ResourceLimitError, |
| "MemoryAllocationFailed","..."); |
| return(id); |
| } |
| state|=UpdateConfigurationState | RedrawWidgetState; |
| } |
| /* |
| Wait for next event. |
| */ |
| if (event != (XEvent *) NULL) |
| switch (event->type) |
| { |
| case ButtonPress: |
| { |
| for (i=0; i < (int) number_selections; i++) |
| { |
| if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse) |
| continue; |
| if (i >= (int) windows->command.data) |
| { |
| selection_info[i].raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->command,&selection_info[i]); |
| break; |
| } |
| submenu_info=selection_info[i]; |
| submenu_info.active=MagickTrue; |
| toggle_info.y= |
| submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1); |
| id=i; |
| (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask, |
| event); |
| break; |
| } |
| break; |
| } |
| case ButtonRelease: |
| { |
| for (i=0; i < (int) number_selections; i++) |
| { |
| if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse) |
| continue; |
| id=i; |
| if (id >= (int) windows->command.data) |
| { |
| selection_info[id].raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->command,&selection_info[id]); |
| break; |
| } |
| break; |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, withdraw command widget. |
| */ |
| if (event->xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event->xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| (void) XWithdrawWindow(display,windows->command.id, |
| windows->command.screen); |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event->xconfigure.window != windows->command.id) |
| break; |
| if (event->xconfigure.send_event != 0) |
| { |
| windows->command.x=event->xconfigure.x; |
| windows->command.y=event->xconfigure.y; |
| } |
| if ((event->xconfigure.width == (int) windows->command.width) && |
| (event->xconfigure.height == (int) windows->command.height)) |
| break; |
| windows->command.width=(unsigned int) |
| MagickMax(event->xconfigure.width,(int) windows->command.min_width); |
| windows->command.height=(unsigned int) |
| MagickMax(event->xconfigure.height,(int) windows->command.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case Expose: |
| { |
| if (event->xexpose.window != windows->command.id) |
| break; |
| if (event->xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Return the ID of the highlighted menu entry. |
| */ |
| for ( ; ; ) |
| { |
| for (i=0; i < (int) number_selections; i++) |
| { |
| if (i >= (int) windows->command.data) |
| { |
| if (selection_info[i].raised == |
| MatteIsActive(selection_info[i],event->xmotion)) |
| { |
| /* |
| Button status changed. |
| */ |
| selection_info[i].raised=!selection_info[i].raised; |
| XDrawBeveledButton(display,&windows->command, |
| &selection_info[i]); |
| } |
| continue; |
| } |
| if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse) |
| continue; |
| submenu_info=selection_info[i]; |
| submenu_info.active=MagickTrue; |
| toggle_info.raised=MagickTrue; |
| toggle_info.y=submenu_info.y+(submenu_info.height >> 1)- |
| (toggle_info.height >> 1); |
| XDrawTriangleEast(display,&windows->command,&toggle_info); |
| id=i; |
| } |
| XDelay(display,SuspendTime); |
| if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse) |
| break; |
| while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; |
| toggle_info.raised=MagickFalse; |
| if (windows->command.data != 0) |
| XDrawTriangleEast(display,&windows->command,&toggle_info); |
| } |
| break; |
| } |
| case MapNotify: |
| { |
| windows->command.mapped=MagickTrue; |
| break; |
| } |
| case UnmapNotify: |
| { |
| windows->command.mapped=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize button information. |
| */ |
| assert(selections != (const char **) NULL); |
| y=tile_height+20; |
| for (i=0; i < (int) number_selections; i++) |
| { |
| XGetWidgetInfo(selections[i],&selection_info[i]); |
| selection_info[i].center=MagickFalse; |
| selection_info[i].bevel_width--; |
| selection_info[i].height=(unsigned int) ((3*height) >> 1); |
| selection_info[i].x=(QuantumMargin >> 1)+4; |
| selection_info[i].width=(unsigned int) |
| (windows->command.width-(selection_info[i].x << 1)); |
| selection_info[i].y=y; |
| y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6; |
| } |
| XGetWidgetInfo((char *) NULL,&toggle_info); |
| toggle_info.bevel_width--; |
| toggle_info.width=(unsigned int) |
| (((5*height) >> 3)-(toggle_info.bevel_width << 1)); |
| toggle_info.height=toggle_info.width; |
| toggle_info.x=selection_info[0].x+selection_info[0].width- |
| toggle_info.width-(QuantumMargin >> 1); |
| if (windows->command.mapped) |
| (void) XClearWindow(display,windows->command.id); |
| } |
| if (state & RedrawWidgetState) |
| { |
| Pixmap |
| tile_pixmap; |
| |
| /* |
| Draw command buttons. |
| */ |
| tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id, |
| (char *) tile_bits,tile_width,tile_height,1L,0L,1); |
| if (tile_pixmap != (Pixmap) NULL) |
| { |
| (void) XCopyPlane(display,tile_pixmap,windows->command.id, |
| windows->command.annotate_context,0,0,tile_width,tile_height, |
| (int) ((windows->command.width-tile_width) >> 1),10,1L); |
| (void) XFreePixmap(display,tile_pixmap); |
| } |
| for (i=0; i < (int) number_selections; i++) |
| { |
| XDrawBeveledButton(display,&windows->command,&selection_info[i]); |
| if (i >= (int) windows->command.data) |
| continue; |
| toggle_info.raised=i == id ? MagickTrue : MagickFalse; |
| toggle_info.y=selection_info[i].y+ |
| (selection_info[i].height >> 1)-(toggle_info.height >> 1); |
| XDrawTriangleEast(display,&windows->command,&toggle_info); |
| } |
| XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset); |
| } |
| return(id); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X C o n f i r m W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XConfirmWidget() displays a Confirm widget with a notice to the user. The |
| % function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes. |
| % |
| % The format of the XConfirmWidget method is: |
| % |
| % int XConfirmWidget(Display *display,XWindows *windows, |
| % const char *reason,const char *description) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o reason: Specifies the message to display before terminating the |
| % program. |
| % |
| % o description: Specifies any description to the message. |
| % |
| */ |
| MagickExport int XConfirmWidget(Display *display,XWindows *windows, |
| const char *reason,const char *description) |
| { |
| #define CancelButtonText "Cancel" |
| #define DismissButtonText "Dismiss" |
| #define YesButtonText "Yes" |
| |
| int |
| confirm, |
| x, |
| y; |
| |
| Status |
| status; |
| |
| unsigned int |
| height, |
| width; |
| |
| size_t |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| cancel_info, |
| dismiss_info, |
| yes_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine Confirm widget attributes. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(reason != (char *) NULL); |
| assert(description != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason); |
| XCheckRefreshWindows(display,windows); |
| font_info=windows->widget.font_info; |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| if (WidgetTextWidth(font_info,DismissButtonText) > width) |
| width=WidgetTextWidth(font_info,DismissButtonText); |
| if (WidgetTextWidth(font_info,YesButtonText) > width) |
| width=WidgetTextWidth(font_info,YesButtonText); |
| width<<=1; |
| if (description != (char *) NULL) |
| if (WidgetTextWidth(font_info,(char *) description) > width) |
| width=WidgetTextWidth(font_info,(char *) description); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Confirm widget. |
| */ |
| windows->widget.width=(unsigned int) (width+9*QuantumMargin); |
| windows->widget.min_width=(unsigned int) (9*QuantumMargin+ |
| WidgetTextWidth(font_info,CancelButtonText)+ |
| WidgetTextWidth(font_info,DismissButtonText)+ |
| WidgetTextWidth(font_info,YesButtonText)); |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) (12*height); |
| windows->widget.min_height=(unsigned int) (7*height); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Confirm widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| confirm=0; |
| state=UpdateConfigurationState; |
| XSetCursorState(display,windows,MagickTrue); |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=(unsigned int) QuantumMargin+ |
| WidgetTextWidth(font_info,CancelButtonText); |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) (windows->widget.width-cancel_info.width- |
| QuantumMargin); |
| cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1)); |
| dismiss_info=cancel_info; |
| dismiss_info.text=(char *) DismissButtonText; |
| if (LocaleCompare(description,"Do you want to save it") == 0) |
| dismiss_info.text=(char *) "Don't Save"; |
| dismiss_info.width=(unsigned int) QuantumMargin+ |
| WidgetTextWidth(font_info,dismiss_info.text); |
| dismiss_info.x=(int) |
| ((windows->widget.width >> 1)-(dismiss_info.width >> 1)); |
| yes_info=cancel_info; |
| yes_info.text=(char *) YesButtonText; |
| if (LocaleCompare(description,"Do you want to save it") == 0) |
| yes_info.text=(char *) "Save"; |
| yes_info.width=(unsigned int) QuantumMargin+ |
| WidgetTextWidth(font_info,yes_info.text); |
| if (yes_info.width < cancel_info.width) |
| yes_info.width=cancel_info.width; |
| yes_info.x=QuantumMargin; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Confirm widget. |
| */ |
| width=WidgetTextWidth(font_info,(char *) reason); |
| x=(int) ((windows->widget.width >> 1)-(width >> 1)); |
| y=(int) ((windows->widget.height >> 1)-(height << 1)); |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,(char *) reason,Extent(reason)); |
| if (description != (char *) NULL) |
| { |
| char |
| question[MaxTextExtent]; |
| |
| (void) CopyMagickString(question,description,MaxTextExtent); |
| (void) ConcatenateMagickString(question,"?",MaxTextExtent); |
| width=WidgetTextWidth(font_info,question); |
| x=(int) ((windows->widget.width >> 1)-(width >> 1)); |
| y+=height; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,question,Extent(question)); |
| } |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| XDrawBeveledButton(display,&windows->widget,&yes_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~RedrawWidgetState); |
| } |
| /* |
| Wait for next event. |
| */ |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed No button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| { |
| /* |
| User pressed Dismiss button. |
| */ |
| dismiss_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| if (MatteIsActive(yes_info,event.xbutton)) |
| { |
| /* |
| User pressed Yes button. |
| */ |
| yes_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&yes_info); |
| break; |
| } |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| confirm=0; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| if (dismiss_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| { |
| confirm=(-1); |
| state|=ExitState; |
| } |
| dismiss_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| } |
| if (yes_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(yes_info,event.xbutton)) |
| { |
| confirm=1; |
| state|=ExitState; |
| } |
| yes_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&yes_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| yes_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&yes_info); |
| confirm=1; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (state & InactiveWidgetState) |
| break; |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) |
| { |
| /* |
| Dismiss button status changed. |
| */ |
| dismiss_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| if (yes_info.raised == MatteIsActive(yes_info,event.xmotion)) |
| { |
| /* |
| Yes button status changed. |
| */ |
| yes_info.raised=yes_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&yes_info); |
| break; |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| return(confirm); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X D i a l o g W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XDialogWidget() displays a Dialog widget with a query to the user. The user |
| % keys a reply and presses the Ok or Cancel button to exit. The typed text is |
| % returned as the reply function parameter. |
| % |
| % The format of the XDialogWidget method is: |
| % |
| % int XDialogWidget(Display *display,XWindows *windows,const char *action, |
| % const char *query,char *reply) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o action: Specifies a pointer to the action of this widget. |
| % |
| % o query: Specifies a pointer to the query to present to the user. |
| % |
| % o reply: the response from the user is returned in this parameter. |
| % |
| */ |
| MagickExport int XDialogWidget(Display *display,XWindows *windows, |
| const char *action,const char *query,char *reply) |
| { |
| #define CancelButtonText "Cancel" |
| |
| char |
| primary_selection[MaxTextExtent]; |
| |
| int |
| x; |
| |
| register int |
| i; |
| |
| static MagickBooleanType |
| raised = MagickFalse; |
| |
| Status |
| status; |
| |
| unsigned int |
| anomaly, |
| height, |
| width; |
| |
| size_t |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| action_info, |
| cancel_info, |
| reply_info, |
| special_info, |
| text_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine Dialog widget attributes. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(action != (char *) NULL); |
| assert(query != (char *) NULL); |
| assert(reply != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); |
| XCheckRefreshWindows(display,windows); |
| font_info=windows->widget.font_info; |
| width=WidgetTextWidth(font_info,(char *) action); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| width+=(3*QuantumMargin) >> 1; |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Dialog widget. |
| */ |
| windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int) |
| WidgetTextWidth(font_info,(char *) query)); |
| if (windows->widget.width < WidgetTextWidth(font_info,reply)) |
| windows->widget.width=WidgetTextWidth(font_info,reply); |
| windows->widget.width+=6*QuantumMargin; |
| windows->widget.min_width=(unsigned int) |
| (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin); |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1)); |
| windows->widget.min_height=windows->widget.height; |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Dialog widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| anomaly=(LocaleCompare(action,"Background") == 0) || |
| (LocaleCompare(action,"New") == 0) || |
| (LocaleCompare(action,"Quantize") == 0) || |
| (LocaleCompare(action,"Resize") == 0) || |
| (LocaleCompare(action,"Save") == 0) || |
| (LocaleCompare(action,"Shade") == 0); |
| state=UpdateConfigurationState; |
| XSetCursorState(display,windows,MagickTrue); |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) |
| (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1)); |
| cancel_info.y=(int) |
| (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1)); |
| XGetWidgetInfo(action,&action_info); |
| action_info.width=width; |
| action_info.height=(unsigned int) ((3*height) >> 1); |
| action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+ |
| (action_info.bevel_width << 1)); |
| action_info.y=cancel_info.y; |
| /* |
| Initialize reply information. |
| */ |
| XGetWidgetInfo(reply,&reply_info); |
| reply_info.raised=MagickFalse; |
| reply_info.bevel_width--; |
| reply_info.width=windows->widget.width-(3*QuantumMargin); |
| reply_info.height=height << 1; |
| reply_info.x=(3*QuantumMargin) >> 1; |
| reply_info.y=action_info.y-reply_info.height-QuantumMargin; |
| /* |
| Initialize option information. |
| */ |
| XGetWidgetInfo("Dither",&special_info); |
| special_info.raised=raised; |
| special_info.bevel_width--; |
| special_info.width=(unsigned int) QuantumMargin >> 1; |
| special_info.height=(unsigned int) QuantumMargin >> 1; |
| special_info.x=reply_info.x; |
| special_info.y=action_info.y+action_info.height-special_info.height; |
| if (LocaleCompare(action,"Background") == 0) |
| special_info.text=(char *) "Backdrop"; |
| if (LocaleCompare(action,"New") == 0) |
| special_info.text=(char *) "Gradation"; |
| if (LocaleCompare(action,"Resize") == 0) |
| special_info.text=(char *) "Constrain ratio"; |
| if (LocaleCompare(action,"Save") == 0) |
| special_info.text=(char *) "Non-progressive"; |
| if (LocaleCompare(action,"Shade") == 0) |
| special_info.text=(char *) "Color shading"; |
| /* |
| Initialize text information. |
| */ |
| XGetWidgetInfo(query,&text_info); |
| text_info.width=reply_info.width; |
| text_info.height=height; |
| text_info.x=reply_info.x-(QuantumMargin >> 1); |
| text_info.y=QuantumMargin; |
| text_info.center=MagickFalse; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Dialog widget. |
| */ |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawBeveledMatte(display,&windows->widget,&reply_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| if (anomaly) |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~RedrawWidgetState); |
| } |
| /* |
| Wait for next event. |
| */ |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (anomaly) |
| if (MatteIsActive(special_info,event.xbutton)) |
| { |
| /* |
| Option button status changed. |
| */ |
| special_info.raised=!special_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| break; |
| } |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| /* |
| User pressed Action button. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| if (event.xbutton.button != Button2) |
| { |
| static Time |
| click_time; |
| |
| /* |
| Move text cursor to position of button press. |
| */ |
| x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); |
| for (i=1; i <= Extent(reply_info.marker); i++) |
| if (XTextWidth(font_info,reply_info.marker,i) > x) |
| break; |
| reply_info.cursor=reply_info.marker+i-1; |
| if (event.xbutton.time > (click_time+DoubleClick)) |
| reply_info.highlight=MagickFalse; |
| else |
| { |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| windows->widget.id ? MagickTrue : MagickFalse; |
| } |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| click_time=event.xbutton.time; |
| break; |
| } |
| /* |
| Request primary selection. |
| */ |
| (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, |
| windows->widget.id,event.xbutton.time); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (action_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(action_info,event.xbutton)) |
| state|=ExitState; |
| action_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| state|=ExitState; |
| break; |
| } |
| if (key_symbol == XK_Control_L) |
| { |
| state|=ControlState; |
| break; |
| } |
| if (state & ControlState) |
| switch ((int) key_symbol) |
| { |
| case XK_u: |
| case XK_U: |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| reply_info.marker=reply_info.text; |
| reply_info.highlight=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| XEditText(display,&reply_info,key_symbol,command,state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| case KeyRelease: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key release. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if (key_symbol == XK_Control_L) |
| state&=(~ControlState); |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (state & InactiveWidgetState) |
| break; |
| if (action_info.raised == MatteIsActive(action_info,event.xmotion)) |
| { |
| /* |
| Action button status changed. |
| */ |
| action_info.raised=action_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| reply_info.highlight=MagickFalse; |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| case SelectionNotify: |
| { |
| Atom |
| type; |
| |
| int |
| format; |
| |
| unsigned char |
| *data; |
| |
| unsigned long |
| after, |
| length; |
| |
| /* |
| Obtain response from primary selection. |
| */ |
| if (event.xselection.property == (Atom) None) |
| break; |
| status=XGetWindowProperty(display,event.xselection.requestor, |
| event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, |
| &format,&length,&after,&data); |
| if ((status != Success) || (type != XA_STRING) || (format == 32) || |
| (length == 0)) |
| break; |
| if ((Extent(reply_info.text)+length) >= MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| /* |
| Insert primary selection in reply text. |
| */ |
| *(data+length)='\0'; |
| XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, |
| state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| } |
| (void) XFree((void *) data); |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| if (reply_info.highlight == MagickFalse) |
| break; |
| /* |
| Set primary selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False,0, |
| (XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| if (anomaly) |
| if (special_info.raised) |
| if (*reply != '\0') |
| raised=MagickTrue; |
| return(raised == MagickFalse); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X F i l e B r o w s e r W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XFileBrowserWidget() displays a File Browser widget with a file query to the |
| % user. The user keys a reply and presses the Action or Cancel button to |
| % exit. The typed text is returned as the reply function parameter. |
| % |
| % The format of the XFileBrowserWidget method is: |
| % |
| % void XFileBrowserWidget(Display *display,XWindows *windows, |
| % const char *action,char *reply) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o action: Specifies a pointer to the action of this widget. |
| % |
| % o reply: the response from the user is returned in this parameter. |
| % |
| */ |
| MagickExport void XFileBrowserWidget(Display *display,XWindows *windows, |
| const char *action,char *reply) |
| { |
| #define CancelButtonText "Cancel" |
| #define DirectoryText "Directory:" |
| #define FilenameText "File name:" |
| #define GrabButtonText "Grab" |
| #define FormatButtonText "Format" |
| #define HomeButtonText "Home" |
| #define UpButtonText "Up" |
| |
| char |
| *directory, |
| **filelist, |
| home_directory[MaxTextExtent], |
| primary_selection[MaxTextExtent], |
| text[MaxTextExtent], |
| working_path[MaxTextExtent]; |
| |
| int |
| x, |
| y; |
| |
| register ssize_t |
| i; |
| |
| static char |
| glob_pattern[MaxTextExtent] = "*", |
| format[MaxTextExtent] = "miff"; |
| |
| static MagickStatusType |
| mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); |
| |
| Status |
| status; |
| |
| unsigned int |
| anomaly, |
| height, |
| text_width, |
| visible_files, |
| width; |
| |
| size_t |
| delay, |
| files, |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| action_info, |
| cancel_info, |
| expose_info, |
| special_info, |
| list_info, |
| home_info, |
| north_info, |
| reply_info, |
| scroll_info, |
| selection_info, |
| slider_info, |
| south_info, |
| text_info, |
| up_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Read filelist from current directory. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(action != (char *) NULL); |
| assert(reply != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| directory=getcwd(home_directory,MaxTextExtent); |
| (void) directory; |
| (void) CopyMagickString(working_path,home_directory,MaxTextExtent); |
| filelist=ListFiles(working_path,glob_pattern,&files); |
| if (filelist == (char **) NULL) |
| { |
| /* |
| Directory read failed. |
| */ |
| XNoticeWidget(display,windows,"Unable to read directory:",working_path); |
| (void) XDialogWidget(display,windows,action,"Enter filename:",reply); |
| return; |
| } |
| /* |
| Determine File Browser widget attributes. |
| */ |
| font_info=windows->widget.font_info; |
| text_width=0; |
| for (i=0; i < (ssize_t) files; i++) |
| if (WidgetTextWidth(font_info,filelist[i]) > text_width) |
| text_width=WidgetTextWidth(font_info,filelist[i]); |
| width=WidgetTextWidth(font_info,(char *) action); |
| if (WidgetTextWidth(font_info,GrabButtonText) > width) |
| width=WidgetTextWidth(font_info,GrabButtonText); |
| if (WidgetTextWidth(font_info,FormatButtonText) > width) |
| width=WidgetTextWidth(font_info,FormatButtonText); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| if (WidgetTextWidth(font_info,HomeButtonText) > width) |
| width=WidgetTextWidth(font_info,HomeButtonText); |
| if (WidgetTextWidth(font_info,UpButtonText) > width) |
| width=WidgetTextWidth(font_info,UpButtonText); |
| width+=QuantumMargin; |
| if (WidgetTextWidth(font_info,DirectoryText) > width) |
| width=WidgetTextWidth(font_info,DirectoryText); |
| if (WidgetTextWidth(font_info,FilenameText) > width) |
| width=WidgetTextWidth(font_info,FilenameText); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position File Browser widget. |
| */ |
| windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+ |
| 6*QuantumMargin; |
| windows->widget.min_width=width+MinTextWidth+4*QuantumMargin; |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) |
| (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4); |
| windows->widget.min_height=(unsigned int) |
| (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map File Browser widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Browse and Select a File", |
| MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id, |
| windows->widget.screen,mask,&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| XGetWidgetInfo((char *) NULL,&slider_info); |
| XGetWidgetInfo((char *) NULL,&north_info); |
| XGetWidgetInfo((char *) NULL,&south_info); |
| XGetWidgetInfo((char *) NULL,&expose_info); |
| visible_files=0; |
| anomaly=(LocaleCompare(action,"Composite") == 0) || |
| (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0); |
| *reply='\0'; |
| delay=SuspendTime << 2; |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| int |
| id; |
| |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) |
| (windows->widget.width-cancel_info.width-QuantumMargin-2); |
| cancel_info.y=(int) |
| (windows->widget.height-cancel_info.height-QuantumMargin); |
| XGetWidgetInfo(action,&action_info); |
| action_info.width=width; |
| action_info.height=(unsigned int) ((3*height) >> 1); |
| action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ |
| (action_info.bevel_width << 1)); |
| action_info.y=cancel_info.y; |
| XGetWidgetInfo(GrabButtonText,&special_info); |
| special_info.width=width; |
| special_info.height=(unsigned int) ((3*height) >> 1); |
| special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+ |
| (special_info.bevel_width << 1)); |
| special_info.y=action_info.y; |
| if (anomaly == MagickFalse) |
| { |
| register char |
| *p; |
| |
| special_info.text=(char *) FormatButtonText; |
| p=reply+Extent(reply)-1; |
| while ((p > (reply+1)) && (*(p-1) != '.')) |
| p--; |
| if ((p > (reply+1)) && (*(p-1) == '.')) |
| (void) CopyMagickString(format,p,MaxTextExtent); |
| } |
| XGetWidgetInfo(UpButtonText,&up_info); |
| up_info.width=width; |
| up_info.height=(unsigned int) ((3*height) >> 1); |
| up_info.x=QuantumMargin; |
| up_info.y=((5*QuantumMargin) >> 1)+height; |
| XGetWidgetInfo(HomeButtonText,&home_info); |
| home_info.width=width; |
| home_info.height=(unsigned int) ((3*height) >> 1); |
| home_info.x=QuantumMargin; |
| home_info.y=up_info.y+up_info.height+QuantumMargin; |
| /* |
| Initialize reply information. |
| */ |
| XGetWidgetInfo(reply,&reply_info); |
| reply_info.raised=MagickFalse; |
| reply_info.bevel_width--; |
| reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); |
| reply_info.height=height << 1; |
| reply_info.x=(int) (width+(QuantumMargin << 1)); |
| reply_info.y=action_info.y-reply_info.height-QuantumMargin; |
| /* |
| Initialize scroll information. |
| */ |
| XGetWidgetInfo((char *) NULL,&scroll_info); |
| scroll_info.bevel_width--; |
| scroll_info.width=height; |
| scroll_info.height=(unsigned int) |
| (reply_info.y-up_info.y-(QuantumMargin >> 1)); |
| scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); |
| scroll_info.y=up_info.y-reply_info.bevel_width; |
| scroll_info.raised=MagickFalse; |
| scroll_info.trough=MagickTrue; |
| north_info=scroll_info; |
| north_info.raised=MagickTrue; |
| north_info.width-=(north_info.bevel_width << 1); |
| north_info.height=north_info.width-1; |
| north_info.x+=north_info.bevel_width; |
| north_info.y+=north_info.bevel_width; |
| south_info=north_info; |
| south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- |
| south_info.height; |
| id=slider_info.id; |
| slider_info=north_info; |
| slider_info.id=id; |
| slider_info.width-=2; |
| slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ |
| slider_info.bevel_width+2; |
| slider_info.height=scroll_info.height-((slider_info.min_y- |
| scroll_info.y+1) << 1)+4; |
| visible_files=scroll_info.height/(height+(height >> 3)); |
| if (files > visible_files) |
| slider_info.height=(unsigned int) |
| ((visible_files*slider_info.height)/files); |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.x=scroll_info.x+slider_info.bevel_width+1; |
| slider_info.y=slider_info.min_y; |
| expose_info=scroll_info; |
| expose_info.y=slider_info.y; |
| /* |
| Initialize list information. |
| */ |
| XGetWidgetInfo((char *) NULL,&list_info); |
| list_info.raised=MagickFalse; |
| list_info.bevel_width--; |
| list_info.width=(unsigned int) |
| (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); |
| list_info.height=scroll_info.height; |
| list_info.x=reply_info.x; |
| list_info.y=scroll_info.y; |
| if (windows->widget.mapped == MagickFalse) |
| state|=JumpListState; |
| /* |
| Initialize text information. |
| */ |
| *text='\0'; |
| XGetWidgetInfo(text,&text_info); |
| text_info.center=MagickFalse; |
| text_info.width=reply_info.width; |
| text_info.height=height; |
| text_info.x=list_info.x-(QuantumMargin >> 1); |
| text_info.y=QuantumMargin; |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=list_info.width; |
| selection_info.height=(unsigned int) ((9*height) >> 3); |
| selection_info.x=list_info.x; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw File Browser window. |
| */ |
| x=QuantumMargin; |
| y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,DirectoryText, |
| Extent(DirectoryText)); |
| (void) CopyMagickString(text_info.text,working_path,MaxTextExtent); |
| (void) ConcatenateMagickString(text_info.text,DirectorySeparator, |
| MaxTextExtent); |
| (void) ConcatenateMagickString(text_info.text,glob_pattern, |
| MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawBeveledButton(display,&windows->widget,&up_info); |
| XDrawBeveledButton(display,&windows->widget,&home_info); |
| XDrawBeveledMatte(display,&windows->widget,&list_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| x=QuantumMargin; |
| y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,FilenameText, |
| Extent(FilenameText)); |
| XDrawBeveledMatte(display,&windows->widget,&reply_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| state&=(~RedrawWidgetState); |
| } |
| if (state & UpdateListState) |
| { |
| char |
| **checklist; |
| |
| size_t |
| number_files; |
| |
| /* |
| Update file list. |
| */ |
| checklist=ListFiles(working_path,glob_pattern,&number_files); |
| if (checklist == (char **) NULL) |
| { |
| /* |
| Reply is a filename, exit. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| for (i=0; i < (ssize_t) files; i++) |
| filelist[i]=DestroyString(filelist[i]); |
| if (filelist != (char **) NULL) |
| filelist=(char **) RelinquishMagickMemory(filelist); |
| filelist=checklist; |
| files=number_files; |
| /* |
| Update file list. |
| */ |
| slider_info.height= |
| scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; |
| if (files > visible_files) |
| slider_info.height=(unsigned int) |
| ((visible_files*slider_info.height)/files); |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| expose_info.y=slider_info.y; |
| selection_info.id=(~0); |
| list_info.id=(~0); |
| state|=RedrawListState; |
| /* |
| Redraw directory name & reply. |
| */ |
| if (IsGlob(reply_info.text) == MagickFalse) |
| { |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| } |
| (void) CopyMagickString(text_info.text,working_path,MaxTextExtent); |
| (void) ConcatenateMagickString(text_info.text,DirectorySeparator, |
| MaxTextExtent); |
| (void) ConcatenateMagickString(text_info.text,glob_pattern, |
| MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~UpdateListState); |
| } |
| if (state & JumpListState) |
| { |
| /* |
| Jump scroll to match user filename. |
| */ |
| list_info.id=(~0); |
| for (i=0; i < (ssize_t) files; i++) |
| if (LocaleCompare(filelist[i],reply) >= 0) |
| { |
| list_info.id=(int) |
| (LocaleCompare(filelist[i],reply) == 0 ? i : ~0); |
| break; |
| } |
| if ((i < (ssize_t) slider_info.id) || |
| (i >= (ssize_t) (slider_info.id+visible_files))) |
| slider_info.id=(int) i-(visible_files >> 1); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| state&=(~JumpListState); |
| } |
| if (state & RedrawListState) |
| { |
| /* |
| Determine slider id and position. |
| */ |
| if (slider_info.id >= (int) (files-visible_files)) |
| slider_info.id=(int) (files-visible_files); |
| if ((slider_info.id < 0) || (files <= visible_files)) |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| if (files > 0) |
| slider_info.y+=(int) (slider_info.id*(slider_info.max_y- |
| slider_info.min_y+1)/files); |
| if (slider_info.id != selection_info.id) |
| { |
| /* |
| Redraw scroll bar and file names. |
| */ |
| selection_info.id=slider_info.id; |
| selection_info.y=list_info.y+(height >> 3)+2; |
| for (i=0; i < (ssize_t) visible_files; i++) |
| { |
| selection_info.raised=(int) (slider_info.id+i) != list_info.id ? |
| MagickTrue : MagickFalse; |
| selection_info.text=(char *) NULL; |
| if ((slider_info.id+i) < (ssize_t) files) |
| selection_info.text=filelist[slider_info.id+i]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| /* |
| Update slider. |
| */ |
| if (slider_info.y > expose_info.y) |
| { |
| expose_info.height=(unsigned int) slider_info.y-expose_info.y; |
| expose_info.y=slider_info.y-expose_info.height- |
| slider_info.bevel_width-1; |
| } |
| else |
| { |
| expose_info.height=(unsigned int) expose_info.y-slider_info.y; |
| expose_info.y=slider_info.y+slider_info.height+ |
| slider_info.bevel_width+1; |
| } |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawMatte(display,&windows->widget,&expose_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| expose_info.y=slider_info.y; |
| } |
| state&=(~RedrawListState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (north_info.raised && south_info.raised) |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| else |
| { |
| /* |
| Brief delay before advancing scroll bar. |
| */ |
| XDelay(display,delay); |
| delay=SuspendTime; |
| (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); |
| if (north_info.raised == MagickFalse) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| slider_info.id--; |
| state|=RedrawListState; |
| } |
| if (south_info.raised == MagickFalse) |
| if (slider_info.id < (int) files) |
| { |
| /* |
| Move slider down. |
| */ |
| slider_info.id++; |
| state|=RedrawListState; |
| } |
| if (event.type != ButtonRelease) |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(slider_info,event.xbutton)) |
| { |
| /* |
| Track slider. |
| */ |
| slider_info.active=MagickTrue; |
| break; |
| } |
| if (MatteIsActive(north_info,event.xbutton)) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| north_info.raised=MagickFalse; |
| slider_info.id--; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(south_info,event.xbutton)) |
| if (slider_info.id < (int) files) |
| { |
| /* |
| Move slider down. |
| */ |
| south_info.raised=MagickFalse; |
| slider_info.id++; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(scroll_info,event.xbutton)) |
| { |
| /* |
| Move slider. |
| */ |
| if (event.xbutton.y < slider_info.y) |
| slider_info.id-=(visible_files-1); |
| else |
| slider_info.id+=(visible_files-1); |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(list_info,event.xbutton)) |
| { |
| int |
| id; |
| |
| /* |
| User pressed file matte. |
| */ |
| id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ |
| selection_info.height; |
| if (id >= (int) files) |
| break; |
| (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent); |
| reply_info.highlight=MagickFalse; |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| if (id == list_info.id) |
| { |
| register char |
| *p; |
| |
| p=reply_info.text+strlen(reply_info.text)-1; |
| if (*p == *DirectorySeparator) |
| ChopPathComponents(reply_info.text,1); |
| (void) ConcatenateMagickString(working_path,DirectorySeparator, |
| MaxTextExtent); |
| (void) ConcatenateMagickString(working_path,reply_info.text, |
| MaxTextExtent); |
| *reply='\0'; |
| state|=UpdateListState; |
| } |
| selection_info.id=(~0); |
| list_info.id=id; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(up_info,event.xbutton)) |
| { |
| /* |
| User pressed Up button. |
| */ |
| up_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&up_info); |
| break; |
| } |
| if (MatteIsActive(home_info,event.xbutton)) |
| { |
| /* |
| User pressed Home button. |
| */ |
| home_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&home_info); |
| break; |
| } |
| if (MatteIsActive(special_info,event.xbutton)) |
| { |
| /* |
| User pressed Special button. |
| */ |
| special_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| break; |
| } |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| /* |
| User pressed action button. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| if (event.xbutton.button != Button2) |
| { |
| static Time |
| click_time; |
| |
| /* |
| Move text cursor to position of button press. |
| */ |
| x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); |
| for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++) |
| if (XTextWidth(font_info,reply_info.marker,(int) i) > x) |
| break; |
| reply_info.cursor=reply_info.marker+i-1; |
| if (event.xbutton.time > (click_time+DoubleClick)) |
| reply_info.highlight=MagickFalse; |
| else |
| { |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| windows->widget.id ? MagickTrue : MagickFalse; |
| } |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| click_time=event.xbutton.time; |
| break; |
| } |
| /* |
| Request primary selection. |
| */ |
| (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, |
| windows->widget.id,event.xbutton.time); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (north_info.raised == MagickFalse) |
| { |
| /* |
| User released up button. |
| */ |
| delay=SuspendTime << 2; |
| north_info.raised=MagickTrue; |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| } |
| if (south_info.raised == MagickFalse) |
| { |
| /* |
| User released down button. |
| */ |
| delay=SuspendTime << 2; |
| south_info.raised=MagickTrue; |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| } |
| if (slider_info.active) |
| { |
| /* |
| Stop tracking slider. |
| */ |
| slider_info.active=MagickFalse; |
| break; |
| } |
| if (up_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(up_info,event.xbutton)) |
| { |
| ChopPathComponents(working_path,1); |
| if (*working_path == '\0') |
| (void) CopyMagickString(working_path,DirectorySeparator, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| up_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&up_info); |
| } |
| if (home_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(home_info,event.xbutton)) |
| { |
| (void) CopyMagickString(working_path,home_directory, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| home_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&home_info); |
| } |
| if (special_info.raised == MagickFalse) |
| { |
| if (anomaly == MagickFalse) |
| { |
| char |
| **formats; |
| |
| ExceptionInfo |
| *exception; |
| |
| size_t |
| number_formats; |
| |
| /* |
| Let user select image format. |
| */ |
| exception=AcquireExceptionInfo(); |
| formats=GetMagickList("*",&number_formats,exception); |
| exception=DestroyExceptionInfo(exception); |
| (void) XCheckDefineCursor(display,windows->widget.id, |
| windows->widget.busy_cursor); |
| windows->popup.x=windows->widget.x+60; |
| windows->popup.y=windows->widget.y+60; |
| XListBrowserWidget(display,windows,&windows->popup, |
| (const char **) formats,"Select","Select image format type:", |
| format); |
| XSetCursorState(display,windows,MagickTrue); |
| (void) XCheckDefineCursor(display,windows->widget.id, |
| windows->widget.cursor); |
| LocaleLower(format); |
| AppendImageFormat(format,reply_info.text); |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| special_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| for (i=0; i < (ssize_t) number_formats; i++) |
| formats[i]=DestroyString(formats[i]); |
| formats=(char **) RelinquishMagickMemory(formats); |
| break; |
| } |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(special_info,event.xbutton)) |
| { |
| (void) CopyMagickString(working_path,"x:",MaxTextExtent); |
| state|=ExitState; |
| } |
| special_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| } |
| if (action_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| { |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| if (*reply_info.text == '\0') |
| (void) XBell(display,0); |
| else |
| state|=ExitState; |
| } |
| } |
| action_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| *reply_info.text='\0'; |
| *reply='\0'; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if (AreaIsActive(scroll_info,event.xkey)) |
| { |
| /* |
| Move slider. |
| */ |
| switch ((int) key_symbol) |
| { |
| case XK_Home: |
| case XK_KP_Home: |
| { |
| slider_info.id=0; |
| break; |
| } |
| case XK_Up: |
| case XK_KP_Up: |
| { |
| slider_info.id--; |
| break; |
| } |
| case XK_Down: |
| case XK_KP_Down: |
| { |
| slider_info.id++; |
| break; |
| } |
| case XK_Prior: |
| case XK_KP_Prior: |
| { |
| slider_info.id-=visible_files; |
| break; |
| } |
| case XK_Next: |
| case XK_KP_Next: |
| { |
| slider_info.id+=visible_files; |
| break; |
| } |
| case XK_End: |
| case XK_KP_End: |
| { |
| slider_info.id=(int) files; |
| break; |
| } |
| } |
| state|=RedrawListState; |
| break; |
| } |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| /* |
| Read new directory or glob patterm. |
| */ |
| if (*reply_info.text == '\0') |
| break; |
| if (IsGlob(reply_info.text)) |
| (void) CopyMagickString(glob_pattern,reply_info.text, |
| MaxTextExtent); |
| else |
| { |
| (void) ConcatenateMagickString(working_path,DirectorySeparator, |
| MaxTextExtent); |
| (void) ConcatenateMagickString(working_path,reply_info.text, |
| MaxTextExtent); |
| if (*working_path == '~') |
| ExpandFilename(working_path); |
| *reply='\0'; |
| } |
| state|=UpdateListState; |
| break; |
| } |
| if (key_symbol == XK_Control_L) |
| { |
| state|=ControlState; |
| break; |
| } |
| if (state & ControlState) |
| switch ((int) key_symbol) |
| { |
| case XK_u: |
| case XK_U: |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| reply_info.marker=reply_info.text; |
| reply_info.highlight=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| XEditText(display,&reply_info,key_symbol,command,state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| break; |
| } |
| case KeyRelease: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key release. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if (key_symbol == XK_Control_L) |
| state&=(~ControlState); |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MapNotify: |
| { |
| mask&=(~CWX); |
| mask&=(~CWY); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (slider_info.active) |
| { |
| /* |
| Move slider matte. |
| */ |
| slider_info.y=event.xmotion.y- |
| ((slider_info.height+slider_info.bevel_width) >> 1)+1; |
| if (slider_info.y < slider_info.min_y) |
| slider_info.y=slider_info.min_y; |
| if (slider_info.y > slider_info.max_y) |
| slider_info.y=slider_info.max_y; |
| slider_info.id=0; |
| if (slider_info.y != slider_info.min_y) |
| slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/ |
| (slider_info.max_y-slider_info.min_y+1)); |
| state|=RedrawListState; |
| break; |
| } |
| if (state & InactiveWidgetState) |
| break; |
| if (up_info.raised == MatteIsActive(up_info,event.xmotion)) |
| { |
| /* |
| Up button status changed. |
| */ |
| up_info.raised=!up_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&up_info); |
| break; |
| } |
| if (home_info.raised == MatteIsActive(home_info,event.xmotion)) |
| { |
| /* |
| Home button status changed. |
| */ |
| home_info.raised=!home_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&home_info); |
| break; |
| } |
| if (special_info.raised == MatteIsActive(special_info,event.xmotion)) |
| { |
| /* |
| Grab button status changed. |
| */ |
| special_info.raised=!special_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&special_info); |
| break; |
| } |
| if (action_info.raised == MatteIsActive(action_info,event.xmotion)) |
| { |
| /* |
| Action button status changed. |
| */ |
| action_info.raised=action_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| reply_info.highlight=MagickFalse; |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| case SelectionNotify: |
| { |
| Atom |
| type; |
| |
| int |
| format; |
| |
| unsigned char |
| *data; |
| |
| unsigned long |
| after, |
| length; |
| |
| /* |
| Obtain response from primary selection. |
| */ |
| if (event.xselection.property == (Atom) None) |
| break; |
| status=XGetWindowProperty(display,event.xselection.requestor, |
| event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, |
| &format,&length,&after,&data); |
| if ((status != Success) || (type != XA_STRING) || (format == 32) || |
| (length == 0)) |
| break; |
| if ((Extent(reply_info.text)+length) >= MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| /* |
| Insert primary selection in reply text. |
| */ |
| *(data+length)='\0'; |
| XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, |
| state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| state|=RedrawActionState; |
| } |
| (void) XFree((void *) data); |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| if (reply_info.highlight == MagickFalse) |
| break; |
| /* |
| Set primary selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False,0, |
| (XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| /* |
| Free file list. |
| */ |
| for (i=0; i < (ssize_t) files; i++) |
| filelist[i]=DestroyString(filelist[i]); |
| if (filelist != (char **) NULL) |
| filelist=(char **) RelinquishMagickMemory(filelist); |
| if (*reply != '\0') |
| { |
| (void) ConcatenateMagickString(working_path,DirectorySeparator, |
| MaxTextExtent); |
| (void) ConcatenateMagickString(working_path,reply,MaxTextExtent); |
| } |
| (void) CopyMagickString(reply,working_path,MaxTextExtent); |
| if (*reply == '~') |
| ExpandFilename(reply); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X F o n t B r o w s e r W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XFontBrowserWidget() displays a Font Browser widget with a font query to the |
| % user. The user keys a reply and presses the Action or Cancel button to |
| % exit. The typed text is returned as the reply function parameter. |
| % |
| % The format of the XFontBrowserWidget method is: |
| % |
| % void XFontBrowserWidget(Display *display,XWindows *windows, |
| % const char *action,char *reply) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o action: Specifies a pointer to the action of this widget. |
| % |
| % o reply: the response from the user is returned in this parameter. |
| % |
| % |
| */ |
| |
| #if defined(__cplusplus) || defined(c_plusplus) |
| extern "C" { |
| #endif |
| |
| static int FontCompare(const void *x,const void *y) |
| { |
| register char |
| *p, |
| *q; |
| |
| p=(char *) *((char **) x); |
| q=(char *) *((char **) y); |
| while ((*p != '\0') && (*q != '\0') && (*p == *q)) |
| { |
| p++; |
| q++; |
| } |
| return(*p-(*q)); |
| } |
| |
| #if defined(__cplusplus) || defined(c_plusplus) |
| } |
| #endif |
| |
| MagickExport void XFontBrowserWidget(Display *display,XWindows *windows, |
| const char *action,char *reply) |
| { |
| #define BackButtonText "Back" |
| #define CancelButtonText "Cancel" |
| #define FontnameText "Name:" |
| #define FontPatternText "Pattern:" |
| #define ResetButtonText "Reset" |
| |
| char |
| back_pattern[MaxTextExtent], |
| **fontlist, |
| **listhead, |
| primary_selection[MaxTextExtent], |
| reset_pattern[MaxTextExtent], |
| text[MaxTextExtent]; |
| |
| int |
| fonts, |
| x, |
| y; |
| |
| register int |
| i; |
| |
| static char |
| glob_pattern[MaxTextExtent] = "*"; |
| |
| static MagickStatusType |
| mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); |
| |
| Status |
| status; |
| |
| unsigned int |
| height, |
| text_width, |
| visible_fonts, |
| width; |
| |
| size_t |
| delay, |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| action_info, |
| back_info, |
| cancel_info, |
| expose_info, |
| list_info, |
| mode_info, |
| north_info, |
| reply_info, |
| reset_info, |
| scroll_info, |
| selection_info, |
| slider_info, |
| south_info, |
| text_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Get font list and sort in ascending order. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(action != (char *) NULL); |
| assert(reply != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent); |
| (void) CopyMagickString(reset_pattern,"*",MaxTextExtent); |
| fontlist=XListFonts(display,glob_pattern,32767,&fonts); |
| if (fonts == 0) |
| { |
| /* |
| Pattern failed, obtain all the fonts. |
| */ |
| XNoticeWidget(display,windows,"Unable to obtain fonts names:", |
| glob_pattern); |
| (void) CopyMagickString(glob_pattern,"*",MaxTextExtent); |
| fontlist=XListFonts(display,glob_pattern,32767,&fonts); |
| if (fontlist == (char **) NULL) |
| { |
| XNoticeWidget(display,windows,"Unable to obtain fonts names:", |
| glob_pattern); |
| return; |
| } |
| } |
| /* |
| Sort font list in ascending order. |
| */ |
| listhead=fontlist; |
| fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist)); |
| if (fontlist == (char **) NULL) |
| { |
| XNoticeWidget(display,windows,"MemoryAllocationFailed", |
| "UnableToViewFonts"); |
| return; |
| } |
| for (i=0; i < fonts; i++) |
| fontlist[i]=listhead[i]; |
| qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare); |
| /* |
| Determine Font Browser widget attributes. |
| */ |
| font_info=windows->widget.font_info; |
| text_width=0; |
| for (i=0; i < fonts; i++) |
| if (WidgetTextWidth(font_info,fontlist[i]) > text_width) |
| text_width=WidgetTextWidth(font_info,fontlist[i]); |
| width=WidgetTextWidth(font_info,(char *) action); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| if (WidgetTextWidth(font_info,ResetButtonText) > width) |
| width=WidgetTextWidth(font_info,ResetButtonText); |
| if (WidgetTextWidth(font_info,BackButtonText) > width) |
| width=WidgetTextWidth(font_info,BackButtonText); |
| width+=QuantumMargin; |
| if (WidgetTextWidth(font_info,FontPatternText) > width) |
| width=WidgetTextWidth(font_info,FontPatternText); |
| if (WidgetTextWidth(font_info,FontnameText) > width) |
| width=WidgetTextWidth(font_info,FontnameText); |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Font Browser widget. |
| */ |
| windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+ |
| 6*QuantumMargin; |
| windows->widget.min_width=width+MinTextWidth+4*QuantumMargin; |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) |
| (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4); |
| windows->widget.min_height=(unsigned int) |
| (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Font Browser widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Browse and Select a Font", |
| MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id, |
| windows->widget.screen,mask,&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| XGetWidgetInfo((char *) NULL,&slider_info); |
| XGetWidgetInfo((char *) NULL,&north_info); |
| XGetWidgetInfo((char *) NULL,&south_info); |
| XGetWidgetInfo((char *) NULL,&expose_info); |
| visible_fonts=0; |
| delay=SuspendTime << 2; |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| int |
| id; |
| |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) |
| (windows->widget.width-cancel_info.width-QuantumMargin-2); |
| cancel_info.y=(int) |
| (windows->widget.height-cancel_info.height-QuantumMargin); |
| XGetWidgetInfo(action,&action_info); |
| action_info.width=width; |
| action_info.height=(unsigned int) ((3*height) >> 1); |
| action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ |
| (action_info.bevel_width << 1)); |
| action_info.y=cancel_info.y; |
| XGetWidgetInfo(BackButtonText,&back_info); |
| back_info.width=width; |
| back_info.height=(unsigned int) ((3*height) >> 1); |
| back_info.x=QuantumMargin; |
| back_info.y=((5*QuantumMargin) >> 1)+height; |
| XGetWidgetInfo(ResetButtonText,&reset_info); |
| reset_info.width=width; |
| reset_info.height=(unsigned int) ((3*height) >> 1); |
| reset_info.x=QuantumMargin; |
| reset_info.y=back_info.y+back_info.height+QuantumMargin; |
| /* |
| Initialize reply information. |
| */ |
| XGetWidgetInfo(reply,&reply_info); |
| reply_info.raised=MagickFalse; |
| reply_info.bevel_width--; |
| reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1); |
| reply_info.height=height << 1; |
| reply_info.x=(int) (width+(QuantumMargin << 1)); |
| reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin; |
| /* |
| Initialize mode information. |
| */ |
| XGetWidgetInfo(reply,&mode_info); |
| mode_info.bevel_width=0; |
| mode_info.width=(unsigned int) |
| (action_info.x-reply_info.x-QuantumMargin); |
| mode_info.height=action_info.height << 1; |
| mode_info.x=reply_info.x; |
| mode_info.y=action_info.y-action_info.height+action_info.bevel_width; |
| /* |
| Initialize scroll information. |
| */ |
| XGetWidgetInfo((char *) NULL,&scroll_info); |
| scroll_info.bevel_width--; |
| scroll_info.width=height; |
| scroll_info.height=(unsigned int) |
| (reply_info.y-back_info.y-(QuantumMargin >> 1)); |
| scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); |
| scroll_info.y=back_info.y-reply_info.bevel_width; |
| scroll_info.raised=MagickFalse; |
| scroll_info.trough=MagickTrue; |
| north_info=scroll_info; |
| north_info.raised=MagickTrue; |
| north_info.width-=(north_info.bevel_width << 1); |
| north_info.height=north_info.width-1; |
| north_info.x+=north_info.bevel_width; |
| north_info.y+=north_info.bevel_width; |
| south_info=north_info; |
| south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- |
| south_info.height; |
| id=slider_info.id; |
| slider_info=north_info; |
| slider_info.id=id; |
| slider_info.width-=2; |
| slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ |
| slider_info.bevel_width+2; |
| slider_info.height=scroll_info.height-((slider_info.min_y- |
| scroll_info.y+1) << 1)+4; |
| visible_fonts=scroll_info.height/(height+(height >> 3)); |
| if (fonts > (int) visible_fonts) |
| slider_info.height=(visible_fonts*slider_info.height)/fonts; |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.x=scroll_info.x+slider_info.bevel_width+1; |
| slider_info.y=slider_info.min_y; |
| expose_info=scroll_info; |
| expose_info.y=slider_info.y; |
| /* |
| Initialize list information. |
| */ |
| XGetWidgetInfo((char *) NULL,&list_info); |
| list_info.raised=MagickFalse; |
| list_info.bevel_width--; |
| list_info.width=(unsigned int) |
| (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); |
| list_info.height=scroll_info.height; |
| list_info.x=reply_info.x; |
| list_info.y=scroll_info.y; |
| if (windows->widget.mapped == MagickFalse) |
| state|=JumpListState; |
| /* |
| Initialize text information. |
| */ |
| *text='\0'; |
| XGetWidgetInfo(text,&text_info); |
| text_info.center=MagickFalse; |
| text_info.width=reply_info.width; |
| text_info.height=height; |
| text_info.x=list_info.x-(QuantumMargin >> 1); |
| text_info.y=QuantumMargin; |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=list_info.width; |
| selection_info.height=(unsigned int) ((9*height) >> 3); |
| selection_info.x=list_info.x; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Font Browser window. |
| */ |
| x=QuantumMargin; |
| y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,FontPatternText, |
| Extent(FontPatternText)); |
| (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawBeveledButton(display,&windows->widget,&back_info); |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| XDrawBeveledMatte(display,&windows->widget,&list_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| x=QuantumMargin; |
| y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,FontnameText, |
| Extent(FontnameText)); |
| XDrawBeveledMatte(display,&windows->widget,&reply_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| selection_info.id=(~0); |
| state|=RedrawActionState; |
| state|=RedrawListState; |
| state&=(~RedrawWidgetState); |
| } |
| if (state & UpdateListState) |
| { |
| char |
| **checklist; |
| |
| int |
| number_fonts; |
| |
| /* |
| Update font list. |
| */ |
| checklist=XListFonts(display,glob_pattern,32767,&number_fonts); |
| if (checklist == (char **) NULL) |
| { |
| if ((strchr(glob_pattern,'*') == (char *) NULL) && |
| (strchr(glob_pattern,'?') == (char *) NULL)) |
| { |
| /* |
| Might be a scaleable font-- exit. |
| */ |
| (void) CopyMagickString(reply,glob_pattern,MaxTextExtent); |
| (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent); |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent); |
| (void) XBell(display,0); |
| } |
| else |
| if (number_fonts == 1) |
| { |
| /* |
| Reply is a single font name-- exit. |
| */ |
| (void) CopyMagickString(reply,checklist[0],MaxTextExtent); |
| (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent); |
| (void) XFreeFontNames(checklist); |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| else |
| { |
| (void) XFreeFontNames(listhead); |
| fontlist=(char **) RelinquishMagickMemory(fontlist); |
| fontlist=checklist; |
| fonts=number_fonts; |
| } |
| /* |
| Sort font list in ascending order. |
| */ |
| listhead=fontlist; |
| fontlist=(char **) AcquireQuantumMemory((size_t) fonts, |
| sizeof(*fontlist)); |
| if (fontlist == (char **) NULL) |
| { |
| XNoticeWidget(display,windows,"MemoryAllocationFailed", |
| "UnableToViewFonts"); |
| return; |
| } |
| for (i=0; i < fonts; i++) |
| fontlist[i]=listhead[i]; |
| qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare); |
| slider_info.height= |
| scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1; |
| if (fonts > (int) visible_fonts) |
| slider_info.height=(visible_fonts*slider_info.height)/fonts; |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| expose_info.y=slider_info.y; |
| selection_info.id=(~0); |
| list_info.id=(~0); |
| state|=RedrawListState; |
| /* |
| Redraw font name & reply. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent); |
| XDrawWidgetText(display,&windows->widget,&text_info); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~UpdateListState); |
| } |
| if (state & JumpListState) |
| { |
| /* |
| Jump scroll to match user font. |
| */ |
| list_info.id=(~0); |
| for (i=0; i < fonts; i++) |
| if (LocaleCompare(fontlist[i],reply) >= 0) |
| { |
| list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0; |
| break; |
| } |
| if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts))) |
| slider_info.id=i-(visible_fonts >> 1); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| state&=(~JumpListState); |
| } |
| if (state & RedrawListState) |
| { |
| /* |
| Determine slider id and position. |
| */ |
| if (slider_info.id >= (int) (fonts-visible_fonts)) |
| slider_info.id=fonts-visible_fonts; |
| if ((slider_info.id < 0) || (fonts <= (int) visible_fonts)) |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| if (fonts > 0) |
| slider_info.y+= |
| slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts; |
| if (slider_info.id != selection_info.id) |
| { |
| /* |
| Redraw scroll bar and file names. |
| */ |
| selection_info.id=slider_info.id; |
| selection_info.y=list_info.y+(height >> 3)+2; |
| for (i=0; i < (int) visible_fonts; i++) |
| { |
| selection_info.raised=(slider_info.id+i) != list_info.id ? |
| MagickTrue : MagickFalse; |
| selection_info.text=(char *) NULL; |
| if ((slider_info.id+i) < fonts) |
| selection_info.text=fontlist[slider_info.id+i]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| /* |
| Update slider. |
| */ |
| if (slider_info.y > expose_info.y) |
| { |
| expose_info.height=(unsigned int) slider_info.y-expose_info.y; |
| expose_info.y=slider_info.y-expose_info.height- |
| slider_info.bevel_width-1; |
| } |
| else |
| { |
| expose_info.height=(unsigned int) expose_info.y-slider_info.y; |
| expose_info.y=slider_info.y+slider_info.height+ |
| slider_info.bevel_width+1; |
| } |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawMatte(display,&windows->widget,&expose_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| expose_info.y=slider_info.y; |
| } |
| state&=(~RedrawListState); |
| } |
| if (state & RedrawActionState) |
| { |
| XFontStruct |
| *save_info; |
| |
| /* |
| Display the selected font in a drawing area. |
| */ |
| save_info=windows->widget.font_info; |
| font_info=XLoadQueryFont(display,reply_info.text); |
| if (font_info != (XFontStruct *) NULL) |
| { |
| windows->widget.font_info=font_info; |
| (void) XSetFont(display,windows->widget.widget_context, |
| font_info->fid); |
| } |
| XDrawBeveledButton(display,&windows->widget,&mode_info); |
| windows->widget.font_info=save_info; |
| if (font_info != (XFontStruct *) NULL) |
| { |
| (void) XSetFont(display,windows->widget.widget_context, |
| windows->widget.font_info->fid); |
| (void) XFreeFont(display,font_info); |
| } |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state&=(~RedrawActionState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (north_info.raised && south_info.raised) |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| else |
| { |
| /* |
| Brief delay before advancing scroll bar. |
| */ |
| XDelay(display,delay); |
| delay=SuspendTime; |
| (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); |
| if (north_info.raised == MagickFalse) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| slider_info.id--; |
| state|=RedrawListState; |
| } |
| if (south_info.raised == MagickFalse) |
| if (slider_info.id < fonts) |
| { |
| /* |
| Move slider down. |
| */ |
| slider_info.id++; |
| state|=RedrawListState; |
| } |
| if (event.type != ButtonRelease) |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(slider_info,event.xbutton)) |
| { |
| /* |
| Track slider. |
| */ |
| slider_info.active=MagickTrue; |
| break; |
| } |
| if (MatteIsActive(north_info,event.xbutton)) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| north_info.raised=MagickFalse; |
| slider_info.id--; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(south_info,event.xbutton)) |
| if (slider_info.id < fonts) |
| { |
| /* |
| Move slider down. |
| */ |
| south_info.raised=MagickFalse; |
| slider_info.id++; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(scroll_info,event.xbutton)) |
| { |
| /* |
| Move slider. |
| */ |
| if (event.xbutton.y < slider_info.y) |
| slider_info.id-=(visible_fonts-1); |
| else |
| slider_info.id+=(visible_fonts-1); |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(list_info,event.xbutton)) |
| { |
| int |
| id; |
| |
| /* |
| User pressed list matte. |
| */ |
| id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ |
| selection_info.height; |
| if (id >= (int) fonts) |
| break; |
| (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent); |
| reply_info.highlight=MagickFalse; |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=RedrawActionState; |
| if (id == list_info.id) |
| { |
| (void) CopyMagickString(glob_pattern,reply_info.text, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| selection_info.id=(~0); |
| list_info.id=id; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(back_info,event.xbutton)) |
| { |
| /* |
| User pressed Back button. |
| */ |
| back_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&back_info); |
| break; |
| } |
| if (MatteIsActive(reset_info,event.xbutton)) |
| { |
| /* |
| User pressed Reset button. |
| */ |
| reset_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| break; |
| } |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| /* |
| User pressed action button. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| if (event.xbutton.button != Button2) |
| { |
| static Time |
| click_time; |
| |
| /* |
| Move text cursor to position of button press. |
| */ |
| x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); |
| for (i=1; i <= Extent(reply_info.marker); i++) |
| if (XTextWidth(font_info,reply_info.marker,i) > x) |
| break; |
| reply_info.cursor=reply_info.marker+i-1; |
| if (event.xbutton.time > (click_time+DoubleClick)) |
| reply_info.highlight=MagickFalse; |
| else |
| { |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| windows->widget.id ? MagickTrue : MagickFalse; |
| } |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| click_time=event.xbutton.time; |
| break; |
| } |
| /* |
| Request primary selection. |
| */ |
| (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, |
| windows->widget.id,event.xbutton.time); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (north_info.raised == MagickFalse) |
| { |
| /* |
| User released up button. |
| */ |
| delay=SuspendTime << 2; |
| north_info.raised=MagickTrue; |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| } |
| if (south_info.raised == MagickFalse) |
| { |
| /* |
| User released down button. |
| */ |
| delay=SuspendTime << 2; |
| south_info.raised=MagickTrue; |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| } |
| if (slider_info.active) |
| { |
| /* |
| Stop tracking slider. |
| */ |
| slider_info.active=MagickFalse; |
| break; |
| } |
| if (back_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(back_info,event.xbutton)) |
| { |
| (void) CopyMagickString(glob_pattern,back_pattern, |
| MaxTextExtent); |
| state|=UpdateListState; |
| } |
| back_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&back_info); |
| } |
| if (reset_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(reset_info,event.xbutton)) |
| { |
| (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent); |
| (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent); |
| state|=UpdateListState; |
| } |
| reset_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| } |
| if (action_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| { |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| if (*reply_info.text == '\0') |
| (void) XBell(display,0); |
| else |
| state|=ExitState; |
| } |
| } |
| action_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if (AreaIsActive(scroll_info,event.xkey)) |
| { |
| /* |
| Move slider. |
| */ |
| switch ((int) key_symbol) |
| { |
| case XK_Home: |
| case XK_KP_Home: |
| { |
| slider_info.id=0; |
| break; |
| } |
| case XK_Up: |
| case XK_KP_Up: |
| { |
| slider_info.id--; |
| break; |
| } |
| case XK_Down: |
| case XK_KP_Down: |
| { |
| slider_info.id++; |
| break; |
| } |
| case XK_Prior: |
| case XK_KP_Prior: |
| { |
| slider_info.id-=visible_fonts; |
| break; |
| } |
| case XK_Next: |
| case XK_KP_Next: |
| { |
| slider_info.id+=visible_fonts; |
| break; |
| } |
| case XK_End: |
| case XK_KP_End: |
| { |
| slider_info.id=fonts; |
| break; |
| } |
| } |
| state|=RedrawListState; |
| break; |
| } |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| /* |
| Read new font or glob patterm. |
| */ |
| if (*reply_info.text == '\0') |
| break; |
| (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent); |
| (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent); |
| state|=UpdateListState; |
| break; |
| } |
| if (key_symbol == XK_Control_L) |
| { |
| state|=ControlState; |
| break; |
| } |
| if (state & ControlState) |
| switch ((int) key_symbol) |
| { |
| case XK_u: |
| case XK_U: |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| reply_info.marker=reply_info.text; |
| reply_info.highlight=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| XEditText(display,&reply_info,key_symbol,command,state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| break; |
| } |
| case KeyRelease: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key release. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if (key_symbol == XK_Control_L) |
| state&=(~ControlState); |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MapNotify: |
| { |
| mask&=(~CWX); |
| mask&=(~CWY); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (slider_info.active) |
| { |
| /* |
| Move slider matte. |
| */ |
| slider_info.y=event.xmotion.y- |
| ((slider_info.height+slider_info.bevel_width) >> 1)+1; |
| if (slider_info.y < slider_info.min_y) |
| slider_info.y=slider_info.min_y; |
| if (slider_info.y > slider_info.max_y) |
| slider_info.y=slider_info.max_y; |
| slider_info.id=0; |
| if (slider_info.y != slider_info.min_y) |
| slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/ |
| (slider_info.max_y-slider_info.min_y+1); |
| state|=RedrawListState; |
| break; |
| } |
| if (state & InactiveWidgetState) |
| break; |
| if (back_info.raised == MatteIsActive(back_info,event.xmotion)) |
| { |
| /* |
| Back button status changed. |
| */ |
| back_info.raised=!back_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&back_info); |
| break; |
| } |
| if (reset_info.raised == MatteIsActive(reset_info,event.xmotion)) |
| { |
| /* |
| Reset button status changed. |
| */ |
| reset_info.raised=!reset_info.raised; |
| XDrawBeveledButton(display,&windows->widget,&reset_info); |
| break; |
| } |
| if (action_info.raised == MatteIsActive(action_info,event.xmotion)) |
| { |
| /* |
| Action button status changed. |
| */ |
| action_info.raised=action_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&action_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| reply_info.highlight=MagickFalse; |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| break; |
| } |
| case SelectionNotify: |
| { |
| Atom |
| type; |
| |
| int |
| format; |
| |
| unsigned char |
| *data; |
| |
| unsigned long |
| after, |
| length; |
| |
| /* |
| Obtain response from primary selection. |
| */ |
| if (event.xselection.property == (Atom) None) |
| break; |
| status=XGetWindowProperty(display,event.xselection.requestor, |
| event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type, |
| &format,&length,&after,&data); |
| if ((status != Success) || (type != XA_STRING) || (format == 32) || |
| (length == 0)) |
| break; |
| if ((Extent(reply_info.text)+length) >= MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| /* |
| Insert primary selection in reply text. |
| */ |
| *(data+length)='\0'; |
| XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, |
| state); |
| XDrawMatteText(display,&windows->widget,&reply_info); |
| state|=JumpListState; |
| state|=RedrawActionState; |
| } |
| (void) XFree((void *) data); |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| /* |
| Set XA_PRIMARY selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False,0, |
| (XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| /* |
| Free font list. |
| */ |
| (void) XFreeFontNames(listhead); |
| fontlist=(char **) RelinquishMagickMemory(fontlist); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X I n f o W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XInfoWidget() displays text in the Info widget. The purpose is to inform |
| % the user that what activity is currently being performed (e.g. reading |
| % an image, rotating an image, etc.). |
| % |
| % The format of the XInfoWidget method is: |
| % |
| % void XInfoWidget(Display *display,XWindows *windows,const char *activity) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o activity: This character string reflects the current activity and is |
| % displayed in the Info widget. |
| % |
| */ |
| MagickExport void XInfoWidget(Display *display,XWindows *windows, |
| const char *activity) |
| { |
| unsigned int |
| height, |
| margin, |
| width; |
| |
| XFontStruct |
| *font_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Map Info widget. |
| */ |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(activity != (char *) NULL); |
| font_info=windows->info.font_info; |
| width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4; |
| height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4); |
| if ((windows->info.width != width) || (windows->info.height != height)) |
| { |
| /* |
| Size Info widget to accommodate the activity text. |
| */ |
| windows->info.width=width; |
| windows->info.height=height; |
| window_changes.width=(int) width; |
| window_changes.height=(int) height; |
| (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen, |
| (unsigned int) (CWWidth | CWHeight),&window_changes); |
| } |
| if (windows->info.mapped == MagickFalse) |
| { |
| (void) XMapRaised(display,windows->info.id); |
| windows->info.mapped=MagickTrue; |
| } |
| /* |
| Initialize Info matte information. |
| */ |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| XGetWidgetInfo(activity,&monitor_info); |
| monitor_info.bevel_width--; |
| margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2; |
| monitor_info.center=MagickFalse; |
| monitor_info.x=(int) margin; |
| monitor_info.y=(int) margin; |
| monitor_info.width=windows->info.width-(margin << 1); |
| monitor_info.height=windows->info.height-(margin << 1)+1; |
| /* |
| Draw Info widget. |
| */ |
| monitor_info.raised=MagickFalse; |
| XDrawBeveledMatte(display,&windows->info,&monitor_info); |
| monitor_info.raised=MagickTrue; |
| XDrawWidgetText(display,&windows->info,&monitor_info); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X L i s t B r o w s e r W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XListBrowserWidget() displays a List Browser widget with a query to the |
| % user. The user keys a reply or select a reply from the list. Finally, the |
| % user presses the Action or Cancel button to exit. The typed text is |
| % returned as the reply function parameter. |
| % |
| % The format of the XListBrowserWidget method is: |
| % |
| % void XListBrowserWidget(Display *display,XWindows *windows, |
| % XWindowInfo *window_info,const char **list,const char *action, |
| % const char *query,char *reply) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o list: Specifies a pointer to an array of strings. The user can |
| % select from these strings as a possible reply value. |
| % |
| % o action: Specifies a pointer to the action of this widget. |
| % |
| % o query: Specifies a pointer to the query to present to the user. |
| % |
| % o reply: the response from the user is returned in this parameter. |
| % |
| */ |
| MagickExport void XListBrowserWidget(Display *display,XWindows *windows, |
| XWindowInfo *window_info,const char **list,const char *action, |
| const char *query,char *reply) |
| { |
| #define CancelButtonText "Cancel" |
| |
| char |
| primary_selection[MaxTextExtent]; |
| |
| int |
| x; |
| |
| register int |
| i; |
| |
| static MagickStatusType |
| mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); |
| |
| Status |
| status; |
| |
| unsigned int |
| entries, |
| height, |
| text_width, |
| visible_entries, |
| width; |
| |
| size_t |
| delay, |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| action_info, |
| cancel_info, |
| expose_info, |
| list_info, |
| north_info, |
| reply_info, |
| scroll_info, |
| selection_info, |
| slider_info, |
| south_info, |
| text_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Count the number of entries in the list. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(window_info != (XWindowInfo *) NULL); |
| assert(list != (const char **) NULL); |
| assert(action != (char *) NULL); |
| assert(query != (char *) NULL); |
| assert(reply != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action); |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| if (list == (const char **) NULL) |
| { |
| XNoticeWidget(display,windows,"No text to browse:",(char *) NULL); |
| return; |
| } |
| for (entries=0; ; entries++) |
| if (list[entries] == (char *) NULL) |
| break; |
| /* |
| Determine Font Browser widget attributes. |
| */ |
| font_info=window_info->font_info; |
| text_width=WidgetTextWidth(font_info,(char *) query); |
| for (i=0; i < (int) entries; i++) |
| if (WidgetTextWidth(font_info,(char *) list[i]) > text_width) |
| text_width=WidgetTextWidth(font_info,(char *) list[i]); |
| width=WidgetTextWidth(font_info,(char *) action); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| width+=QuantumMargin; |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position List Browser widget. |
| */ |
| window_info->width=(unsigned int) MagickMin((int) text_width,(int) |
| MaxTextWidth)+((9*QuantumMargin) >> 1); |
| window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin); |
| if (window_info->width < window_info->min_width) |
| window_info->width=window_info->min_width; |
| window_info->height=(unsigned int) |
| (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4); |
| window_info->min_height=(unsigned int) |
| (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4); |
| if (window_info->height < window_info->min_height) |
| window_info->height=window_info->min_height; |
| XConstrainWindowPosition(display,window_info); |
| /* |
| Map List Browser widget. |
| */ |
| (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent); |
| status=XStringListToTextProperty(&window_info->name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,window_info->id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) window_info->width; |
| window_changes.height=(int) window_info->height; |
| window_changes.x=window_info->x; |
| window_changes.y=window_info->y; |
| (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask, |
| &window_changes); |
| (void) XMapRaised(display,window_info->id); |
| window_info->mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| XGetWidgetInfo((char *) NULL,&slider_info); |
| XGetWidgetInfo((char *) NULL,&north_info); |
| XGetWidgetInfo((char *) NULL,&south_info); |
| XGetWidgetInfo((char *) NULL,&expose_info); |
| visible_entries=0; |
| delay=SuspendTime << 2; |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| int |
| id; |
| |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) ((3*height) >> 1); |
| cancel_info.x=(int) |
| (window_info->width-cancel_info.width-QuantumMargin-2); |
| cancel_info.y=(int) |
| (window_info->height-cancel_info.height-QuantumMargin); |
| XGetWidgetInfo(action,&action_info); |
| action_info.width=width; |
| action_info.height=(unsigned int) ((3*height) >> 1); |
| action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+ |
| (action_info.bevel_width << 1)); |
| action_info.y=cancel_info.y; |
| /* |
| Initialize reply information. |
| */ |
| XGetWidgetInfo(reply,&reply_info); |
| reply_info.raised=MagickFalse; |
| reply_info.bevel_width--; |
| reply_info.width=window_info->width-((4*QuantumMargin) >> 1); |
| reply_info.height=height << 1; |
| reply_info.x=QuantumMargin; |
| reply_info.y=action_info.y-reply_info.height-QuantumMargin; |
| /* |
| Initialize scroll information. |
| */ |
| XGetWidgetInfo((char *) NULL,&scroll_info); |
| scroll_info.bevel_width--; |
| scroll_info.width=height; |
| scroll_info.height=(unsigned int) |
| (reply_info.y-((6*QuantumMargin) >> 1)-height); |
| scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width); |
| scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width; |
| scroll_info.raised=MagickFalse; |
| scroll_info.trough=MagickTrue; |
| north_info=scroll_info; |
| north_info.raised=MagickTrue; |
| north_info.width-=(north_info.bevel_width << 1); |
| north_info.height=north_info.width-1; |
| north_info.x+=north_info.bevel_width; |
| north_info.y+=north_info.bevel_width; |
| south_info=north_info; |
| south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- |
| south_info.height; |
| id=slider_info.id; |
| slider_info=north_info; |
| slider_info.id=id; |
| slider_info.width-=2; |
| slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ |
| slider_info.bevel_width+2; |
| slider_info.height=scroll_info.height-((slider_info.min_y- |
| scroll_info.y+1) << 1)+4; |
| visible_entries=scroll_info.height/(height+(height >> 3)); |
| if (entries > visible_entries) |
| slider_info.height=(visible_entries*slider_info.height)/entries; |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.x=scroll_info.x+slider_info.bevel_width+1; |
| slider_info.y=slider_info.min_y; |
| expose_info=scroll_info; |
| expose_info.y=slider_info.y; |
| /* |
| Initialize list information. |
| */ |
| XGetWidgetInfo((char *) NULL,&list_info); |
| list_info.raised=MagickFalse; |
| list_info.bevel_width--; |
| list_info.width=(unsigned int) |
| (scroll_info.x-reply_info.x-(QuantumMargin >> 1)); |
| list_info.height=scroll_info.height; |
| list_info.x=reply_info.x; |
| list_info.y=scroll_info.y; |
| if (window_info->mapped == MagickFalse) |
| for (i=0; i < (int) entries; i++) |
| if (LocaleCompare(list[i],reply) == 0) |
| { |
| list_info.id=i; |
| slider_info.id=i-(visible_entries >> 1); |
| if (slider_info.id < 0) |
| slider_info.id=0; |
| } |
| /* |
| Initialize text information. |
| */ |
| XGetWidgetInfo(query,&text_info); |
| text_info.width=reply_info.width; |
| text_info.height=height; |
| text_info.x=list_info.x-(QuantumMargin >> 1); |
| text_info.y=QuantumMargin; |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=list_info.width; |
| selection_info.height=(unsigned int) ((9*height) >> 3); |
| selection_info.x=list_info.x; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw List Browser window. |
| */ |
| XDrawWidgetText(display,window_info,&text_info); |
| XDrawBeveledMatte(display,window_info,&list_info); |
| XDrawBeveledMatte(display,window_info,&scroll_info); |
| XDrawTriangleNorth(display,window_info,&north_info); |
| XDrawBeveledButton(display,window_info,&slider_info); |
| XDrawTriangleSouth(display,window_info,&south_info); |
| XDrawBeveledMatte(display,window_info,&reply_info); |
| XDrawMatteText(display,window_info,&reply_info); |
| XDrawBeveledButton(display,window_info,&action_info); |
| XDrawBeveledButton(display,window_info,&cancel_info); |
| XHighlightWidget(display,window_info,BorderOffset,BorderOffset); |
| selection_info.id=(~0); |
| state|=RedrawActionState; |
| state|=RedrawListState; |
| state&=(~RedrawWidgetState); |
| } |
| if (state & RedrawListState) |
| { |
| /* |
| Determine slider id and position. |
| */ |
| if (slider_info.id >= (int) (entries-visible_entries)) |
| slider_info.id=(int) (entries-visible_entries); |
| if ((slider_info.id < 0) || (entries <= visible_entries)) |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| if (entries > 0) |
| slider_info.y+= |
| slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries; |
| if (slider_info.id != selection_info.id) |
| { |
| /* |
| Redraw scroll bar and file names. |
| */ |
| selection_info.id=slider_info.id; |
| selection_info.y=list_info.y+(height >> 3)+2; |
| for (i=0; i < (int) visible_entries; i++) |
| { |
| selection_info.raised=(slider_info.id+i) != list_info.id ? |
| MagickTrue : MagickFalse; |
| selection_info.text=(char *) NULL; |
| if ((slider_info.id+i) < (int) entries) |
| selection_info.text=(char *) list[slider_info.id+i]; |
| XDrawWidgetText(display,window_info,&selection_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| /* |
| Update slider. |
| */ |
| if (slider_info.y > expose_info.y) |
| { |
| expose_info.height=(unsigned int) slider_info.y-expose_info.y; |
| expose_info.y=slider_info.y-expose_info.height- |
| slider_info.bevel_width-1; |
| } |
| else |
| { |
| expose_info.height=(unsigned int) expose_info.y-slider_info.y; |
| expose_info.y=slider_info.y+slider_info.height+ |
| slider_info.bevel_width+1; |
| } |
| XDrawTriangleNorth(display,window_info,&north_info); |
| XDrawMatte(display,window_info,&expose_info); |
| XDrawBeveledButton(display,window_info,&slider_info); |
| XDrawTriangleSouth(display,window_info,&south_info); |
| expose_info.y=slider_info.y; |
| } |
| state&=(~RedrawListState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (north_info.raised && south_info.raised) |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| else |
| { |
| /* |
| Brief delay before advancing scroll bar. |
| */ |
| XDelay(display,delay); |
| delay=SuspendTime; |
| (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); |
| if (north_info.raised == MagickFalse) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| slider_info.id--; |
| state|=RedrawListState; |
| } |
| if (south_info.raised == MagickFalse) |
| if (slider_info.id < (int) entries) |
| { |
| /* |
| Move slider down. |
| */ |
| slider_info.id++; |
| state|=RedrawListState; |
| } |
| if (event.type != ButtonRelease) |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(slider_info,event.xbutton)) |
| { |
| /* |
| Track slider. |
| */ |
| slider_info.active=MagickTrue; |
| break; |
| } |
| if (MatteIsActive(north_info,event.xbutton)) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| north_info.raised=MagickFalse; |
| slider_info.id--; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(south_info,event.xbutton)) |
| if (slider_info.id < (int) entries) |
| { |
| /* |
| Move slider down. |
| */ |
| south_info.raised=MagickFalse; |
| slider_info.id++; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(scroll_info,event.xbutton)) |
| { |
| /* |
| Move slider. |
| */ |
| if (event.xbutton.y < slider_info.y) |
| slider_info.id-=(visible_entries-1); |
| else |
| slider_info.id+=(visible_entries-1); |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(list_info,event.xbutton)) |
| { |
| int |
| id; |
| |
| /* |
| User pressed list matte. |
| */ |
| id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ |
| selection_info.height; |
| if (id >= (int) entries) |
| break; |
| (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent); |
| reply_info.highlight=MagickFalse; |
| reply_info.marker=reply_info.text; |
| reply_info.cursor=reply_info.text+Extent(reply_info.text); |
| XDrawMatteText(display,window_info,&reply_info); |
| selection_info.id=(~0); |
| if (id == list_info.id) |
| { |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,window_info,&action_info); |
| state|=ExitState; |
| } |
| list_info.id=id; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| /* |
| User pressed action button. |
| */ |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,window_info,&action_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,window_info,&cancel_info); |
| break; |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| if (event.xbutton.button != Button2) |
| { |
| static Time |
| click_time; |
| |
| /* |
| Move text cursor to position of button press. |
| */ |
| x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2); |
| for (i=1; i <= Extent(reply_info.marker); i++) |
| if (XTextWidth(font_info,reply_info.marker,i) > x) |
| break; |
| reply_info.cursor=reply_info.marker+i-1; |
| if (event.xbutton.time > (click_time+DoubleClick)) |
| reply_info.highlight=MagickFalse; |
| else |
| { |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,reply_info.text, |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id, |
| event.xbutton.time); |
| reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) == |
| window_info->id ? MagickTrue : MagickFalse; |
| } |
| XDrawMatteText(display,window_info,&reply_info); |
| click_time=event.xbutton.time; |
| break; |
| } |
| /* |
| Request primary selection. |
| */ |
| (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, |
| window_info->id,event.xbutton.time); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (window_info->mapped == MagickFalse) |
| break; |
| if (north_info.raised == MagickFalse) |
| { |
| /* |
| User released up button. |
| */ |
| delay=SuspendTime << 2; |
| north_info.raised=MagickTrue; |
| XDrawTriangleNorth(display,window_info,&north_info); |
| } |
| if (south_info.raised == MagickFalse) |
| { |
| /* |
| User released down button. |
| */ |
| delay=SuspendTime << 2; |
| south_info.raised=MagickTrue; |
| XDrawTriangleSouth(display,window_info,&south_info); |
| } |
| if (slider_info.active) |
| { |
| /* |
| Stop tracking slider. |
| */ |
| slider_info.active=MagickFalse; |
| break; |
| } |
| if (action_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == window_info->id) |
| { |
| if (MatteIsActive(action_info,event.xbutton)) |
| { |
| if (*reply_info.text == '\0') |
| (void) XBell(display,0); |
| else |
| state|=ExitState; |
| } |
| } |
| action_info.raised=MagickTrue; |
| XDrawBeveledButton(display,window_info,&action_info); |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == window_info->id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| } |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,window_info,&cancel_info); |
| } |
| if (MatteIsActive(reply_info,event.xbutton) == MagickFalse) |
| break; |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == window_info->id) |
| { |
| *reply_info.text='\0'; |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != window_info->id) |
| break; |
| if ((event.xconfigure.width == (int) window_info->width) && |
| (event.xconfigure.height == (int) window_info->height)) |
| break; |
| window_info->width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) window_info->min_width); |
| window_info->height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) window_info->min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != window_info->id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != window_info->id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != window_info->id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if (AreaIsActive(scroll_info,event.xkey)) |
| { |
| /* |
| Move slider. |
| */ |
| switch ((int) key_symbol) |
| { |
| case XK_Home: |
| case XK_KP_Home: |
| { |
| slider_info.id=0; |
| break; |
| } |
| case XK_Up: |
| case XK_KP_Up: |
| { |
| slider_info.id--; |
| break; |
| } |
| case XK_Down: |
| case XK_KP_Down: |
| { |
| slider_info.id++; |
| break; |
| } |
| case XK_Prior: |
| case XK_KP_Prior: |
| { |
| slider_info.id-=visible_entries; |
| break; |
| } |
| case XK_Next: |
| case XK_KP_Next: |
| { |
| slider_info.id+=visible_entries; |
| break; |
| } |
| case XK_End: |
| case XK_KP_End: |
| { |
| slider_info.id=(int) entries; |
| break; |
| } |
| } |
| state|=RedrawListState; |
| break; |
| } |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| /* |
| Read new entry. |
| */ |
| if (*reply_info.text == '\0') |
| break; |
| action_info.raised=MagickFalse; |
| XDrawBeveledButton(display,window_info,&action_info); |
| state|=ExitState; |
| break; |
| } |
| if (key_symbol == XK_Control_L) |
| { |
| state|=ControlState; |
| break; |
| } |
| if (state & ControlState) |
| switch ((int) key_symbol) |
| { |
| case XK_u: |
| case XK_U: |
| { |
| /* |
| Erase the entire line of text. |
| */ |
| *reply_info.text='\0'; |
| reply_info.cursor=reply_info.text; |
| reply_info.marker=reply_info.text; |
| reply_info.highlight=MagickFalse; |
| break; |
| } |
| default: |
| break; |
| } |
| XEditText(display,&reply_info,key_symbol,command,state); |
| XDrawMatteText(display,window_info,&reply_info); |
| break; |
| } |
| case KeyRelease: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key release. |
| */ |
| if (event.xkey.window != window_info->id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if (key_symbol == XK_Control_L) |
| state&=(~ControlState); |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != window_info->id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MapNotify: |
| { |
| mask&=(~CWX); |
| mask&=(~CWY); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (slider_info.active) |
| { |
| /* |
| Move slider matte. |
| */ |
| slider_info.y=event.xmotion.y- |
| ((slider_info.height+slider_info.bevel_width) >> 1)+1; |
| if (slider_info.y < slider_info.min_y) |
| slider_info.y=slider_info.min_y; |
| if (slider_info.y > slider_info.max_y) |
| slider_info.y=slider_info.max_y; |
| slider_info.id=0; |
| if (slider_info.y != slider_info.min_y) |
| slider_info.id=(int) ((entries*(slider_info.y- |
| slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1)); |
| state|=RedrawListState; |
| break; |
| } |
| if (state & InactiveWidgetState) |
| break; |
| if (action_info.raised == MatteIsActive(action_info,event.xmotion)) |
| { |
| /* |
| Action button status changed. |
| */ |
| action_info.raised=action_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,window_info,&action_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised=cancel_info.raised == MagickFalse ? |
| MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,window_info,&cancel_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| reply_info.highlight=MagickFalse; |
| XDrawMatteText(display,window_info,&reply_info); |
| break; |
| } |
| case SelectionNotify: |
| { |
| Atom |
| type; |
| |
| int |
| format; |
| |
| unsigned char |
| *data; |
| |
| unsigned long |
| after, |
| length; |
| |
| /* |
| Obtain response from primary selection. |
| */ |
| if (event.xselection.property == (Atom) None) |
| break; |
| status=XGetWindowProperty(display, |
| event.xselection.requestor,event.xselection.property,0L,2047L, |
| MagickTrue,XA_STRING,&type,&format,&length,&after,&data); |
| if ((status != Success) || (type != XA_STRING) || (format == 32) || |
| (length == 0)) |
| break; |
| if ((Extent(reply_info.text)+length) >= MaxTextExtent) |
| (void) XBell(display,0); |
| else |
| { |
| /* |
| Insert primary selection in reply text. |
| */ |
| *(data+length)='\0'; |
| XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data, |
| state); |
| XDrawMatteText(display,window_info,&reply_info); |
| state|=RedrawActionState; |
| } |
| (void) XFree((void *) data); |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| if (reply_info.highlight == MagickFalse) |
| break; |
| /* |
| Set primary selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.send_event=MagickTrue; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False,NoEventMask, |
| (XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,window_info->id,window_info->screen); |
| XCheckRefreshWindows(display,windows); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X M e n u W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XMenuWidget() maps a menu and returns the command pointed to by the user |
| % when the button is released. |
| % |
| % The format of the XMenuWidget method is: |
| % |
| % int XMenuWidget(Display *display,XWindows *windows,const char *title, |
| % const char **selections,char *item) |
| % |
| % A description of each parameter follows: |
| % |
| % o selection_number: Specifies the number of the selection that the |
| % user choose. |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o title: Specifies a character string that describes the menu selections. |
| % |
| % o selections: Specifies a pointer to one or more strings that comprise |
| % the choices in the menu. |
| % |
| % o item: Specifies a character array. The item selected from the menu |
| % is returned here. |
| % |
| */ |
| MagickExport int XMenuWidget(Display *display,XWindows *windows, |
| const char *title,const char **selections,char *item) |
| { |
| Cursor |
| cursor; |
| |
| int |
| id, |
| x, |
| y; |
| |
| unsigned int |
| height, |
| number_selections, |
| title_height, |
| top_offset, |
| width; |
| |
| size_t |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XSetWindowAttributes |
| window_attributes; |
| |
| XWidgetInfo |
| highlight_info, |
| menu_info, |
| selection_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine Menu widget attributes. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(title != (char *) NULL); |
| assert(selections != (const char **) NULL); |
| assert(item != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title); |
| font_info=windows->widget.font_info; |
| windows->widget.width=submenu_info.active == 0 ? |
| WidgetTextWidth(font_info,(char *) title) : 0; |
| for (id=0; selections[id] != (char *) NULL; id++) |
| { |
| width=WidgetTextWidth(font_info,(char *) selections[id]); |
| if (width > windows->widget.width) |
| windows->widget.width=width; |
| } |
| number_selections=(unsigned int) id; |
| XGetWidgetInfo((char *) NULL,&menu_info); |
| title_height=(unsigned int) (submenu_info.active == 0 ? |
| (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2); |
| width=WidgetTextWidth(font_info,(char *) title); |
| height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1); |
| /* |
| Position Menu widget. |
| */ |
| windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1); |
| top_offset=title_height+menu_info.bevel_width-1; |
| windows->widget.height=top_offset+number_selections*height+4; |
| windows->widget.min_width=windows->widget.width; |
| windows->widget.min_height=windows->widget.height; |
| XQueryPosition(display,windows->widget.root,&x,&y); |
| windows->widget.x=x-(QuantumMargin >> 1); |
| if (submenu_info.active != 0) |
| { |
| windows->widget.x= |
| windows->command.x+windows->command.width-QuantumMargin; |
| toggle_info.raised=MagickTrue; |
| XDrawTriangleEast(display,&windows->command,&toggle_info); |
| } |
| windows->widget.y=submenu_info.active == 0 ? y-(int) |
| ((3*title_height) >> 2) : y; |
| if (submenu_info.active != 0) |
| windows->widget.y=windows->command.y+submenu_info.y; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Menu widget. |
| */ |
| window_attributes.override_redirect=MagickTrue; |
| (void) XChangeWindowAttributes(display,windows->widget.id, |
| (size_t) CWOverrideRedirect,&window_attributes); |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| selection_info.height=height; |
| cursor=XCreateFontCursor(display,XC_right_ptr); |
| (void) XCheckDefineCursor(display,windows->image.id,cursor); |
| (void) XCheckDefineCursor(display,windows->command.id,cursor); |
| (void) XCheckDefineCursor(display,windows->widget.id,cursor); |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&menu_info); |
| menu_info.bevel_width--; |
| menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1); |
| menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1); |
| menu_info.x=(int) menu_info.bevel_width; |
| menu_info.y=(int) menu_info.bevel_width; |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=menu_info.width; |
| selection_info.height=height; |
| selection_info.x=menu_info.x; |
| highlight_info=selection_info; |
| highlight_info.bevel_width--; |
| highlight_info.width-=(highlight_info.bevel_width << 1); |
| highlight_info.height-=(highlight_info.bevel_width << 1); |
| highlight_info.x+=highlight_info.bevel_width; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Menu widget. |
| */ |
| if (submenu_info.active == 0) |
| { |
| y=(int) title_height; |
| XSetBevelColor(display,&windows->widget,MagickFalse); |
| (void) XDrawLine(display,windows->widget.id, |
| windows->widget.widget_context,selection_info.x,y-1, |
| (int) selection_info.width,y-1); |
| XSetBevelColor(display,&windows->widget,MagickTrue); |
| (void) XDrawLine(display,windows->widget.id, |
| windows->widget.widget_context,selection_info.x,y, |
| (int) selection_info.width,y); |
| (void) XSetFillStyle(display,windows->widget.widget_context, |
| FillSolid); |
| } |
| /* |
| Draw menu selections. |
| */ |
| selection_info.center=MagickTrue; |
| selection_info.y=(int) menu_info.bevel_width; |
| selection_info.text=(char *) title; |
| if (submenu_info.active == 0) |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.y=(int) top_offset; |
| for (id=0; id < (int) number_selections; id++) |
| { |
| selection_info.text=(char *) selections[id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| highlight_info.y=selection_info.y+highlight_info.bevel_width; |
| if (id == selection_info.id) |
| XDrawBevel(display,&windows->widget,&highlight_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| XDrawBevel(display,&windows->widget,&menu_info); |
| state&=(~RedrawWidgetState); |
| } |
| if (number_selections > 2) |
| { |
| /* |
| Redraw Menu line. |
| */ |
| y=(int) (top_offset+selection_info.height*(number_selections-1)); |
| XSetBevelColor(display,&windows->widget,MagickFalse); |
| (void) XDrawLine(display,windows->widget.id, |
| windows->widget.widget_context,selection_info.x,y-1, |
| (int) selection_info.width,y-1); |
| XSetBevelColor(display,&windows->widget,MagickTrue); |
| (void) XDrawLine(display,windows->widget.id, |
| windows->widget.widget_context,selection_info.x,y, |
| (int) selection_info.width,y); |
| (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid); |
| } |
| /* |
| Wait for next event. |
| */ |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (event.xbutton.window != windows->widget.id) |
| { |
| /* |
| exit menu. |
| */ |
| if (event.xbutton.window == windows->command.id) |
| (void) XPutBackEvent(display,&event); |
| selection_info.id=(~0); |
| *item='\0'; |
| state|=ExitState; |
| break; |
| } |
| state&=(~InactiveWidgetState); |
| id=(event.xbutton.y-top_offset)/(int) selection_info.height; |
| selection_info.id=id; |
| if ((id < 0) || (id >= (int) number_selections)) |
| break; |
| /* |
| Highlight this selection. |
| */ |
| selection_info.y=(int) (top_offset+id*selection_info.height); |
| selection_info.text=(char *) selections[id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| highlight_info.y=selection_info.y+highlight_info.bevel_width; |
| XDrawBevel(display,&windows->widget,&highlight_info); |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (event.xbutton.window == windows->command.id) |
| if ((state & InactiveWidgetState) == 0) |
| break; |
| /* |
| exit menu. |
| */ |
| XSetCursorState(display,windows,MagickFalse); |
| *item='\0'; |
| state|=ExitState; |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| if (event.xcrossing.state == 0) |
| break; |
| state&=(~InactiveWidgetState); |
| id=((event.xcrossing.y-top_offset)/(int) selection_info.height); |
| if ((selection_info.id >= 0) && |
| (selection_info.id < (int) number_selections)) |
| { |
| /* |
| Unhighlight last selection. |
| */ |
| if (id == selection_info.id) |
| break; |
| selection_info.y=(int) |
| (top_offset+selection_info.id*selection_info.height); |
| selection_info.text=(char *) selections[selection_info.id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| } |
| if ((id < 0) || (id >= (int) number_selections)) |
| break; |
| /* |
| Highlight this selection. |
| */ |
| selection_info.id=id; |
| selection_info.y=(int) |
| (top_offset+selection_info.id*selection_info.height); |
| selection_info.text=(char *) selections[selection_info.id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| highlight_info.y=selection_info.y+highlight_info.bevel_width; |
| XDrawBevel(display,&windows->widget,&highlight_info); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| id=selection_info.id; |
| if ((id < 0) || (id >= (int) number_selections)) |
| break; |
| /* |
| Unhighlight last selection. |
| */ |
| selection_info.y=(int) (top_offset+id*selection_info.height); |
| selection_info.id=(~0); |
| selection_info.text=(char *) selections[id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (submenu_info.active != 0) |
| if (event.xmotion.window == windows->command.id) |
| { |
| if ((state & InactiveWidgetState) == 0) |
| { |
| if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse) |
| { |
| selection_info.id=(~0); |
| *item='\0'; |
| state|=ExitState; |
| break; |
| } |
| } |
| else |
| if (WindowIsActive(windows->command,event.xmotion)) |
| { |
| selection_info.id=(~0); |
| *item='\0'; |
| state|=ExitState; |
| break; |
| } |
| } |
| if (event.xmotion.window != windows->widget.id) |
| break; |
| if (state & InactiveWidgetState) |
| break; |
| id=(event.xmotion.y-top_offset)/(int) selection_info.height; |
| if ((selection_info.id >= 0) && |
| (selection_info.id < (int) number_selections)) |
| { |
| /* |
| Unhighlight last selection. |
| */ |
| if (id == selection_info.id) |
| break; |
| selection_info.y=(int) |
| (top_offset+selection_info.id*selection_info.height); |
| selection_info.text=(char *) selections[selection_info.id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| } |
| selection_info.id=id; |
| if ((id < 0) || (id >= (int) number_selections)) |
| break; |
| /* |
| Highlight this selection. |
| */ |
| selection_info.y=(int) (top_offset+id*selection_info.height); |
| selection_info.text=(char *) selections[id]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| highlight_info.y=selection_info.y+highlight_info.bevel_width; |
| XDrawBevel(display,&windows->widget,&highlight_info); |
| break; |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| (void) XFreeCursor(display,cursor); |
| window_attributes.override_redirect=MagickFalse; |
| (void) XChangeWindowAttributes(display,windows->widget.id, |
| (size_t) CWOverrideRedirect,&window_attributes); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| if (submenu_info.active != 0) |
| { |
| submenu_info.active=MagickFalse; |
| toggle_info.raised=MagickFalse; |
| XDrawTriangleEast(display,&windows->command,&toggle_info); |
| } |
| if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections)) |
| return(~0); |
| (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent); |
| return(selection_info.id); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X N o t i c e W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XNoticeWidget() displays a Notice widget with a notice to the user. The |
| % function returns when the user presses the "Dismiss" button. |
| % |
| % The format of the XNoticeWidget method is: |
| % |
| % void XNoticeWidget(Display *display,XWindows *windows, |
| % const char *reason,const char *description) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o reason: Specifies the message to display before terminating the |
| % program. |
| % |
| % o description: Specifies any description to the message. |
| % |
| */ |
| MagickExport void XNoticeWidget(Display *display,XWindows *windows, |
| const char *reason,const char *description) |
| { |
| #define DismissButtonText "Dismiss" |
| #define Timeout 8 |
| |
| const char |
| *text; |
| |
| int |
| x, |
| y; |
| |
| Status |
| status; |
| |
| time_t |
| timer; |
| |
| unsigned int |
| height, |
| width; |
| |
| size_t |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| dismiss_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine Notice widget attributes. |
| */ |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(reason != (char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason); |
| XDelay(display,SuspendTime << 3); /* avoid surpise with delay */ |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| font_info=windows->widget.font_info; |
| width=WidgetTextWidth(font_info,DismissButtonText); |
| text=GetLocaleExceptionMessage(XServerError,reason); |
| if (text != (char *) NULL) |
| if (WidgetTextWidth(font_info,(char *) text) > width) |
| width=WidgetTextWidth(font_info,(char *) text); |
| if (description != (char *) NULL) |
| { |
| text=GetLocaleExceptionMessage(XServerError,description); |
| if (text != (char *) NULL) |
| if (WidgetTextWidth(font_info,(char *) text) > width) |
| width=WidgetTextWidth(font_info,(char *) text); |
| } |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Notice widget. |
| */ |
| windows->widget.width=width+4*QuantumMargin; |
| windows->widget.min_width=width+QuantumMargin; |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) (12*height); |
| windows->widget.min_height=(unsigned int) (7*height); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Notice widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| (void) XBell(display,0); |
| /* |
| Respond to X events. |
| */ |
| timer=time((time_t *) NULL)+Timeout; |
| state=UpdateConfigurationState; |
| do |
| { |
| if (time((time_t *) NULL) > timer) |
| break; |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize Dismiss button information. |
| */ |
| XGetWidgetInfo(DismissButtonText,&dismiss_info); |
| dismiss_info.width=(unsigned int) QuantumMargin+ |
| WidgetTextWidth(font_info,DismissButtonText); |
| dismiss_info.height=(unsigned int) ((3*height) >> 1); |
| dismiss_info.x=(int) |
| ((windows->widget.width >> 1)-(dismiss_info.width >> 1)); |
| dismiss_info.y=(int) |
| (windows->widget.height-(dismiss_info.height << 1)); |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Notice widget. |
| */ |
| width=WidgetTextWidth(font_info,(char *) reason); |
| x=(int) ((windows->widget.width >> 1)-(width >> 1)); |
| y=(int) ((windows->widget.height >> 1)-(height << 1)); |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,(char *) reason,Extent(reason)); |
| if (description != (char *) NULL) |
| { |
| width=WidgetTextWidth(font_info,(char *) description); |
| x=(int) ((windows->widget.width >> 1)-(width >> 1)); |
| y+=height; |
| (void) XDrawString(display,windows->widget.id, |
| windows->widget.annotate_context,x,y,(char *) description, |
| Extent(description)); |
| } |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~RedrawWidgetState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse) |
| { |
| /* |
| Do not block if delay > 0. |
| */ |
| XDelay(display,SuspendTime << 2); |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| { |
| /* |
| User pressed Dismiss button. |
| */ |
| dismiss_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (dismiss_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| state|=ExitState; |
| dismiss_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| dismiss_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (state & InactiveWidgetState) |
| break; |
| if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) |
| { |
| /* |
| Dismiss button status changed. |
| */ |
| dismiss_info.raised= |
| dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X P r e f e r e n c e s W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XPreferencesWidget() displays a Preferences widget with program preferences. |
| % If the user presses the Apply button, the preferences are stored in a |
| % configuration file in the users' home directory. |
| % |
| % The format of the XPreferencesWidget method is: |
| % |
| % MagickBooleanType XPreferencesWidget(Display *display, |
| % XResourceInfo *resource_info,XWindows *windows) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| */ |
| MagickExport MagickBooleanType XPreferencesWidget(Display *display, |
| XResourceInfo *resource_info,XWindows *windows) |
| { |
| #define ApplyButtonText "Apply" |
| #define CacheButtonText "%lu mega-bytes of memory in the undo edit cache " |
| #define CancelButtonText "Cancel" |
| #define NumberPreferences 8 |
| |
| static const char |
| *Preferences[] = |
| { |
| "display image centered on a backdrop", |
| "confirm on program exit", |
| "confirm on image edits", |
| "correct image for display gamma", |
| "display warning messages", |
| "apply Floyd/Steinberg error diffusion to image", |
| "use a shared colormap for colormapped X visuals", |
| "display images as an X server pixmap" |
| }; |
| |
| char |
| cache[MaxTextExtent]; |
| |
| int |
| x, |
| y; |
| |
| register int |
| i; |
| |
| Status |
| status; |
| |
| unsigned int |
| height, |
| text_width, |
| width; |
| |
| size_t |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| apply_info, |
| cache_info, |
| cancel_info, |
| preferences_info[NumberPreferences]; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Determine Preferences widget attributes. |
| */ |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); |
| assert(display != (Display *) NULL); |
| assert(resource_info != (XResourceInfo *) NULL); |
| assert(windows != (XWindows *) NULL); |
| XCheckRefreshWindows(display,windows); |
| font_info=windows->widget.font_info; |
| text_width=WidgetTextWidth(font_info,CacheButtonText); |
| for (i=0; i < NumberPreferences; i++) |
| if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width) |
| text_width=WidgetTextWidth(font_info,(char *) Preferences[i]); |
| width=WidgetTextWidth(font_info,ApplyButtonText); |
| if (WidgetTextWidth(font_info,CancelButtonText) > width) |
| width=WidgetTextWidth(font_info,CancelButtonText); |
| width+=(unsigned int) QuantumMargin; |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| /* |
| Position Preferences widget. |
| */ |
| windows->widget.width=(unsigned int) (MagickMax((int) (width << 1), |
| (int) text_width)+6*QuantumMargin); |
| windows->widget.min_width=(width << 1)+QuantumMargin; |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) |
| (7*height+NumberPreferences*(height+(QuantumMargin >> 1))); |
| windows->widget.min_height=(unsigned int) |
| (7*height+NumberPreferences*(height+(QuantumMargin >> 1))); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Preferences widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen, |
| (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| state=UpdateConfigurationState; |
| XSetCursorState(display,windows,MagickTrue); |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(CancelButtonText,&cancel_info); |
| cancel_info.width=width; |
| cancel_info.height=(unsigned int) (3*height) >> 1; |
| cancel_info.x=(int) windows->widget.width-cancel_info.width- |
| (QuantumMargin << 1); |
| cancel_info.y=(int) windows->widget.height- |
| cancel_info.height-QuantumMargin; |
| XGetWidgetInfo(ApplyButtonText,&apply_info); |
| apply_info.width=width; |
| apply_info.height=(unsigned int) (3*height) >> 1; |
| apply_info.x=QuantumMargin << 1; |
| apply_info.y=cancel_info.y; |
| y=(int) (height << 1); |
| for (i=0; i < NumberPreferences; i++) |
| { |
| XGetWidgetInfo(Preferences[i],&preferences_info[i]); |
| preferences_info[i].bevel_width--; |
| preferences_info[i].width=(unsigned int) QuantumMargin >> 1; |
| preferences_info[i].height=(unsigned int) QuantumMargin >> 1; |
| preferences_info[i].x=QuantumMargin << 1; |
| preferences_info[i].y=y; |
| y+=height+(QuantumMargin >> 1); |
| } |
| preferences_info[0].raised=resource_info->backdrop == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[1].raised=resource_info->confirm_exit == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[2].raised=resource_info->confirm_edit == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[3].raised=resource_info->gamma_correct == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[4].raised=resource_info->display_warnings == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[5].raised=resource_info->quantize_info->dither == |
| MagickFalse ? MagickTrue : MagickFalse; |
| preferences_info[6].raised=resource_info->colormap != |
| SharedColormap ? MagickTrue : MagickFalse; |
| preferences_info[7].raised=resource_info->use_pixmap == |
| MagickFalse ? MagickTrue : MagickFalse; |
| (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText, |
| (unsigned long) resource_info->undo_cache); |
| XGetWidgetInfo(cache,&cache_info); |
| cache_info.bevel_width--; |
| cache_info.width=(unsigned int) QuantumMargin >> 1; |
| cache_info.height=(unsigned int) QuantumMargin >> 1; |
| cache_info.x=QuantumMargin << 1; |
| cache_info.y=y; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Preferences widget. |
| */ |
| XDrawBeveledButton(display,&windows->widget,&apply_info); |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| for (i=0; i < NumberPreferences; i++) |
| XDrawBeveledButton(display,&windows->widget,&preferences_info[i]); |
| XDrawTriangleEast(display,&windows->widget,&cache_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| state&=(~RedrawWidgetState); |
| } |
| /* |
| Wait for next event. |
| */ |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(apply_info,event.xbutton)) |
| { |
| /* |
| User pressed Apply button. |
| */ |
| apply_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&apply_info); |
| break; |
| } |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| { |
| /* |
| User pressed Cancel button. |
| */ |
| cancel_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| for (i=0; i < NumberPreferences; i++) |
| if (MatteIsActive(preferences_info[i],event.xbutton)) |
| { |
| /* |
| User pressed a Preferences button. |
| */ |
| preferences_info[i].raised=preferences_info[i].raised == |
| MagickFalse ? MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&preferences_info[i]); |
| break; |
| } |
| if (MatteIsActive(cache_info,event.xbutton)) |
| { |
| /* |
| User pressed Cache button. |
| */ |
| x=cache_info.x+cache_info.width+cache_info.bevel_width+ |
| (QuantumMargin >> 1); |
| y=cache_info.y+((cache_info.height-height) >> 1); |
| width=WidgetTextWidth(font_info,cache); |
| (void) XClearArea(display,windows->widget.id,x,y,width,height, |
| False); |
| resource_info->undo_cache<<=1; |
| if (resource_info->undo_cache > 256) |
| resource_info->undo_cache=1; |
| (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText, |
| (unsigned long) resource_info->undo_cache); |
| cache_info.raised=MagickFalse; |
| XDrawTriangleEast(display,&windows->widget,&cache_info); |
| break; |
| } |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (apply_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(apply_info,event.xbutton)) |
| state|=ExitState; |
| apply_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&apply_info); |
| apply_info.raised=MagickFalse; |
| } |
| if (cancel_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(cancel_info,event.xbutton)) |
| state|=ExitState; |
| cancel_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| } |
| if (cache_info.raised == MagickFalse) |
| { |
| cache_info.raised=MagickTrue; |
| XDrawTriangleEast(display,&windows->widget,&cache_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| (void) XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| apply_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&apply_info); |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (state & InactiveWidgetState) |
| break; |
| if (apply_info.raised == MatteIsActive(apply_info,event.xmotion)) |
| { |
| /* |
| Apply button status changed. |
| */ |
| apply_info.raised= |
| apply_info.raised == MagickFalse ? MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&apply_info); |
| break; |
| } |
| if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion)) |
| { |
| /* |
| Cancel button status changed. |
| */ |
| cancel_info.raised= |
| cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&cancel_info); |
| break; |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| if (apply_info.raised) |
| return(MagickFalse); |
| /* |
| Save user preferences to the client configuration file. |
| */ |
| resource_info->backdrop= |
| preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->confirm_exit= |
| preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->confirm_edit= |
| preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->gamma_correct= |
| preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->display_warnings= |
| preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->quantize_info->dither= |
| preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse; |
| resource_info->colormap=SharedColormap; |
| if (preferences_info[6].raised) |
| resource_info->colormap=PrivateColormap; |
| resource_info->use_pixmap= |
| preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse; |
| XUserPreferences(resource_info); |
| return(MagickTrue); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X P r o g r e s s M o n i t o r W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XProgressMonitorWidget() displays the progress a task is making in |
| % completing a task. A span of zero toggles the active status. An inactive |
| % state disables the progress monitor. |
| % |
| % The format of the XProgressMonitorWidget method is: |
| % |
| % void XProgressMonitorWidget(Display *display,XWindows *windows, |
| % const char *task,const MagickOffsetType offset, |
| % const MagickSizeType span) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o task: Identifies the task in progress. |
| % |
| % o offset: Specifies the offset position within the span which represents |
| % how much progress has been made in completing a task. |
| % |
| % o span: Specifies the span relative to completing a task. |
| % |
| */ |
| MagickExport void XProgressMonitorWidget(Display *display,XWindows *windows, |
| const char *task,const MagickOffsetType offset,const MagickSizeType span) |
| { |
| unsigned int |
| width; |
| |
| XEvent |
| event; |
| |
| assert(display != (Display *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(task != (const char *) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task); |
| if (span == 0) |
| return; |
| /* |
| Update image windows if there is a pending expose event. |
| */ |
| while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event)) |
| (void) XCommandWidget(display,windows,(const char **) NULL,&event); |
| while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event)) |
| XRefreshWindow(display,&windows->image,&event); |
| while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event)) |
| if (monitor_info.text != (char *) NULL) |
| XInfoWidget(display,windows,monitor_info.text); |
| /* |
| Draw progress monitor bar to represent percent completion of a task. |
| */ |
| if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text)) |
| XInfoWidget(display,windows,task); |
| width=(unsigned int) (((offset+1)*(windows->info.width- |
| (2*monitor_info.x)))/span); |
| if (width < monitor_info.width) |
| { |
| monitor_info.raised=MagickTrue; |
| XDrawWidgetText(display,&windows->info,&monitor_info); |
| monitor_info.raised=MagickFalse; |
| } |
| monitor_info.width=width; |
| XDrawWidgetText(display,&windows->info,&monitor_info); |
| (void) XFlush(display); |
| } |
| |
| /* |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % % |
| % % |
| % % |
| % X T e x t V i e w W i d g e t % |
| % % |
| % % |
| % % |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| % |
| % XTextViewWidget() displays text in a Text View widget. |
| % |
| % The format of the XTextViewWidget method is: |
| % |
| % void XTextViewWidget(Display *display,const XResourceInfo *resource_info, |
| % XWindows *windows,const MagickBooleanType mono,const char *title, |
| % const char **textlist) |
| % |
| % A description of each parameter follows: |
| % |
| % o display: Specifies a connection to an X server; returned from |
| % XOpenDisplay. |
| % |
| % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. |
| % |
| % o window: Specifies a pointer to a XWindows structure. |
| % |
| % o mono: Use mono-spaced font when displaying text. |
| % |
| % o title: This character string is displayed at the top of the widget |
| % window. |
| % |
| % o textlist: This string list is displayed within the Text View widget. |
| % |
| */ |
| MagickExport void XTextViewWidget(Display *display, |
| const XResourceInfo *resource_info,XWindows *windows, |
| const MagickBooleanType mono,const char *title,const char **textlist) |
| { |
| #define DismissButtonText "Dismiss" |
| |
| char |
| primary_selection[MaxTextExtent]; |
| |
| register int |
| i; |
| |
| static MagickStatusType |
| mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY); |
| |
| Status |
| status; |
| |
| unsigned int |
| height, |
| lines, |
| text_width, |
| visible_lines, |
| width; |
| |
| size_t |
| delay, |
| state; |
| |
| XEvent |
| event; |
| |
| XFontStruct |
| *font_info, |
| *text_info; |
| |
| XTextProperty |
| window_name; |
| |
| XWidgetInfo |
| dismiss_info, |
| expose_info, |
| list_info, |
| north_info, |
| scroll_info, |
| selection_info, |
| slider_info, |
| south_info; |
| |
| XWindowChanges |
| window_changes; |
| |
| /* |
| Convert text string to a text list. |
| */ |
| assert(display != (Display *) NULL); |
| assert(resource_info != (XResourceInfo *) NULL); |
| assert(windows != (XWindows *) NULL); |
| assert(title != (const char *) NULL); |
| assert(textlist != (const char **) NULL); |
| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title); |
| XSetCursorState(display,windows,MagickTrue); |
| XCheckRefreshWindows(display,windows); |
| if (textlist == (const char **) NULL) |
| { |
| XNoticeWidget(display,windows,"No text to view:",(char *) NULL); |
| return; |
| } |
| /* |
| Determine Text View widget attributes. |
| */ |
| font_info=windows->widget.font_info; |
| text_info=(XFontStruct *) NULL; |
| if (mono != MagickFalse) |
| text_info=XBestFont(display,resource_info,MagickTrue); |
| if (text_info == (XFontStruct *) NULL) |
| text_info=windows->widget.font_info; |
| text_width=0; |
| for (i=0; textlist[i] != (char *) NULL; i++) |
| if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width) |
| text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i], |
| MagickMin(Extent(textlist[i]),160)); |
| lines=(unsigned int) i; |
| width=WidgetTextWidth(font_info,DismissButtonText); |
| width+=QuantumMargin; |
| height=(unsigned int) (text_info->ascent+text_info->descent); |
| /* |
| Position Text View widget. |
| */ |
| windows->widget.width=(unsigned int) (MagickMin((int) text_width, |
| (int) MaxTextWidth)+5*QuantumMargin); |
| windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin); |
| if (windows->widget.width < windows->widget.min_width) |
| windows->widget.width=windows->widget.min_width; |
| windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)* |
| height+((13*height) >> 1)+((9*QuantumMargin) >> 1)); |
| windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9* |
| QuantumMargin) >> 1)); |
| if (windows->widget.height < windows->widget.min_height) |
| windows->widget.height=windows->widget.min_height; |
| XConstrainWindowPosition(display,&windows->widget); |
| /* |
| Map Text View widget. |
| */ |
| (void) CopyMagickString(windows->widget.name,title,MaxTextExtent); |
| status=XStringListToTextProperty(&windows->widget.name,1,&window_name); |
| if (status != False) |
| { |
| XSetWMName(display,windows->widget.id,&window_name); |
| XSetWMIconName(display,windows->widget.id,&window_name); |
| (void) XFree((void *) window_name.value); |
| } |
| window_changes.width=(int) windows->widget.width; |
| window_changes.height=(int) windows->widget.height; |
| window_changes.x=windows->widget.x; |
| window_changes.y=windows->widget.y; |
| (void) XReconfigureWMWindow(display,windows->widget.id, |
| windows->widget.screen,(unsigned int) mask,&window_changes); |
| (void) XMapRaised(display,windows->widget.id); |
| windows->widget.mapped=MagickFalse; |
| /* |
| Respond to X events. |
| */ |
| XGetWidgetInfo((char *) NULL,&slider_info); |
| XGetWidgetInfo((char *) NULL,&north_info); |
| XGetWidgetInfo((char *) NULL,&south_info); |
| XGetWidgetInfo((char *) NULL,&expose_info); |
| visible_lines=0; |
| delay=SuspendTime << 2; |
| height=(unsigned int) (font_info->ascent+font_info->descent); |
| state=UpdateConfigurationState; |
| do |
| { |
| if (state & UpdateConfigurationState) |
| { |
| int |
| id; |
| |
| /* |
| Initialize button information. |
| */ |
| XGetWidgetInfo(DismissButtonText,&dismiss_info); |
| dismiss_info.width=width; |
| dismiss_info.height=(unsigned int) ((3*height) >> 1); |
| dismiss_info.x=(int) windows->widget.width-dismiss_info.width- |
| QuantumMargin-2; |
| dismiss_info.y=(int) windows->widget.height-dismiss_info.height- |
| QuantumMargin; |
| /* |
| Initialize scroll information. |
| */ |
| XGetWidgetInfo((char *) NULL,&scroll_info); |
| scroll_info.bevel_width--; |
| scroll_info.width=height; |
| scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >> |
| 1)); |
| scroll_info.x=(int) windows->widget.width-QuantumMargin- |
| scroll_info.width; |
| scroll_info.y=(3*QuantumMargin) >> 1; |
| scroll_info.raised=MagickFalse; |
| scroll_info.trough=MagickTrue; |
| north_info=scroll_info; |
| north_info.raised=MagickTrue; |
| north_info.width-=(north_info.bevel_width << 1); |
| north_info.height=north_info.width-1; |
| north_info.x+=north_info.bevel_width; |
| north_info.y+=north_info.bevel_width; |
| south_info=north_info; |
| south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width- |
| south_info.height; |
| id=slider_info.id; |
| slider_info=north_info; |
| slider_info.id=id; |
| slider_info.width-=2; |
| slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+ |
| slider_info.bevel_width+2; |
| slider_info.height=scroll_info.height-((slider_info.min_y- |
| scroll_info.y+1) << 1)+4; |
| visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+ |
| ((text_info->ascent+text_info->descent) >> 3)); |
| if (lines > visible_lines) |
| slider_info.height=(unsigned int) (visible_lines*slider_info.height)/ |
| lines; |
| slider_info.max_y=south_info.y-south_info.bevel_width- |
| slider_info.bevel_width-2; |
| slider_info.x=scroll_info.x+slider_info.bevel_width+1; |
| slider_info.y=slider_info.min_y; |
| expose_info=scroll_info; |
| expose_info.y=slider_info.y; |
| /* |
| Initialize list information. |
| */ |
| XGetWidgetInfo((char *) NULL,&list_info); |
| list_info.raised=MagickFalse; |
| list_info.bevel_width--; |
| list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1); |
| list_info.height=scroll_info.height; |
| list_info.x=QuantumMargin; |
| list_info.y=scroll_info.y; |
| /* |
| Initialize selection information. |
| */ |
| XGetWidgetInfo((char *) NULL,&selection_info); |
| selection_info.center=MagickFalse; |
| selection_info.width=list_info.width; |
| selection_info.height=(unsigned int) |
| (9*(text_info->ascent+text_info->descent)) >> 3; |
| selection_info.x=list_info.x; |
| state&=(~UpdateConfigurationState); |
| } |
| if (state & RedrawWidgetState) |
| { |
| /* |
| Redraw Text View window. |
| */ |
| XDrawBeveledMatte(display,&windows->widget,&list_info); |
| XDrawBeveledMatte(display,&windows->widget,&scroll_info); |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| state&=(~RedrawWidgetState); |
| } |
| if (state & RedrawListState) |
| { |
| /* |
| Determine slider id and position. |
| */ |
| if (slider_info.id >= (int) (lines-visible_lines)) |
| slider_info.id=(int) lines-visible_lines; |
| if ((slider_info.id < 0) || (lines <= visible_lines)) |
| slider_info.id=0; |
| slider_info.y=slider_info.min_y; |
| if (lines != 0) |
| slider_info.y+= |
| slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines; |
| if (slider_info.id != selection_info.id) |
| { |
| /* |
| Redraw scroll bar and text. |
| */ |
| windows->widget.font_info=text_info; |
| (void) XSetFont(display,windows->widget.annotate_context, |
| text_info->fid); |
| (void) XSetFont(display,windows->widget.highlight_context, |
| text_info->fid); |
| selection_info.id=slider_info.id; |
| selection_info.y=list_info.y+(height >> 3)+2; |
| for (i=0; i < (int) visible_lines; i++) |
| { |
| selection_info.raised= |
| (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse; |
| selection_info.text=(char *) NULL; |
| if ((slider_info.id+i) < (int) lines) |
| selection_info.text=(char *) textlist[slider_info.id+i]; |
| XDrawWidgetText(display,&windows->widget,&selection_info); |
| selection_info.y+=(int) selection_info.height; |
| } |
| windows->widget.font_info=font_info; |
| (void) XSetFont(display,windows->widget.annotate_context, |
| font_info->fid); |
| (void) XSetFont(display,windows->widget.highlight_context, |
| font_info->fid); |
| /* |
| Update slider. |
| */ |
| if (slider_info.y > expose_info.y) |
| { |
| expose_info.height=(unsigned int) slider_info.y-expose_info.y; |
| expose_info.y=slider_info.y-expose_info.height- |
| slider_info.bevel_width-1; |
| } |
| else |
| { |
| expose_info.height=(unsigned int) expose_info.y-slider_info.y; |
| expose_info.y=slider_info.y+slider_info.height+ |
| slider_info.bevel_width+1; |
| } |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| XDrawMatte(display,&windows->widget,&expose_info); |
| XDrawBeveledButton(display,&windows->widget,&slider_info); |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| expose_info.y=slider_info.y; |
| } |
| state&=(~RedrawListState); |
| } |
| /* |
| Wait for next event. |
| */ |
| if (north_info.raised && south_info.raised) |
| (void) XIfEvent(display,&event,XScreenEvent,(char *) windows); |
| else |
| { |
| /* |
| Brief delay before advancing scroll bar. |
| */ |
| XDelay(display,delay); |
| delay=SuspendTime; |
| (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows); |
| if (north_info.raised == MagickFalse) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| slider_info.id--; |
| state|=RedrawListState; |
| } |
| if (south_info.raised == MagickFalse) |
| if (slider_info.id < (int) lines) |
| { |
| /* |
| Move slider down. |
| */ |
| slider_info.id++; |
| state|=RedrawListState; |
| } |
| if (event.type != ButtonRelease) |
| continue; |
| } |
| switch (event.type) |
| { |
| case ButtonPress: |
| { |
| if (MatteIsActive(slider_info,event.xbutton)) |
| { |
| /* |
| Track slider. |
| */ |
| slider_info.active=MagickTrue; |
| break; |
| } |
| if (MatteIsActive(north_info,event.xbutton)) |
| if (slider_info.id > 0) |
| { |
| /* |
| Move slider up. |
| */ |
| north_info.raised=MagickFalse; |
| slider_info.id--; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(south_info,event.xbutton)) |
| if (slider_info.id < (int) lines) |
| { |
| /* |
| Move slider down. |
| */ |
| south_info.raised=MagickFalse; |
| slider_info.id++; |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(scroll_info,event.xbutton)) |
| { |
| /* |
| Move slider. |
| */ |
| if (event.xbutton.y < slider_info.y) |
| slider_info.id-=(visible_lines-1); |
| else |
| slider_info.id+=(visible_lines-1); |
| state|=RedrawListState; |
| break; |
| } |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| { |
| /* |
| User pressed Dismiss button. |
| */ |
| dismiss_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| if (MatteIsActive(list_info,event.xbutton)) |
| { |
| int |
| id; |
| |
| static Time |
| click_time; |
| |
| /* |
| User pressed list matte. |
| */ |
| id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/ |
| selection_info.height; |
| if (id >= (int) lines) |
| break; |
| if (id != list_info.id) |
| { |
| list_info.id=id; |
| click_time=event.xbutton.time; |
| break; |
| } |
| list_info.id=id; |
| if (event.xbutton.time >= (click_time+DoubleClick)) |
| { |
| click_time=event.xbutton.time; |
| break; |
| } |
| click_time=event.xbutton.time; |
| /* |
| Become the XA_PRIMARY selection owner. |
| */ |
| (void) CopyMagickString(primary_selection,textlist[list_info.id], |
| MaxTextExtent); |
| (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id, |
| event.xbutton.time); |
| if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id) |
| break; |
| selection_info.id=(~0); |
| list_info.id=id; |
| state|=RedrawListState; |
| break; |
| } |
| break; |
| } |
| case ButtonRelease: |
| { |
| if (windows->widget.mapped == MagickFalse) |
| break; |
| if (north_info.raised == MagickFalse) |
| { |
| /* |
| User released up button. |
| */ |
| delay=SuspendTime << 2; |
| north_info.raised=MagickTrue; |
| XDrawTriangleNorth(display,&windows->widget,&north_info); |
| } |
| if (south_info.raised == MagickFalse) |
| { |
| /* |
| User released down button. |
| */ |
| delay=SuspendTime << 2; |
| south_info.raised=MagickTrue; |
| XDrawTriangleSouth(display,&windows->widget,&south_info); |
| } |
| if (slider_info.active) |
| { |
| /* |
| Stop tracking slider. |
| */ |
| slider_info.active=MagickFalse; |
| break; |
| } |
| if (dismiss_info.raised == MagickFalse) |
| { |
| if (event.xbutton.window == windows->widget.id) |
| if (MatteIsActive(dismiss_info,event.xbutton)) |
| state|=ExitState; |
| dismiss_info.raised=MagickTrue; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| /* |
| If client window delete message, exit. |
| */ |
| if (event.xclient.message_type != windows->wm_protocols) |
| break; |
| if (*event.xclient.data.l == (int) windows->wm_take_focus) |
| { |
| (void) XSetInputFocus(display,event.xclient.window,RevertToParent, |
| (Time) event.xclient.data.l[1]); |
| break; |
| } |
| if (*event.xclient.data.l != (int) windows->wm_delete_window) |
| break; |
| if (event.xclient.window == windows->widget.id) |
| { |
| state|=ExitState; |
| break; |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| /* |
| Update widget configuration. |
| */ |
| if (event.xconfigure.window != windows->widget.id) |
| break; |
| if ((event.xconfigure.width == (int) windows->widget.width) && |
| (event.xconfigure.height == (int) windows->widget.height)) |
| break; |
| windows->widget.width=(unsigned int) |
| MagickMax(event.xconfigure.width,(int) windows->widget.min_width); |
| windows->widget.height=(unsigned int) |
| MagickMax(event.xconfigure.height,(int) windows->widget.min_height); |
| state|=UpdateConfigurationState; |
| break; |
| } |
| case EnterNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state&=(~InactiveWidgetState); |
| break; |
| } |
| case Expose: |
| { |
| if (event.xexpose.window != windows->widget.id) |
| break; |
| if (event.xexpose.count != 0) |
| break; |
| state|=RedrawWidgetState; |
| break; |
| } |
| case KeyPress: |
| { |
| static char |
| command[MaxTextExtent]; |
| |
| static int |
| length; |
| |
| static KeySym |
| key_symbol; |
| |
| /* |
| Respond to a user key press. |
| */ |
| if (event.xkey.window != windows->widget.id) |
| break; |
| length=XLookupString((XKeyEvent *) &event.xkey,command, |
| (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL); |
| *(command+length)='\0'; |
| if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter)) |
| { |
| dismiss_info.raised=MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| state|=ExitState; |
| break; |
| } |
| if (AreaIsActive(scroll_info,event.xkey)) |
| { |
| /* |
| Move slider. |
| */ |
| switch ((int) key_symbol) |
| { |
| case XK_Home: |
| case XK_KP_Home: |
| { |
| slider_info.id=0; |
| break; |
| } |
| case XK_Up: |
| case XK_KP_Up: |
| { |
| slider_info.id--; |
| break; |
| } |
| case XK_Down: |
| case XK_KP_Down: |
| { |
| slider_info.id++; |
| break; |
| } |
| case XK_Prior: |
| case XK_KP_Prior: |
| { |
| slider_info.id-=visible_lines; |
| break; |
| } |
| case XK_Next: |
| case XK_KP_Next: |
| { |
| slider_info.id+=visible_lines; |
| break; |
| } |
| case XK_End: |
| case XK_KP_End: |
| { |
| slider_info.id=(int) lines; |
| break; |
| } |
| } |
| state|=RedrawListState; |
| break; |
| } |
| break; |
| } |
| case KeyRelease: |
| break; |
| case LeaveNotify: |
| { |
| if (event.xcrossing.window != windows->widget.id) |
| break; |
| state|=InactiveWidgetState; |
| break; |
| } |
| case MapNotify: |
| { |
| mask&=(~CWX); |
| mask&=(~CWY); |
| break; |
| } |
| case MotionNotify: |
| { |
| /* |
| Discard pending button motion events. |
| */ |
| while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ; |
| if (slider_info.active) |
| { |
| /* |
| Move slider matte. |
| */ |
| slider_info.y=event.xmotion.y- |
| ((slider_info.height+slider_info.bevel_width) >> 1)+1; |
| if (slider_info.y < slider_info.min_y) |
| slider_info.y=slider_info.min_y; |
| if (slider_info.y > slider_info.max_y) |
| slider_info.y=slider_info.max_y; |
| slider_info.id=0; |
| if (slider_info.y != slider_info.min_y) |
| slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/ |
| (slider_info.max_y-slider_info.min_y+1); |
| state|=RedrawListState; |
| break; |
| } |
| if (state & InactiveWidgetState) |
| break; |
| if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion)) |
| { |
| /* |
| Dismiss button status changed. |
| */ |
| dismiss_info.raised= |
| dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse; |
| XDrawBeveledButton(display,&windows->widget,&dismiss_info); |
| break; |
| } |
| break; |
| } |
| case SelectionClear: |
| { |
| list_info.id=(~0); |
| selection_info.id=(~0); |
| state|=RedrawListState; |
| break; |
| } |
| case SelectionRequest: |
| { |
| XSelectionEvent |
| notify; |
| |
| XSelectionRequestEvent |
| *request; |
| |
| if (list_info.id == (~0)) |
| break; |
| /* |
| Set primary selection. |
| */ |
| request=(&(event.xselectionrequest)); |
| (void) XChangeProperty(request->display,request->requestor, |
| request->property,request->target,8,PropModeReplace, |
| (unsigned char *) primary_selection,Extent(primary_selection)); |
| notify.type=SelectionNotify; |
| notify.send_event=MagickTrue; |
| notify.display=request->display; |
| notify.requestor=request->requestor; |
| notify.selection=request->selection; |
| notify.target=request->target; |
| notify.time=request->time; |
| if (request->property == None) |
| notify.property=request->target; |
| else |
| notify.property=request->property; |
| (void) XSendEvent(request->display,request->requestor,False,NoEventMask, |
| (XEvent *) ¬ify); |
| } |
| default: |
| break; |
| } |
| } while ((state & ExitState) == 0); |
| if (text_info != windows->widget.font_info) |
| (void) XFreeFont(display,text_info); |
| XSetCursorState(display,windows,MagickFalse); |
| (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen); |
| XCheckRefreshWindows(display,windows); |
| } |
| #endif |