blob: 1cb98042f471af799ac565f665c42723857f6ab1 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% %
7% W W IIIII DDDD GGGG EEEEE TTTTT %
8% W W I D D G E T %
9% W W W I D D G GG EEE T %
10% WW WW I D D G G E T %
11% W W IIIII DDDD GGGG EEEEE T %
12% %
13% %
14% MagickCore X11 User Interface Methods %
15% %
16% Software Design %
17% John Cristy %
18% September 1993 %
19% %
20% %
cristy7e41fe82010-12-04 23:12:08 +000021% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000022% dedicated to making software imaging solutions freely available. %
23% %
24% You may not use this file except in compliance with the License. You may %
25% obtain a copy of the License at %
26% %
27% http://www.imagemagick.org/script/license.php %
28% %
29% Unless required by applicable law or agreed to in writing, software %
30% distributed under the License is distributed on an "AS IS" BASIS, %
31% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32% See the License for the specific language governing permissions and %
33% limitations under the License. %
34% %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/color.h"
45#include "MagickCore/color-private.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
48#include "MagickCore/image.h"
49#include "MagickCore/magick.h"
50#include "MagickCore/memory_.h"
51#include "MagickCore/PreRvIcccm.h"
52#include "MagickCore/string_.h"
53#include "MagickCore/token.h"
cristy7832dc22011-09-05 01:21:53 +000054#include "MagickCore/token-private.h"
cristy4c08aed2011-07-01 19:47:50 +000055#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000056#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/xwindow-private.h"
58#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000059#include "MagickCore/widget-private.h"
cristy3ed852e2009-09-05 21:47:34 +000060
61#if defined(MAGICKCORE_X11_DELEGATE)
62
63/*
64 Define declarations.
65*/
66#define AreaIsActive(matte_info,position) ( \
67 ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \
68 (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
69 ? MagickTrue : MagickFalse)
70#define Extent(s) ((int) strlen(s))
71#define MatteIsActive(matte_info,position) ( \
72 ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \
73 (position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \
74 (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) && \
75 (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
76 ? MagickTrue : MagickFalse)
77#define MaxTextWidth ((unsigned int) (255*XTextWidth(font_info,"_",1)))
78#define MinTextWidth (26*XTextWidth(font_info,"_",1))
79#define QuantumMargin MagickMax(font_info->max_bounds.width,12)
80#define WidgetTextWidth(font_info,text) \
81 ((unsigned int) XTextWidth(font_info,text,Extent(text)))
82#define WindowIsActive(window_info,position) ( \
83 ((position.x >= 0) && (position.y >= 0) && \
84 (position.x < (int) window_info.width) && \
85 (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse)
86
87/*
88 Enum declarations.
89*/
90typedef enum
91{
92 ControlState = 0x0001,
93 InactiveWidgetState = 0x0004,
94 JumpListState = 0x0008,
95 RedrawActionState = 0x0010,
96 RedrawListState = 0x0020,
97 RedrawWidgetState = 0x0040,
98 UpdateListState = 0x0100
99} WidgetState;
100
101/*
102 Typedef declarations.
103*/
104typedef struct _XWidgetInfo
105{
106 char
107 *cursor,
108 *text,
109 *marker;
110
111 int
112 id;
113
114 unsigned int
115 bevel_width,
116 width,
117 height;
118
119 int
120 x,
121 y,
122 min_y,
123 max_y;
124
125 MagickStatusType
126 raised,
127 active,
128 center,
129 trough,
130 highlight;
131} XWidgetInfo;
132
133/*
134 Variable declarations.
135*/
136static XWidgetInfo
137 monitor_info =
138 {
139 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
140 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
141 },
142 submenu_info =
143 {
144 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
145 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
146 },
147 *selection_info = (XWidgetInfo *) NULL,
148 toggle_info =
149 {
150 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
151 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
152 };
153
154/*
155 Constant declarations.
156*/
157static const int
158 BorderOffset = 4,
159 DoubleClick = 250;
160
161/*
162 Method prototypes.
163*/
164static void
165 XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *),
166 XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType),
167 XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType),
168 XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType);
169
170/*
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172% %
173% %
174% %
175% D e s t r o y X W i d g e t %
176% %
177% %
178% %
179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180%
181% DestroyXWidget() destroys resources associated with the X widget.
182%
183% The format of the DestroyXWidget method is:
184%
185% void DestroyXWidget()
186%
187% A description of each parameter follows:
188%
189*/
cristybcbda3f2011-09-03 13:01:22 +0000190MagickPrivate void DestroyXWidget(void)
cristy3ed852e2009-09-05 21:47:34 +0000191{
192 if (selection_info != (XWidgetInfo *) NULL)
193 selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
194}
195
196/*
197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198% %
199% %
200% %
201+ X D r a w B e v e l %
202% %
203% %
204% %
205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206%
207% XDrawBevel() "sets off" an area with a highlighted upper and left bevel and
208% a shadowed lower and right bevel. The highlighted and shadowed bevels
209% create a 3-D effect.
210%
211% The format of the XDrawBevel function is:
212%
213% XDrawBevel(display,window_info,bevel_info)
214%
215% A description of each parameter follows:
216%
217% o display: Specifies a pointer to the Display structure; returned from
218% XOpenDisplay.
219%
220% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
221%
222% o bevel_info: Specifies a pointer to a XWidgetInfo structure. It
223% contains the extents of the bevel.
224%
225*/
226static void XDrawBevel(Display *display,const XWindowInfo *window_info,
227 const XWidgetInfo *bevel_info)
228{
229 int
230 x1,
231 x2,
232 y1,
233 y2;
234
235 unsigned int
236 bevel_width;
237
238 XPoint
239 points[6];
240
241 /*
242 Draw upper and left beveled border.
243 */
244 x1=bevel_info->x;
245 y1=bevel_info->y+bevel_info->height;
246 x2=bevel_info->x+bevel_info->width;
247 y2=bevel_info->y;
248 bevel_width=bevel_info->bevel_width;
249 points[0].x=x1;
250 points[0].y=y1;
251 points[1].x=x1;
252 points[1].y=y2;
253 points[2].x=x2;
254 points[2].y=y2;
255 points[3].x=x2+bevel_width;
256 points[3].y=y2-bevel_width;
257 points[4].x=x1-bevel_width;
258 points[4].y=y2-bevel_width;
259 points[5].x=x1-bevel_width;
260 points[5].y=y1+bevel_width;
261 XSetBevelColor(display,window_info,bevel_info->raised);
262 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
263 points,6,Complex,CoordModeOrigin);
264 /*
265 Draw lower and right beveled border.
266 */
267 points[0].x=x1;
268 points[0].y=y1;
269 points[1].x=x2;
270 points[1].y=y1;
271 points[2].x=x2;
272 points[2].y=y2;
273 points[3].x=x2+bevel_width;
274 points[3].y=y2-bevel_width;
275 points[4].x=x2+bevel_width;
276 points[4].y=y1+bevel_width;
277 points[5].x=x1-bevel_width;
278 points[5].y=y1+bevel_width;
279 XSetBevelColor(display,window_info,!bevel_info->raised);
280 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
281 points,6,Complex,CoordModeOrigin);
282 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
283}
284
285/*
286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287% %
288% %
289% %
290+ X D r a w B e v e l e d B u t t o n %
291% %
292% %
293% %
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295%
296% XDrawBeveledButton() draws a button with a highlighted upper and left bevel
297% and a shadowed lower and right bevel. The highlighted and shadowed bevels
298% create a 3-D effect.
299%
300% The format of the XDrawBeveledButton function is:
301%
302% XDrawBeveledButton(display,window_info,button_info)
303%
304% A description of each parameter follows:
305%
306% o display: Specifies a pointer to the Display structure; returned from
307% XOpenDisplay.
308%
309% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
310%
311% o button_info: Specifies a pointer to a XWidgetInfo structure. It
312% contains the extents of the button.
313%
314*/
315
316static inline int MagickAbsoluteValue(const int x)
317{
318 if (x < 0)
319 return(-x);
320 return(x);
321}
322
323static inline int MagickMax(const int x,const int y)
324{
325 if (x > y)
326 return(x);
327 return(y);
328}
329
330static inline int MagickMin(const int x,const int y)
331{
332 if (x < y)
333 return(x);
334 return(y);
335}
336
337static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info,
338 const XWidgetInfo *button_info)
339{
340 int
341 x,
342 y;
343
344 unsigned int
345 width;
346
347 XFontStruct
348 *font_info;
349
350 XRectangle
351 crop_info;
352
353 /*
354 Draw matte.
355 */
356 XDrawBevel(display,window_info,button_info);
357 XSetMatteColor(display,window_info,button_info->raised);
358 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
359 button_info->x,button_info->y,button_info->width,button_info->height);
360 x=button_info->x-button_info->bevel_width-1;
361 y=button_info->y-button_info->bevel_width-1;
362 (void) XSetForeground(display,window_info->widget_context,
363 window_info->pixel_info->trough_color.pixel);
364 if (button_info->raised || (window_info->depth == 1))
365 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
366 x,y,button_info->width+(button_info->bevel_width << 1)+1,
367 button_info->height+(button_info->bevel_width << 1)+1);
368 if (button_info->text == (char *) NULL)
369 return;
370 /*
371 Set cropping region.
372 */
373 crop_info.width=(unsigned short) button_info->width;
374 crop_info.height=(unsigned short) button_info->height;
375 crop_info.x=button_info->x;
376 crop_info.y=button_info->y;
377 /*
378 Draw text.
379 */
380 font_info=window_info->font_info;
381 width=WidgetTextWidth(font_info,button_info->text);
382 x=button_info->x+(QuantumMargin >> 1);
383 if (button_info->center)
384 x=button_info->x+(button_info->width >> 1)-(width >> 1);
385 y=button_info->y+((button_info->height-
386 (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
387 if ((int) button_info->width == (QuantumMargin >> 1))
388 {
389 /*
390 Option button-- write label to right of button.
391 */
392 XSetTextColor(display,window_info,MagickTrue);
393 x=button_info->x+button_info->width+button_info->bevel_width+
394 (QuantumMargin >> 1);
395 (void) XDrawString(display,window_info->id,window_info->widget_context,
396 x,y,button_info->text,Extent(button_info->text));
397 return;
398 }
399 (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info,
400 1,Unsorted);
401 XSetTextColor(display,window_info,button_info->raised);
402 (void) XDrawString(display,window_info->id,window_info->widget_context,x,y,
403 button_info->text,Extent(button_info->text));
404 (void) XSetClipMask(display,window_info->widget_context,None);
405 if (button_info->raised == MagickFalse)
406 XDelay(display,SuspendTime << 2);
407}
408
409/*
410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411% %
412% %
413% %
414+ X D r a w B e v e l e d M a t t e %
415% %
416% %
417% %
418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419%
420% XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and
421% a highlighted lower and right bevel. The highlighted and shadowed bevels
422% create a 3-D effect.
423%
424% The format of the XDrawBeveledMatte function is:
425%
426% XDrawBeveledMatte(display,window_info,matte_info)
427%
428% A description of each parameter follows:
429%
430% o display: Specifies a pointer to the Display structure; returned from
431% XOpenDisplay.
432%
433% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
434%
435% o matte_info: Specifies a pointer to a XWidgetInfo structure. It
436% contains the extents of the matte.
437%
438*/
439static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info,
440 const XWidgetInfo *matte_info)
441{
442 /*
443 Draw matte.
444 */
445 XDrawBevel(display,window_info,matte_info);
446 XDrawMatte(display,window_info,matte_info);
447}
448
449/*
450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451% %
452% %
453% %
454+ X D r a w M a t t e %
455% %
456% %
457% %
458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459%
460% XDrawMatte() fills a rectangular area with the matte color.
461%
462% The format of the XDrawMatte function is:
463%
464% XDrawMatte(display,window_info,matte_info)
465%
466% A description of each parameter follows:
467%
468% o display: Specifies a pointer to the Display structure; returned from
469% XOpenDisplay.
470%
471% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
472%
473% o matte_info: Specifies a pointer to a XWidgetInfo structure. It
474% contains the extents of the matte.
475%
476*/
477static void XDrawMatte(Display *display,const XWindowInfo *window_info,
478 const XWidgetInfo *matte_info)
479{
480 /*
481 Draw matte.
482 */
483 if ((matte_info->trough == MagickFalse) || (window_info->depth == 1))
484 (void) XFillRectangle(display,window_info->id,
485 window_info->highlight_context,matte_info->x,matte_info->y,
486 matte_info->width,matte_info->height);
487 else
488 {
489 (void) XSetForeground(display,window_info->widget_context,
490 window_info->pixel_info->trough_color.pixel);
491 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
492 matte_info->x,matte_info->y,matte_info->width,matte_info->height);
493 }
494}
495
496/*
497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498% %
499% %
500% %
501+ X D r a w M a t t e T e x t %
502% %
503% %
504% %
505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506%
507% XDrawMatteText() draws a matte with text. If the text exceeds the extents
508% of the text, a portion of the text relative to the cursor is displayed.
509%
510% The format of the XDrawMatteText function is:
511%
512% XDrawMatteText(display,window_info,text_info)
513%
514% A description of each parameter follows:
515%
516% o display: Specifies a pointer to the Display structure; returned from
517% XOpenDisplay.
518%
519% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
520%
521% o text_info: Specifies a pointer to a XWidgetInfo structure. It
522% contains the extents of the text.
523%
524*/
525static void XDrawMatteText(Display *display,const XWindowInfo *window_info,
526 XWidgetInfo *text_info)
527{
528 const char
529 *text;
530
531 int
532 n,
533 x,
534 y;
535
536 register int
537 i;
538
539 unsigned int
540 height,
541 width;
542
543 XFontStruct
544 *font_info;
545
546 XRectangle
547 crop_info;
548
549 /*
550 Clear the text area.
551 */
552 XSetMatteColor(display,window_info,MagickFalse);
553 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
554 text_info->x,text_info->y,text_info->width,text_info->height);
555 if (text_info->text == (char *) NULL)
556 return;
557 XSetTextColor(display,window_info,text_info->highlight);
558 font_info=window_info->font_info;
559 x=text_info->x+(QuantumMargin >> 2);
560 y=text_info->y+font_info->ascent+(text_info->height >> 2);
561 width=text_info->width-(QuantumMargin >> 1);
562 height=(unsigned int) (font_info->ascent+font_info->descent);
563 if (*text_info->text == '\0')
564 {
565 /*
566 No text-- just draw cursor.
567 */
568 (void) XDrawLine(display,window_info->id,window_info->annotate_context,
569 x,y+3,x,y-height+3);
570 return;
571 }
572 /*
573 Set cropping region.
574 */
575 crop_info.width=(unsigned short) text_info->width;
576 crop_info.height=(unsigned short) text_info->height;
577 crop_info.x=text_info->x;
578 crop_info.y=text_info->y;
579 /*
580 Determine beginning of the visible text.
581 */
582 if (text_info->cursor < text_info->marker)
583 text_info->marker=text_info->cursor;
584 else
585 {
586 text=text_info->marker;
587 if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) >
588 (int) width)
589 {
590 text=text_info->text;
591 for (i=0; i < Extent(text); i++)
592 {
593 n=XTextWidth(font_info,(char *) text+i,(int)
594 (text_info->cursor-text-i));
595 if (n <= (int) width)
596 break;
597 }
598 text_info->marker=(char *) text+i;
599 }
600 }
601 /*
602 Draw text and cursor.
603 */
604 if (text_info->highlight == MagickFalse)
605 {
606 (void) XSetClipRectangles(display,window_info->widget_context,0,0,
607 &crop_info,1,Unsorted);
608 (void) XDrawString(display,window_info->id,window_info->widget_context,
609 x,y,text_info->marker,Extent(text_info->marker));
610 (void) XSetClipMask(display,window_info->widget_context,None);
611 }
612 else
613 {
614 (void) XSetClipRectangles(display,window_info->annotate_context,0,0,
615 &crop_info,1,Unsorted);
616 width=WidgetTextWidth(font_info,text_info->marker);
617 (void) XFillRectangle(display,window_info->id,
618 window_info->annotate_context,x,y-font_info->ascent,width,height);
619 (void) XSetClipMask(display,window_info->annotate_context,None);
620 (void) XSetClipRectangles(display,window_info->highlight_context,0,0,
621 &crop_info,1,Unsorted);
622 (void) XDrawString(display,window_info->id,
623 window_info->highlight_context,x,y,text_info->marker,
624 Extent(text_info->marker));
625 (void) XSetClipMask(display,window_info->highlight_context,None);
626 }
627 x+=XTextWidth(font_info,text_info->marker,(int)
628 (text_info->cursor-text_info->marker));
629 (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
630 x,y-height+3);
631}
632
633/*
634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635% %
636% %
637% %
638+ X D r a w T r i a n g l e E a s t %
639% %
640% %
641% %
642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643%
644% XDrawTriangleEast() draws a triangle with a highlighted left bevel and a
645% shadowed right and lower bevel. The highlighted and shadowed bevels create
646% a 3-D effect.
647%
648% The format of the XDrawTriangleEast function is:
649%
650% XDrawTriangleEast(display,window_info,triangle_info)
651%
652% A description of each parameter follows:
653%
654% o display: Specifies a pointer to the Display structure; returned from
655% XOpenDisplay.
656%
657% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
658%
659% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
660% contains the extents of the triangle.
661%
662*/
663static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info,
664 const XWidgetInfo *triangle_info)
665{
666 int
667 x1,
668 x2,
669 x3,
670 y1,
671 y2,
672 y3;
673
674 unsigned int
675 bevel_width;
676
677 XFontStruct
678 *font_info;
679
680 XPoint
681 points[4];
682
683 /*
684 Draw triangle matte.
685 */
686 x1=triangle_info->x;
687 y1=triangle_info->y;
688 x2=triangle_info->x+triangle_info->width;
689 y2=triangle_info->y+(triangle_info->height >> 1);
690 x3=triangle_info->x;
691 y3=triangle_info->y+triangle_info->height;
692 bevel_width=triangle_info->bevel_width;
693 points[0].x=x1;
694 points[0].y=y1;
695 points[1].x=x2;
696 points[1].y=y2;
697 points[2].x=x3;
698 points[2].y=y3;
699 XSetMatteColor(display,window_info,triangle_info->raised);
700 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
701 points,3,Complex,CoordModeOrigin);
702 /*
703 Draw bottom bevel.
704 */
705 points[0].x=x2;
706 points[0].y=y2;
707 points[1].x=x3;
708 points[1].y=y3;
709 points[2].x=x3-bevel_width;
710 points[2].y=y3+bevel_width;
711 points[3].x=x2+bevel_width;
712 points[3].y=y2;
713 XSetBevelColor(display,window_info,!triangle_info->raised);
714 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
715 points,4,Complex,CoordModeOrigin);
716 /*
717 Draw Left bevel.
718 */
719 points[0].x=x3;
720 points[0].y=y3;
721 points[1].x=x1;
722 points[1].y=y1;
723 points[2].x=x1-bevel_width+1;
724 points[2].y=y1-bevel_width;
725 points[3].x=x3-bevel_width+1;
726 points[3].y=y3+bevel_width;
727 XSetBevelColor(display,window_info,triangle_info->raised);
728 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
729 points,4,Complex,CoordModeOrigin);
730 /*
731 Draw top bevel.
732 */
733 points[0].x=x1;
734 points[0].y=y1;
735 points[1].x=x2;
736 points[1].y=y2;
737 points[2].x=x2+bevel_width;
738 points[2].y=y2;
739 points[3].x=x1-bevel_width;
740 points[3].y=y1-bevel_width;
741 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
742 points,4,Complex,CoordModeOrigin);
743 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
744 if (triangle_info->text == (char *) NULL)
745 return;
746 /*
747 Write label to right of triangle.
748 */
749 font_info=window_info->font_info;
750 XSetTextColor(display,window_info,MagickTrue);
751 x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+
752 (QuantumMargin >> 1);
753 y1=triangle_info->y+((triangle_info->height-
754 (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
755 (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1,
756 triangle_info->text,Extent(triangle_info->text));
757}
758
759/*
760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761% %
762% %
763% %
764+ X D r a w T r i a n g l e N o r t h %
765% %
766% %
767% %
768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769%
770% XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a
771% shadowed right and lower bevel. The highlighted and shadowed bevels create
772% a 3-D effect.
773%
774% The format of the XDrawTriangleNorth function is:
775%
776% XDrawTriangleNorth(display,window_info,triangle_info)
777%
778% A description of each parameter follows:
779%
780% o display: Specifies a pointer to the Display structure; returned from
781% XOpenDisplay.
782%
783% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
784%
785% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
786% contains the extents of the triangle.
787%
788*/
789static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info,
790 const XWidgetInfo *triangle_info)
791{
792 int
793 x1,
794 x2,
795 x3,
796 y1,
797 y2,
798 y3;
799
800 unsigned int
801 bevel_width;
802
803 XPoint
804 points[4];
805
806 /*
807 Draw triangle matte.
808 */
809 x1=triangle_info->x;
810 y1=triangle_info->y+triangle_info->height;
811 x2=triangle_info->x+(triangle_info->width >> 1);
812 y2=triangle_info->y;
813 x3=triangle_info->x+triangle_info->width;
814 y3=triangle_info->y+triangle_info->height;
815 bevel_width=triangle_info->bevel_width;
816 points[0].x=x1;
817 points[0].y=y1;
818 points[1].x=x2;
819 points[1].y=y2;
820 points[2].x=x3;
821 points[2].y=y3;
822 XSetMatteColor(display,window_info,triangle_info->raised);
823 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
824 points,3,Complex,CoordModeOrigin);
825 /*
826 Draw left bevel.
827 */
828 points[0].x=x1;
829 points[0].y=y1;
830 points[1].x=x2;
831 points[1].y=y2;
832 points[2].x=x2;
833 points[2].y=y2-bevel_width-2;
834 points[3].x=x1-bevel_width-1;
835 points[3].y=y1+bevel_width;
836 XSetBevelColor(display,window_info,triangle_info->raised);
837 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
838 points,4,Complex,CoordModeOrigin);
839 /*
840 Draw right bevel.
841 */
842 points[0].x=x2;
843 points[0].y=y2;
844 points[1].x=x3;
845 points[1].y=y3;
846 points[2].x=x3+bevel_width;
847 points[2].y=y3+bevel_width;
848 points[3].x=x2;
849 points[3].y=y2-bevel_width;
850 XSetBevelColor(display,window_info,!triangle_info->raised);
851 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
852 points,4,Complex,CoordModeOrigin);
853 /*
854 Draw lower bevel.
855 */
856 points[0].x=x3;
857 points[0].y=y3;
858 points[1].x=x1;
859 points[1].y=y1;
860 points[2].x=x1-bevel_width;
861 points[2].y=y1+bevel_width;
862 points[3].x=x3+bevel_width;
863 points[3].y=y3+bevel_width;
864 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
865 points,4,Complex,CoordModeOrigin);
866 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
867}
868
869/*
870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871% %
872% %
873% %
874+ X D r a w T r i a n g l e S o u t h %
875% %
876% %
877% %
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879%
880% XDrawTriangleSouth() draws a border with a highlighted left and right bevel
881% and a shadowed lower bevel. The highlighted and shadowed bevels create a
882% 3-D effect.
883%
884% The format of the XDrawTriangleSouth function is:
885%
886% XDrawTriangleSouth(display,window_info,triangle_info)
887%
888% A description of each parameter follows:
889%
890% o display: Specifies a pointer to the Display structure; returned from
891% XOpenDisplay.
892%
893% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
894%
895% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
896% contains the extents of the triangle.
897%
898*/
899static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info,
900 const XWidgetInfo *triangle_info)
901{
902 int
903 x1,
904 x2,
905 x3,
906 y1,
907 y2,
908 y3;
909
910 unsigned int
911 bevel_width;
912
913 XPoint
914 points[4];
915
916 /*
917 Draw triangle matte.
918 */
919 x1=triangle_info->x;
920 y1=triangle_info->y;
921 x2=triangle_info->x+(triangle_info->width >> 1);
922 y2=triangle_info->y+triangle_info->height;
923 x3=triangle_info->x+triangle_info->width;
924 y3=triangle_info->y;
925 bevel_width=triangle_info->bevel_width;
926 points[0].x=x1;
927 points[0].y=y1;
928 points[1].x=x2;
929 points[1].y=y2;
930 points[2].x=x3;
931 points[2].y=y3;
932 XSetMatteColor(display,window_info,triangle_info->raised);
933 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
934 points,3,Complex,CoordModeOrigin);
935 /*
936 Draw top bevel.
937 */
938 points[0].x=x3;
939 points[0].y=y3;
940 points[1].x=x1;
941 points[1].y=y1;
942 points[2].x=x1-bevel_width;
943 points[2].y=y1-bevel_width;
944 points[3].x=x3+bevel_width;
945 points[3].y=y3-bevel_width;
946 XSetBevelColor(display,window_info,triangle_info->raised);
947 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
948 points,4,Complex,CoordModeOrigin);
949 /*
950 Draw right bevel.
951 */
952 points[0].x=x2;
953 points[0].y=y2;
954 points[1].x=x3+1;
955 points[1].y=y3-bevel_width;
956 points[2].x=x3+bevel_width;
957 points[2].y=y3-bevel_width;
958 points[3].x=x2;
959 points[3].y=y2+bevel_width;
960 XSetBevelColor(display,window_info,!triangle_info->raised);
961 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
962 points,4,Complex,CoordModeOrigin);
963 /*
964 Draw left bevel.
965 */
966 points[0].x=x1;
967 points[0].y=y1;
968 points[1].x=x2;
969 points[1].y=y2;
970 points[2].x=x2;
971 points[2].y=y2+bevel_width;
972 points[3].x=x1-bevel_width;
973 points[3].y=y1-bevel_width;
974 XSetBevelColor(display,window_info,triangle_info->raised);
975 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
976 points,4,Complex,CoordModeOrigin);
977 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
978}
979
980/*
981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982% %
983% %
984% %
985+ X D r a w W i d g e t T e x t %
986% %
987% %
988% %
989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990%
991% XDrawWidgetText() first clears the widget and draws a text string justifed
992% left (or center) in the x-direction and centered within the y-direction.
993%
994% The format of the XDrawWidgetText function is:
995%
996% XDrawWidgetText(display,window_info,text_info)
997%
998% A description of each parameter follows:
999%
1000% o display: Specifies a pointer to the Display structure; returned from
1001% XOpenDisplay.
1002%
1003% o window_info: Specifies a pointer to a XWindowText structure.
1004%
1005% o text_info: Specifies a pointer to XWidgetInfo structure.
1006%
1007*/
1008static void XDrawWidgetText(Display *display,const XWindowInfo *window_info,
1009 XWidgetInfo *text_info)
1010{
1011 GC
1012 widget_context;
1013
1014 int
1015 x,
1016 y;
1017
1018 unsigned int
1019 height,
1020 width;
1021
1022 XFontStruct
1023 *font_info;
1024
1025 XRectangle
1026 crop_info;
1027
1028 /*
1029 Clear the text area.
1030 */
1031 widget_context=window_info->annotate_context;
1032 if (text_info->raised)
1033 (void) XClearArea(display,window_info->id,text_info->x,text_info->y,
1034 text_info->width,text_info->height,MagickFalse);
1035 else
1036 {
1037 (void) XFillRectangle(display,window_info->id,widget_context,text_info->x,
1038 text_info->y,text_info->width,text_info->height);
1039 widget_context=window_info->highlight_context;
1040 }
1041 if (text_info->text == (char *) NULL)
1042 return;
1043 if (*text_info->text == '\0')
1044 return;
1045 /*
1046 Set cropping region.
1047 */
1048 font_info=window_info->font_info;
1049 crop_info.width=(unsigned short) text_info->width;
1050 crop_info.height=(unsigned short) text_info->height;
1051 crop_info.x=text_info->x;
1052 crop_info.y=text_info->y;
1053 /*
1054 Draw text.
1055 */
1056 width=WidgetTextWidth(font_info,text_info->text);
1057 x=text_info->x+(QuantumMargin >> 1);
1058 if (text_info->center)
1059 x=text_info->x+(text_info->width >> 1)-(width >> 1);
1060 if (text_info->raised)
1061 if (width > (text_info->width-QuantumMargin))
1062 x+=(text_info->width-QuantumMargin-width);
1063 height=(unsigned int) (font_info->ascent+font_info->descent);
1064 y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
1065 (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted);
1066 (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text,
1067 Extent(text_info->text));
1068 (void) XSetClipMask(display,widget_context,None);
1069 if (x < text_info->x)
1070 (void) XDrawLine(display,window_info->id,window_info->annotate_context,
1071 text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1);
1072}
1073
1074/*
1075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076% %
1077% %
1078% %
1079+ X E d i t T e x t %
1080% %
1081% %
1082% %
1083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084%
1085% XEditText() edits a text string as indicated by the key symbol.
1086%
1087% The format of the XEditText function is:
1088%
1089% XEditText(display,text_info,key_symbol,text,state)
1090%
1091% A description of each parameter follows:
1092%
1093% o display: Specifies a connection to an X server; returned from
1094% XOpenDisplay.
1095%
1096% o text_info: Specifies a pointer to a XWidgetInfo structure. It
1097% contains the extents of the text.
1098%
1099% o key_symbol: A X11 KeySym that indicates what editing function to
1100% perform to the text.
1101%
1102% o text: A character string to insert into the text.
1103%
cristybb503372010-05-27 20:51:26 +00001104% o state: An size_t that indicates whether the key symbol is a
cristy3ed852e2009-09-05 21:47:34 +00001105% control character or not.
1106%
1107*/
1108static void XEditText(Display *display,XWidgetInfo *text_info,
cristybb503372010-05-27 20:51:26 +00001109 const KeySym key_symbol,char *text,const size_t state)
cristy3ed852e2009-09-05 21:47:34 +00001110{
1111 switch ((int) key_symbol)
1112 {
1113 case XK_BackSpace:
1114 case XK_Delete:
1115 {
1116 if (text_info->highlight)
1117 {
1118 /*
1119 Erase the entire line of text.
1120 */
1121 *text_info->text='\0';
1122 text_info->cursor=text_info->text;
1123 text_info->marker=text_info->text;
1124 text_info->highlight=MagickFalse;
1125 }
1126 /*
1127 Erase one character.
1128 */
1129 if (text_info->cursor != text_info->text)
1130 {
1131 text_info->cursor--;
1132 (void) CopyMagickString(text_info->cursor,text_info->cursor+1,
1133 MaxTextExtent);
1134 text_info->highlight=MagickFalse;
1135 break;
1136 }
1137 }
1138 case XK_Left:
1139 case XK_KP_Left:
1140 {
1141 /*
1142 Move cursor one position left.
1143 */
1144 if (text_info->cursor == text_info->text)
1145 break;
1146 text_info->cursor--;
1147 break;
1148 }
1149 case XK_Right:
1150 case XK_KP_Right:
1151 {
1152 /*
1153 Move cursor one position right.
1154 */
1155 if (text_info->cursor == (text_info->text+Extent(text_info->text)))
1156 break;
1157 text_info->cursor++;
1158 break;
1159 }
1160 default:
1161 {
1162 register char
1163 *p,
1164 *q;
1165
1166 register int
1167 i;
1168
1169 if (state & ControlState)
1170 break;
1171 if (*text == '\0')
1172 break;
cristy49e2d862010-11-12 02:50:30 +00001173 if ((Extent(text_info->text)+1) >= (int) MaxTextExtent)
cristy3ed852e2009-09-05 21:47:34 +00001174 (void) XBell(display,0);
1175 else
1176 {
1177 if (text_info->highlight)
1178 {
1179 /*
1180 Erase the entire line of text.
1181 */
1182 *text_info->text='\0';
1183 text_info->cursor=text_info->text;
1184 text_info->marker=text_info->text;
1185 text_info->highlight=MagickFalse;
1186 }
1187 /*
1188 Insert a string into the text.
1189 */
1190 q=text_info->text+Extent(text_info->text)+strlen(text);
1191 for (i=0; i <= Extent(text_info->cursor); i++)
1192 {
1193 *q=(*(q-Extent(text)));
1194 q--;
1195 }
1196 p=text;
1197 for (i=0; i < Extent(text); i++)
1198 *text_info->cursor++=(*p++);
1199 }
1200 break;
1201 }
1202 }
1203}
1204
1205/*
1206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207% %
1208% %
1209% %
1210+ X G e t W i d g e t I n f o %
1211% %
1212% %
1213% %
1214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215%
1216% XGetWidgetInfo() initializes the XWidgetInfo structure.
1217%
1218% The format of the XGetWidgetInfo function is:
1219%
1220% XGetWidgetInfo(text,widget_info)
1221%
1222% A description of each parameter follows:
1223%
1224% o text: A string of characters associated with the widget.
1225%
1226% o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
1227%
1228*/
1229static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info)
1230{
1231 /*
1232 Initialize widget info.
1233 */
1234 widget_info->id=(~0);
1235 widget_info->bevel_width=3;
1236 widget_info->width=1;
1237 widget_info->height=1;
1238 widget_info->x=0;
1239 widget_info->y=0;
1240 widget_info->min_y=0;
1241 widget_info->max_y=0;
1242 widget_info->raised=MagickTrue;
1243 widget_info->active=MagickFalse;
1244 widget_info->center=MagickTrue;
1245 widget_info->trough=MagickFalse;
1246 widget_info->highlight=MagickFalse;
1247 widget_info->text=(char *) text;
1248 widget_info->cursor=(char *) text;
1249 if (text != (char *) NULL)
1250 widget_info->cursor+=Extent(text);
1251 widget_info->marker=(char *) text;
1252}
1253
1254/*
1255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256% %
1257% %
1258% %
1259+ X H i g h l i g h t W i d g e t %
1260% %
1261% %
1262% %
1263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264%
1265% XHighlightWidget() draws a highlighted border around a window.
1266%
1267% The format of the XHighlightWidget function is:
1268%
1269% XHighlightWidget(display,window_info,x,y)
1270%
1271% A description of each parameter follows:
1272%
1273% o display: Specifies a pointer to the Display structure; returned from
1274% XOpenDisplay.
1275%
1276% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1277%
1278% o x: Specifies an integer representing the rectangle offset in the
1279% x-direction.
1280%
1281% o y: Specifies an integer representing the rectangle offset in the
1282% y-direction.
1283%
1284*/
1285static void XHighlightWidget(Display *display,const XWindowInfo *window_info,
1286 const int x,const int y)
1287{
1288 /*
1289 Draw the widget highlighting rectangle.
1290 */
1291 XSetBevelColor(display,window_info,MagickTrue);
1292 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
1293 window_info->width-(x << 1),window_info->height-(y << 1));
1294 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1295 x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
1296 XSetBevelColor(display,window_info,MagickFalse);
1297 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1298 x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1));
1299 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ X S c r e e n E v e n t %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% XScreenEvent() returns MagickTrue if the any event on the X server queue is
1314% associated with the widget window.
1315%
1316% The format of the XScreenEvent function is:
1317%
1318% int XScreenEvent(Display *display,XEvent *event,char *data)
1319%
1320% A description of each parameter follows:
1321%
1322% o display: Specifies a pointer to the Display structure; returned from
1323% XOpenDisplay.
1324%
1325% o event: Specifies a pointer to a X11 XEvent structure.
1326%
1327% o data: Specifies a pointer to a XWindows structure.
1328%
1329*/
1330
1331#if defined(__cplusplus) || defined(c_plusplus)
1332extern "C" {
1333#endif
1334
1335static int XScreenEvent(Display *display,XEvent *event,char *data)
1336{
1337 XWindows
1338 *windows;
1339
1340 windows=(XWindows *) data;
1341 if (event->xany.window == windows->popup.id)
1342 {
1343 if (event->type == MapNotify)
1344 windows->popup.mapped=MagickTrue;
1345 if (event->type == UnmapNotify)
1346 windows->popup.mapped=MagickFalse;
1347 return(MagickTrue);
1348 }
1349 if (event->xany.window == windows->widget.id)
1350 {
1351 if (event->type == MapNotify)
1352 windows->widget.mapped=MagickTrue;
1353 if (event->type == UnmapNotify)
1354 windows->widget.mapped=MagickFalse;
1355 return(MagickTrue);
1356 }
1357 switch (event->type)
1358 {
1359 case ButtonPress:
1360 {
1361 if ((event->xbutton.button == Button3) &&
1362 (event->xbutton.state & Mod1Mask))
1363 {
1364 /*
1365 Convert Alt-Button3 to Button2.
1366 */
1367 event->xbutton.button=Button2;
1368 event->xbutton.state&=(~Mod1Mask);
1369 }
1370 return(MagickTrue);
1371 }
1372 case Expose:
1373 {
1374 if (event->xexpose.window == windows->image.id)
1375 {
1376 XRefreshWindow(display,&windows->image,event);
1377 break;
1378 }
1379 if (event->xexpose.window == windows->magnify.id)
1380 if (event->xexpose.count == 0)
1381 if (windows->magnify.mapped)
1382 {
1383 XMakeMagnifyImage(display,windows);
1384 break;
1385 }
1386 if (event->xexpose.window == windows->command.id)
1387 if (event->xexpose.count == 0)
1388 {
1389 (void) XCommandWidget(display,windows,(const char **) NULL,event);
1390 break;
1391 }
1392 break;
1393 }
1394 case FocusOut:
1395 {
1396 /*
1397 Set input focus for backdrop window.
1398 */
1399 if (event->xfocus.window == windows->image.id)
1400 (void) XSetInputFocus(display,windows->image.id,RevertToNone,
1401 CurrentTime);
1402 return(MagickTrue);
1403 }
1404 case ButtonRelease:
1405 case KeyPress:
1406 case KeyRelease:
1407 case MotionNotify:
1408 case SelectionNotify:
1409 return(MagickTrue);
1410 default:
1411 break;
1412 }
1413 return(MagickFalse);
1414}
1415
1416#if defined(__cplusplus) || defined(c_plusplus)
1417}
1418#endif
1419
1420/*
1421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422% %
1423% %
1424% %
1425+ X S e t B e v e l C o l o r %
1426% %
1427% %
1428% %
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430%
1431% XSetBevelColor() sets the graphic context for drawing a beveled border.
1432%
1433% The format of the XSetBevelColor function is:
1434%
1435% XSetBevelColor(display,window_info,raised)
1436%
1437% A description of each parameter follows:
1438%
1439% o display: Specifies a pointer to the Display structure; returned from
1440% XOpenDisplay.
1441%
1442% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1443%
1444% o raised: A value other than zero indicates the color show be a
1445% "highlight" color, otherwise the "shadow" color is set.
1446%
1447*/
1448static void XSetBevelColor(Display *display,const XWindowInfo *window_info,
1449 const MagickStatusType raised)
1450{
1451 if (window_info->depth == 1)
1452 {
1453 Pixmap
1454 stipple;
1455
1456 /*
1457 Monochrome window.
1458 */
1459 (void) XSetBackground(display,window_info->widget_context,
1460 XBlackPixel(display,window_info->screen));
1461 (void) XSetForeground(display,window_info->widget_context,
1462 XWhitePixel(display,window_info->screen));
1463 (void) XSetFillStyle(display,window_info->widget_context,
1464 FillOpaqueStippled);
1465 stipple=window_info->highlight_stipple;
1466 if (raised == MagickFalse)
1467 stipple=window_info->shadow_stipple;
1468 (void) XSetStipple(display,window_info->widget_context,stipple);
1469 }
1470 else
1471 if (raised)
1472 (void) XSetForeground(display,window_info->widget_context,
1473 window_info->pixel_info->highlight_color.pixel);
1474 else
1475 (void) XSetForeground(display,window_info->widget_context,
1476 window_info->pixel_info->shadow_color.pixel);
1477}
1478
1479/*
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481% %
1482% %
1483% %
1484+ X S e t M a t t e C o l o r %
1485% %
1486% %
1487% %
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489%
1490% XSetMatteColor() sets the graphic context for drawing the matte.
1491%
1492% The format of the XSetMatteColor function is:
1493%
1494% XSetMatteColor(display,window_info,raised)
1495%
1496% A description of each parameter follows:
1497%
1498% o display: Specifies a pointer to the Display structure; returned from
1499% XOpenDisplay.
1500%
1501% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1502%
1503% o raised: A value other than zero indicates the matte is active.
1504%
1505*/
1506static void XSetMatteColor(Display *display,const XWindowInfo *window_info,
1507 const MagickStatusType raised)
1508{
1509 if (window_info->depth == 1)
1510 {
1511 /*
1512 Monochrome window.
1513 */
1514 if (raised)
1515 (void) XSetForeground(display,window_info->widget_context,
1516 XWhitePixel(display,window_info->screen));
1517 else
1518 (void) XSetForeground(display,window_info->widget_context,
1519 XBlackPixel(display,window_info->screen));
1520 }
1521 else
1522 if (raised)
1523 (void) XSetForeground(display,window_info->widget_context,
1524 window_info->pixel_info->matte_color.pixel);
1525 else
1526 (void) XSetForeground(display,window_info->widget_context,
1527 window_info->pixel_info->depth_color.pixel);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
1535+ X S e t T e x t C o l o r %
1536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541% XSetTextColor() sets the graphic context for drawing text on a matte.
1542%
1543% The format of the XSetTextColor function is:
1544%
1545% XSetTextColor(display,window_info,raised)
1546%
1547% A description of each parameter follows:
1548%
1549% o display: Specifies a pointer to the Display structure; returned from
1550% XOpenDisplay.
1551%
1552% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1553%
1554% o raised: A value other than zero indicates the color show be a
1555% "highlight" color, otherwise the "shadow" color is set.
1556%
1557*/
1558static void XSetTextColor(Display *display,const XWindowInfo *window_info,
1559 const MagickStatusType raised)
1560{
cristybb503372010-05-27 20:51:26 +00001561 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001562 foreground,
1563 matte;
1564
1565 if (window_info->depth == 1)
1566 {
1567 /*
1568 Monochrome window.
1569 */
1570 if (raised)
1571 (void) XSetForeground(display,window_info->widget_context,
1572 XBlackPixel(display,window_info->screen));
1573 else
1574 (void) XSetForeground(display,window_info->widget_context,
1575 XWhitePixel(display,window_info->screen));
1576 return;
1577 }
cristy49e2d862010-11-12 02:50:30 +00001578 foreground=(ssize_t) XPixelIntensity(
1579 &window_info->pixel_info->foreground_color);
cristybb503372010-05-27 20:51:26 +00001580 matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
cristy49e2d862010-11-12 02:50:30 +00001581 if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3))
cristy3ed852e2009-09-05 21:47:34 +00001582 (void) XSetForeground(display,window_info->widget_context,
1583 window_info->pixel_info->foreground_color.pixel);
1584 else
1585 (void) XSetForeground(display,window_info->widget_context,
1586 window_info->pixel_info->background_color.pixel);
1587}
1588
1589/*
1590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591% %
1592% %
1593% %
1594% X C o l o r B r o w s e r W i d g e t %
1595% %
1596% %
1597% %
1598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599%
1600% XColorBrowserWidget() displays a Color Browser widget with a color query
1601% to the user. The user keys a reply and presses the Action or Cancel button
1602% to exit. The typed text is returned as the reply function parameter.
1603%
1604% The format of the XColorBrowserWidget method is:
1605%
1606% void XColorBrowserWidget(Display *display,XWindows *windows,
1607% const char *action,char *reply)
1608%
1609% A description of each parameter follows:
1610%
1611% o display: Specifies a connection to an X server; returned from
1612% XOpenDisplay.
1613%
1614% o window: Specifies a pointer to a XWindows structure.
1615%
1616% o action: Specifies a pointer to the action of this widget.
1617%
1618% o reply: the response from the user is returned in this parameter.
1619%
1620*/
cristybcbda3f2011-09-03 13:01:22 +00001621MagickPrivate void XColorBrowserWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00001622 const char *action,char *reply)
1623{
1624#define CancelButtonText "Cancel"
1625#define ColornameText "Name:"
1626#define ColorPatternText "Pattern:"
1627#define GrabButtonText "Grab"
1628#define ResetButtonText "Reset"
1629
1630 char
1631 **colorlist,
1632 primary_selection[MaxTextExtent],
1633 reset_pattern[MaxTextExtent],
1634 text[MaxTextExtent];
1635
1636 ExceptionInfo
1637 *exception;
1638
1639 int
1640 x,
1641 y;
1642
1643 register int
1644 i;
1645
1646 static char
1647 glob_pattern[MaxTextExtent] = "*";
1648
1649 static MagickStatusType
1650 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
1651
1652 Status
1653 status;
1654
1655 unsigned int
1656 height,
1657 text_width,
1658 visible_colors,
1659 width;
1660
cristybb503372010-05-27 20:51:26 +00001661 size_t
cristy3ed852e2009-09-05 21:47:34 +00001662 colors,
1663 delay,
1664 state;
1665
1666 XColor
1667 color;
1668
1669 XEvent
1670 event;
1671
1672 XFontStruct
1673 *font_info;
1674
1675 XTextProperty
1676 window_name;
1677
1678 XWidgetInfo
1679 action_info,
1680 cancel_info,
1681 expose_info,
1682 grab_info,
1683 list_info,
1684 mode_info,
1685 north_info,
1686 reply_info,
1687 reset_info,
1688 scroll_info,
1689 selection_info,
1690 slider_info,
1691 south_info,
1692 text_info;
1693
1694 XWindowChanges
1695 window_changes;
1696
1697 /*
1698 Get color list and sort in ascending order.
1699 */
1700 assert(display != (Display *) NULL);
1701 assert(windows != (XWindows *) NULL);
1702 assert(action != (char *) NULL);
1703 assert(reply != (char *) NULL);
1704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
1705 XSetCursorState(display,windows,MagickTrue);
1706 XCheckRefreshWindows(display,windows);
1707 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
1708 exception=AcquireExceptionInfo();
1709 colorlist=GetColorList(glob_pattern,&colors,exception);
1710 if (colorlist == (char **) NULL)
1711 {
1712 /*
1713 Pattern failed, obtain all the colors.
1714 */
1715 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
1716 colorlist=GetColorList(glob_pattern,&colors,exception);
1717 if (colorlist == (char **) NULL)
1718 {
1719 XNoticeWidget(display,windows,"Unable to obtain colors names:",
1720 glob_pattern);
1721 (void) XDialogWidget(display,windows,action,"Enter color name:",
1722 reply);
1723 return;
1724 }
1725 }
1726 /*
1727 Determine Color Browser widget attributes.
1728 */
1729 font_info=windows->widget.font_info;
1730 text_width=0;
cristy49e2d862010-11-12 02:50:30 +00001731 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001732 if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
1733 text_width=WidgetTextWidth(font_info,colorlist[i]);
1734 width=WidgetTextWidth(font_info,(char *) action);
1735 if (WidgetTextWidth(font_info,CancelButtonText) > width)
1736 width=WidgetTextWidth(font_info,CancelButtonText);
1737 if (WidgetTextWidth(font_info,ResetButtonText) > width)
1738 width=WidgetTextWidth(font_info,ResetButtonText);
1739 if (WidgetTextWidth(font_info,GrabButtonText) > width)
1740 width=WidgetTextWidth(font_info,GrabButtonText);
1741 width+=QuantumMargin;
1742 if (WidgetTextWidth(font_info,ColorPatternText) > width)
1743 width=WidgetTextWidth(font_info,ColorPatternText);
1744 if (WidgetTextWidth(font_info,ColornameText) > width)
1745 width=WidgetTextWidth(font_info,ColornameText);
1746 height=(unsigned int) (font_info->ascent+font_info->descent);
1747 /*
1748 Position Color Browser widget.
1749 */
1750 windows->widget.width=(unsigned int)
1751 (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
1752 windows->widget.min_width=(unsigned int)
1753 (width+MinTextWidth+4*QuantumMargin);
1754 if (windows->widget.width < windows->widget.min_width)
1755 windows->widget.width=windows->widget.min_width;
1756 windows->widget.height=(unsigned int)
1757 ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
1758 windows->widget.min_height=(unsigned int)
1759 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
1760 if (windows->widget.height < windows->widget.min_height)
1761 windows->widget.height=windows->widget.min_height;
1762 XConstrainWindowPosition(display,&windows->widget);
1763 /*
1764 Map Color Browser widget.
1765 */
1766 (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
1767 MaxTextExtent);
1768 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
1769 if (status != False)
1770 {
1771 XSetWMName(display,windows->widget.id,&window_name);
1772 XSetWMIconName(display,windows->widget.id,&window_name);
1773 (void) XFree((void *) window_name.value);
1774 }
1775 window_changes.width=(int) windows->widget.width;
1776 window_changes.height=(int) windows->widget.height;
1777 window_changes.x=windows->widget.x;
1778 window_changes.y=windows->widget.y;
1779 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
1780 mask,&window_changes);
1781 (void) XMapRaised(display,windows->widget.id);
1782 windows->widget.mapped=MagickFalse;
1783 /*
1784 Respond to X events.
1785 */
1786 XGetWidgetInfo((char *) NULL,&slider_info);
1787 XGetWidgetInfo((char *) NULL,&north_info);
1788 XGetWidgetInfo((char *) NULL,&south_info);
1789 XGetWidgetInfo((char *) NULL,&expose_info);
1790 visible_colors=0;
1791 delay=SuspendTime << 2;
1792 state=UpdateConfigurationState;
1793 do
1794 {
1795 if (state & UpdateConfigurationState)
1796 {
1797 int
1798 id;
1799
1800 /*
1801 Initialize button information.
1802 */
1803 XGetWidgetInfo(CancelButtonText,&cancel_info);
1804 cancel_info.width=width;
1805 cancel_info.height=(unsigned int) ((3*height) >> 1);
1806 cancel_info.x=(int)
1807 (windows->widget.width-cancel_info.width-QuantumMargin-2);
1808 cancel_info.y=(int)
1809 (windows->widget.height-cancel_info.height-QuantumMargin);
1810 XGetWidgetInfo(action,&action_info);
1811 action_info.width=width;
1812 action_info.height=(unsigned int) ((3*height) >> 1);
1813 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
1814 (action_info.bevel_width << 1));
1815 action_info.y=cancel_info.y;
1816 XGetWidgetInfo(GrabButtonText,&grab_info);
1817 grab_info.width=width;
1818 grab_info.height=(unsigned int) ((3*height) >> 1);
1819 grab_info.x=QuantumMargin;
1820 grab_info.y=((5*QuantumMargin) >> 1)+height;
1821 XGetWidgetInfo(ResetButtonText,&reset_info);
1822 reset_info.width=width;
1823 reset_info.height=(unsigned int) ((3*height) >> 1);
1824 reset_info.x=QuantumMargin;
1825 reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
1826 /*
1827 Initialize reply information.
1828 */
1829 XGetWidgetInfo(reply,&reply_info);
1830 reply_info.raised=MagickFalse;
1831 reply_info.bevel_width--;
1832 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
1833 reply_info.height=height << 1;
1834 reply_info.x=(int) (width+(QuantumMargin << 1));
1835 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
1836 /*
1837 Initialize mode information.
1838 */
1839 XGetWidgetInfo((char *) NULL,&mode_info);
1840 mode_info.active=MagickTrue;
1841 mode_info.bevel_width=0;
1842 mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
1843 mode_info.height=action_info.height;
1844 mode_info.x=QuantumMargin;
1845 mode_info.y=action_info.y;
1846 /*
1847 Initialize scroll information.
1848 */
1849 XGetWidgetInfo((char *) NULL,&scroll_info);
1850 scroll_info.bevel_width--;
1851 scroll_info.width=height;
1852 scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
1853 (QuantumMargin >> 1));
1854 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
1855 scroll_info.y=grab_info.y-reply_info.bevel_width;
1856 scroll_info.raised=MagickFalse;
1857 scroll_info.trough=MagickTrue;
1858 north_info=scroll_info;
1859 north_info.raised=MagickTrue;
1860 north_info.width-=(north_info.bevel_width << 1);
1861 north_info.height=north_info.width-1;
1862 north_info.x+=north_info.bevel_width;
1863 north_info.y+=north_info.bevel_width;
1864 south_info=north_info;
1865 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
1866 south_info.height;
1867 id=slider_info.id;
1868 slider_info=north_info;
1869 slider_info.id=id;
1870 slider_info.width-=2;
1871 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
1872 slider_info.bevel_width+2;
1873 slider_info.height=scroll_info.height-((slider_info.min_y-
1874 scroll_info.y+1) << 1)+4;
1875 visible_colors=scroll_info.height/(height+(height >> 3));
1876 if (colors > visible_colors)
1877 slider_info.height=(unsigned int)
1878 ((visible_colors*slider_info.height)/colors);
1879 slider_info.max_y=south_info.y-south_info.bevel_width-
1880 slider_info.bevel_width-2;
1881 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
1882 slider_info.y=slider_info.min_y;
1883 expose_info=scroll_info;
1884 expose_info.y=slider_info.y;
1885 /*
1886 Initialize list information.
1887 */
1888 XGetWidgetInfo((char *) NULL,&list_info);
1889 list_info.raised=MagickFalse;
1890 list_info.bevel_width--;
1891 list_info.width=(unsigned int)
1892 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
1893 list_info.height=scroll_info.height;
1894 list_info.x=reply_info.x;
1895 list_info.y=scroll_info.y;
1896 if (windows->widget.mapped == MagickFalse)
1897 state|=JumpListState;
1898 /*
1899 Initialize text information.
1900 */
1901 *text='\0';
1902 XGetWidgetInfo(text,&text_info);
1903 text_info.center=MagickFalse;
1904 text_info.width=reply_info.width;
1905 text_info.height=height;
1906 text_info.x=list_info.x-(QuantumMargin >> 1);
1907 text_info.y=QuantumMargin;
1908 /*
1909 Initialize selection information.
1910 */
1911 XGetWidgetInfo((char *) NULL,&selection_info);
1912 selection_info.center=MagickFalse;
1913 selection_info.width=list_info.width;
1914 selection_info.height=(unsigned int) ((9*height) >> 3);
1915 selection_info.x=list_info.x;
1916 state&=(~UpdateConfigurationState);
1917 }
1918 if (state & RedrawWidgetState)
1919 {
1920 /*
1921 Redraw Color Browser window.
1922 */
1923 x=QuantumMargin;
1924 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
1925 (void) XDrawString(display,windows->widget.id,
1926 windows->widget.annotate_context,x,y,ColorPatternText,
1927 Extent(ColorPatternText));
1928 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
1929 XDrawWidgetText(display,&windows->widget,&text_info);
1930 XDrawBeveledButton(display,&windows->widget,&grab_info);
1931 XDrawBeveledButton(display,&windows->widget,&reset_info);
1932 XDrawBeveledMatte(display,&windows->widget,&list_info);
1933 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
1934 XDrawTriangleNorth(display,&windows->widget,&north_info);
1935 XDrawBeveledButton(display,&windows->widget,&slider_info);
1936 XDrawTriangleSouth(display,&windows->widget,&south_info);
1937 x=QuantumMargin;
1938 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
1939 (void) XDrawString(display,windows->widget.id,
1940 windows->widget.annotate_context,x,y,ColornameText,
1941 Extent(ColornameText));
1942 XDrawBeveledMatte(display,&windows->widget,&reply_info);
1943 XDrawMatteText(display,&windows->widget,&reply_info);
1944 XDrawBeveledButton(display,&windows->widget,&action_info);
1945 XDrawBeveledButton(display,&windows->widget,&cancel_info);
1946 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
1947 selection_info.id=(~0);
1948 state|=RedrawActionState;
1949 state|=RedrawListState;
1950 state&=(~RedrawWidgetState);
1951 }
1952 if (state & UpdateListState)
1953 {
1954 char
1955 **checklist;
1956
cristybb503372010-05-27 20:51:26 +00001957 size_t
cristy3ed852e2009-09-05 21:47:34 +00001958 number_colors;
1959
1960 status=XParseColor(display,windows->widget.map_info->colormap,
1961 glob_pattern,&color);
1962 if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
1963 {
1964 /*
1965 Reply is a single color name-- exit.
1966 */
1967 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
1968 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1969 action_info.raised=MagickFalse;
1970 XDrawBeveledButton(display,&windows->widget,&action_info);
1971 break;
1972 }
1973 /*
1974 Update color list.
1975 */
1976 checklist=GetColorList(glob_pattern,&number_colors,exception);
1977 if (number_colors == 0)
1978 {
1979 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1980 (void) XBell(display,0);
1981 }
1982 else
1983 {
cristy49e2d862010-11-12 02:50:30 +00001984 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001985 colorlist[i]=DestroyString(colorlist[i]);
1986 if (colorlist != (char **) NULL)
1987 colorlist=(char **) RelinquishMagickMemory(colorlist);
1988 colorlist=checklist;
1989 colors=number_colors;
1990 }
1991 /*
1992 Sort color list in ascending order.
1993 */
1994 slider_info.height=
1995 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
1996 if (colors > visible_colors)
1997 slider_info.height=(unsigned int)
1998 ((visible_colors*slider_info.height)/colors);
1999 slider_info.max_y=south_info.y-south_info.bevel_width-
2000 slider_info.bevel_width-2;
2001 slider_info.id=0;
2002 slider_info.y=slider_info.min_y;
2003 expose_info.y=slider_info.y;
2004 selection_info.id=(~0);
2005 list_info.id=(~0);
2006 state|=RedrawListState;
2007 /*
2008 Redraw color name & reply.
2009 */
2010 *reply_info.text='\0';
2011 reply_info.cursor=reply_info.text;
2012 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
2013 XDrawWidgetText(display,&windows->widget,&text_info);
2014 XDrawMatteText(display,&windows->widget,&reply_info);
2015 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
2016 XDrawTriangleNorth(display,&windows->widget,&north_info);
2017 XDrawBeveledButton(display,&windows->widget,&slider_info);
2018 XDrawTriangleSouth(display,&windows->widget,&south_info);
2019 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
2020 state&=(~UpdateListState);
2021 }
2022 if (state & JumpListState)
2023 {
2024 /*
2025 Jump scroll to match user color.
2026 */
2027 list_info.id=(~0);
cristy49e2d862010-11-12 02:50:30 +00002028 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002029 if (LocaleCompare(colorlist[i],reply) >= 0)
2030 {
2031 list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
2032 break;
2033 }
2034 if ((i < slider_info.id) ||
2035 (i >= (int) (slider_info.id+visible_colors)))
2036 slider_info.id=i-(visible_colors >> 1);
2037 selection_info.id=(~0);
2038 state|=RedrawListState;
2039 state&=(~JumpListState);
2040 }
2041 if (state & RedrawListState)
2042 {
2043 /*
2044 Determine slider id and position.
2045 */
2046 if (slider_info.id >= (int) (colors-visible_colors))
2047 slider_info.id=(int) (colors-visible_colors);
2048 if ((slider_info.id < 0) || (colors <= visible_colors))
2049 slider_info.id=0;
2050 slider_info.y=slider_info.min_y;
2051 if (colors != 0)
cristy8891f9c2010-06-04 23:32:17 +00002052 slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
2053 slider_info.min_y+1)/colors);
cristy3ed852e2009-09-05 21:47:34 +00002054 if (slider_info.id != selection_info.id)
2055 {
2056 /*
2057 Redraw scroll bar and file names.
2058 */
2059 selection_info.id=slider_info.id;
2060 selection_info.y=list_info.y+(height >> 3)+2;
2061 for (i=0; i < (int) visible_colors; i++)
2062 {
2063 selection_info.raised=(slider_info.id+i) != list_info.id ?
2064 MagickTrue : MagickFalse;
2065 selection_info.text=(char *) NULL;
cristy49e2d862010-11-12 02:50:30 +00002066 if ((slider_info.id+i) < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002067 selection_info.text=colorlist[slider_info.id+i];
2068 XDrawWidgetText(display,&windows->widget,&selection_info);
2069 selection_info.y+=(int) selection_info.height;
2070 }
2071 /*
2072 Update slider.
2073 */
2074 if (slider_info.y > expose_info.y)
2075 {
2076 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
2077 expose_info.y=slider_info.y-expose_info.height-
2078 slider_info.bevel_width-1;
2079 }
2080 else
2081 {
2082 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
2083 expose_info.y=slider_info.y+slider_info.height+
2084 slider_info.bevel_width+1;
2085 }
2086 XDrawTriangleNorth(display,&windows->widget,&north_info);
2087 XDrawMatte(display,&windows->widget,&expose_info);
2088 XDrawBeveledButton(display,&windows->widget,&slider_info);
2089 XDrawTriangleSouth(display,&windows->widget,&south_info);
2090 expose_info.y=slider_info.y;
2091 }
2092 state&=(~RedrawListState);
2093 }
2094 if (state & RedrawActionState)
2095 {
2096 static char
2097 colorname[MaxTextExtent];
2098
2099 /*
2100 Display the selected color in a drawing area.
2101 */
2102 color=windows->widget.pixel_info->matte_color;
2103 (void) XParseColor(display,windows->widget.map_info->colormap,
2104 reply_info.text,&windows->widget.pixel_info->matte_color);
2105 XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
2106 (unsigned int) windows->widget.visual_info->colormap_size,
2107 &windows->widget.pixel_info->matte_color);
2108 mode_info.text=colorname;
cristyb51dff52011-05-19 16:55:47 +00002109 (void) FormatLocaleString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
cristy3ed852e2009-09-05 21:47:34 +00002110 windows->widget.pixel_info->matte_color.red,
2111 windows->widget.pixel_info->matte_color.green,
2112 windows->widget.pixel_info->matte_color.blue);
2113 XDrawBeveledButton(display,&windows->widget,&mode_info);
2114 windows->widget.pixel_info->matte_color=color;
2115 state&=(~RedrawActionState);
2116 }
2117 /*
2118 Wait for next event.
2119 */
2120 if (north_info.raised && south_info.raised)
2121 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
2122 else
2123 {
2124 /*
2125 Brief delay before advancing scroll bar.
2126 */
2127 XDelay(display,delay);
2128 delay=SuspendTime;
2129 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
2130 if (north_info.raised == MagickFalse)
2131 if (slider_info.id > 0)
2132 {
2133 /*
2134 Move slider up.
2135 */
2136 slider_info.id--;
2137 state|=RedrawListState;
2138 }
2139 if (south_info.raised == MagickFalse)
cristy49e2d862010-11-12 02:50:30 +00002140 if (slider_info.id < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002141 {
2142 /*
2143 Move slider down.
2144 */
2145 slider_info.id++;
2146 state|=RedrawListState;
2147 }
2148 if (event.type != ButtonRelease)
2149 continue;
2150 }
2151 switch (event.type)
2152 {
2153 case ButtonPress:
2154 {
2155 if (MatteIsActive(slider_info,event.xbutton))
2156 {
2157 /*
2158 Track slider.
2159 */
2160 slider_info.active=MagickTrue;
2161 break;
2162 }
2163 if (MatteIsActive(north_info,event.xbutton))
2164 if (slider_info.id > 0)
2165 {
2166 /*
2167 Move slider up.
2168 */
2169 north_info.raised=MagickFalse;
2170 slider_info.id--;
2171 state|=RedrawListState;
2172 break;
2173 }
2174 if (MatteIsActive(south_info,event.xbutton))
cristy49e2d862010-11-12 02:50:30 +00002175 if (slider_info.id < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002176 {
2177 /*
2178 Move slider down.
2179 */
2180 south_info.raised=MagickFalse;
2181 slider_info.id++;
2182 state|=RedrawListState;
2183 break;
2184 }
2185 if (MatteIsActive(scroll_info,event.xbutton))
2186 {
2187 /*
2188 Move slider.
2189 */
2190 if (event.xbutton.y < slider_info.y)
2191 slider_info.id-=(visible_colors-1);
2192 else
2193 slider_info.id+=(visible_colors-1);
2194 state|=RedrawListState;
2195 break;
2196 }
2197 if (MatteIsActive(list_info,event.xbutton))
2198 {
2199 int
2200 id;
2201
2202 /*
2203 User pressed list matte.
2204 */
2205 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
2206 selection_info.height;
2207 if (id >= (int) colors)
2208 break;
2209 (void) CopyMagickString(reply_info.text,colorlist[id],
2210 MaxTextExtent);
2211 reply_info.highlight=MagickFalse;
2212 reply_info.marker=reply_info.text;
2213 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2214 XDrawMatteText(display,&windows->widget,&reply_info);
2215 state|=RedrawActionState;
2216 if (id == list_info.id)
2217 {
2218 (void) CopyMagickString(glob_pattern,reply_info.text,
2219 MaxTextExtent);
2220 state|=UpdateListState;
2221 }
2222 selection_info.id=(~0);
2223 list_info.id=id;
2224 state|=RedrawListState;
2225 break;
2226 }
2227 if (MatteIsActive(grab_info,event.xbutton))
2228 {
2229 /*
2230 User pressed Grab button.
2231 */
2232 grab_info.raised=MagickFalse;
2233 XDrawBeveledButton(display,&windows->widget,&grab_info);
2234 break;
2235 }
2236 if (MatteIsActive(reset_info,event.xbutton))
2237 {
2238 /*
2239 User pressed Reset button.
2240 */
2241 reset_info.raised=MagickFalse;
2242 XDrawBeveledButton(display,&windows->widget,&reset_info);
2243 break;
2244 }
2245 if (MatteIsActive(mode_info,event.xbutton))
2246 {
2247 /*
2248 User pressed mode button.
2249 */
2250 (void) CopyMagickString(reply_info.text,mode_info.text,
2251 MaxTextExtent);
2252 (void) CopyMagickString(primary_selection,reply_info.text,
2253 MaxTextExtent);
2254 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2255 event.xbutton.time);
2256 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2257 windows->widget.id ? MagickTrue : MagickFalse;
2258 reply_info.marker=reply_info.text;
2259 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2260 XDrawMatteText(display,&windows->widget,&reply_info);
2261 break;
2262 }
2263 if (MatteIsActive(action_info,event.xbutton))
2264 {
2265 /*
2266 User pressed action button.
2267 */
2268 action_info.raised=MagickFalse;
2269 XDrawBeveledButton(display,&windows->widget,&action_info);
2270 break;
2271 }
2272 if (MatteIsActive(cancel_info,event.xbutton))
2273 {
2274 /*
2275 User pressed Cancel button.
2276 */
2277 cancel_info.raised=MagickFalse;
2278 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2279 break;
2280 }
2281 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2282 break;
2283 if (event.xbutton.button != Button2)
2284 {
2285 static Time
2286 click_time;
2287
2288 /*
2289 Move text cursor to position of button press.
2290 */
2291 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
2292 for (i=1; i <= Extent(reply_info.marker); i++)
2293 if (XTextWidth(font_info,reply_info.marker,i) > x)
2294 break;
2295 reply_info.cursor=reply_info.marker+i-1;
2296 if (event.xbutton.time > (click_time+DoubleClick))
2297 reply_info.highlight=MagickFalse;
2298 else
2299 {
2300 /*
2301 Become the XA_PRIMARY selection owner.
2302 */
2303 (void) CopyMagickString(primary_selection,reply_info.text,
2304 MaxTextExtent);
2305 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2306 event.xbutton.time);
2307 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2308 windows->widget.id ? MagickTrue : MagickFalse;
2309 }
2310 XDrawMatteText(display,&windows->widget,&reply_info);
2311 click_time=event.xbutton.time;
2312 break;
2313 }
2314 /*
2315 Request primary selection.
2316 */
2317 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2318 windows->widget.id,event.xbutton.time);
2319 break;
2320 }
2321 case ButtonRelease:
2322 {
2323 if (windows->widget.mapped == MagickFalse)
2324 break;
2325 if (north_info.raised == MagickFalse)
2326 {
2327 /*
2328 User released up button.
2329 */
2330 delay=SuspendTime << 2;
2331 north_info.raised=MagickTrue;
2332 XDrawTriangleNorth(display,&windows->widget,&north_info);
2333 }
2334 if (south_info.raised == MagickFalse)
2335 {
2336 /*
2337 User released down button.
2338 */
2339 delay=SuspendTime << 2;
2340 south_info.raised=MagickTrue;
2341 XDrawTriangleSouth(display,&windows->widget,&south_info);
2342 }
2343 if (slider_info.active)
2344 {
2345 /*
2346 Stop tracking slider.
2347 */
2348 slider_info.active=MagickFalse;
2349 break;
2350 }
2351 if (grab_info.raised == MagickFalse)
2352 {
2353 if (event.xbutton.window == windows->widget.id)
2354 if (MatteIsActive(grab_info,event.xbutton))
2355 {
2356 /*
2357 Select a pen color from the X server.
2358 */
2359 (void) XGetWindowColor(display,windows,reply_info.text);
2360 reply_info.marker=reply_info.text;
2361 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2362 XDrawMatteText(display,&windows->widget,&reply_info);
2363 state|=RedrawActionState;
2364 }
2365 grab_info.raised=MagickTrue;
2366 XDrawBeveledButton(display,&windows->widget,&grab_info);
2367 }
2368 if (reset_info.raised == MagickFalse)
2369 {
2370 if (event.xbutton.window == windows->widget.id)
2371 if (MatteIsActive(reset_info,event.xbutton))
2372 {
2373 (void) CopyMagickString(glob_pattern,reset_pattern,
2374 MaxTextExtent);
2375 state|=UpdateListState;
2376 }
2377 reset_info.raised=MagickTrue;
2378 XDrawBeveledButton(display,&windows->widget,&reset_info);
2379 }
2380 if (action_info.raised == MagickFalse)
2381 {
2382 if (event.xbutton.window == windows->widget.id)
2383 {
2384 if (MatteIsActive(action_info,event.xbutton))
2385 {
2386 if (*reply_info.text == '\0')
2387 (void) XBell(display,0);
2388 else
2389 state|=ExitState;
2390 }
2391 }
2392 action_info.raised=MagickTrue;
2393 XDrawBeveledButton(display,&windows->widget,&action_info);
2394 }
2395 if (cancel_info.raised == MagickFalse)
2396 {
2397 if (event.xbutton.window == windows->widget.id)
2398 if (MatteIsActive(cancel_info,event.xbutton))
2399 {
2400 *reply_info.text='\0';
2401 state|=ExitState;
2402 }
2403 cancel_info.raised=MagickTrue;
2404 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2405 }
2406 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2407 break;
2408 break;
2409 }
2410 case ClientMessage:
2411 {
2412 /*
2413 If client window delete message, exit.
2414 */
2415 if (event.xclient.message_type != windows->wm_protocols)
2416 break;
2417 if (*event.xclient.data.l == (int) windows->wm_take_focus)
2418 {
2419 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2420 (Time) event.xclient.data.l[1]);
2421 break;
2422 }
2423 if (*event.xclient.data.l != (int) windows->wm_delete_window)
2424 break;
2425 if (event.xclient.window == windows->widget.id)
2426 {
2427 *reply_info.text='\0';
2428 state|=ExitState;
2429 break;
2430 }
2431 break;
2432 }
2433 case ConfigureNotify:
2434 {
2435 /*
2436 Update widget configuration.
2437 */
2438 if (event.xconfigure.window != windows->widget.id)
2439 break;
2440 if ((event.xconfigure.width == (int) windows->widget.width) &&
2441 (event.xconfigure.height == (int) windows->widget.height))
2442 break;
2443 windows->widget.width=(unsigned int)
2444 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
2445 windows->widget.height=(unsigned int)
2446 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
2447 state|=UpdateConfigurationState;
2448 break;
2449 }
2450 case EnterNotify:
2451 {
2452 if (event.xcrossing.window != windows->widget.id)
2453 break;
2454 state&=(~InactiveWidgetState);
2455 break;
2456 }
2457 case Expose:
2458 {
2459 if (event.xexpose.window != windows->widget.id)
2460 break;
2461 if (event.xexpose.count != 0)
2462 break;
2463 state|=RedrawWidgetState;
2464 break;
2465 }
2466 case KeyPress:
2467 {
2468 static char
2469 command[MaxTextExtent];
2470
2471 static int
2472 length;
2473
2474 static KeySym
2475 key_symbol;
2476
2477 /*
2478 Respond to a user key press.
2479 */
2480 if (event.xkey.window != windows->widget.id)
2481 break;
2482 length=XLookupString((XKeyEvent *) &event.xkey,command,
2483 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2484 *(command+length)='\0';
2485 if (AreaIsActive(scroll_info,event.xkey))
2486 {
2487 /*
2488 Move slider.
2489 */
2490 switch ((int) key_symbol)
2491 {
2492 case XK_Home:
2493 case XK_KP_Home:
2494 {
2495 slider_info.id=0;
2496 break;
2497 }
2498 case XK_Up:
2499 case XK_KP_Up:
2500 {
2501 slider_info.id--;
2502 break;
2503 }
2504 case XK_Down:
2505 case XK_KP_Down:
2506 {
2507 slider_info.id++;
2508 break;
2509 }
2510 case XK_Prior:
2511 case XK_KP_Prior:
2512 {
2513 slider_info.id-=visible_colors;
2514 break;
2515 }
2516 case XK_Next:
2517 case XK_KP_Next:
2518 {
2519 slider_info.id+=visible_colors;
2520 break;
2521 }
2522 case XK_End:
2523 case XK_KP_End:
2524 {
2525 slider_info.id=(int) colors;
2526 break;
2527 }
2528 }
2529 state|=RedrawListState;
2530 break;
2531 }
2532 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
2533 {
2534 /*
2535 Read new color or glob patterm.
2536 */
2537 if (*reply_info.text == '\0')
2538 break;
2539 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
2540 state|=UpdateListState;
2541 break;
2542 }
2543 if (key_symbol == XK_Control_L)
2544 {
2545 state|=ControlState;
2546 break;
2547 }
2548 if (state & ControlState)
2549 switch ((int) key_symbol)
2550 {
2551 case XK_u:
2552 case XK_U:
2553 {
2554 /*
2555 Erase the entire line of text.
2556 */
2557 *reply_info.text='\0';
2558 reply_info.cursor=reply_info.text;
2559 reply_info.marker=reply_info.text;
2560 reply_info.highlight=MagickFalse;
2561 break;
2562 }
2563 default:
2564 break;
2565 }
2566 XEditText(display,&reply_info,key_symbol,command,state);
2567 XDrawMatteText(display,&windows->widget,&reply_info);
2568 state|=JumpListState;
2569 status=XParseColor(display,windows->widget.map_info->colormap,
2570 reply_info.text,&color);
2571 if (status != False)
2572 state|=RedrawActionState;
2573 break;
2574 }
2575 case KeyRelease:
2576 {
2577 static char
2578 command[MaxTextExtent];
2579
2580 static KeySym
2581 key_symbol;
2582
2583 /*
2584 Respond to a user key release.
2585 */
2586 if (event.xkey.window != windows->widget.id)
2587 break;
2588 (void) XLookupString((XKeyEvent *) &event.xkey,command,
2589 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2590 if (key_symbol == XK_Control_L)
2591 state&=(~ControlState);
2592 break;
2593 }
2594 case LeaveNotify:
2595 {
2596 if (event.xcrossing.window != windows->widget.id)
2597 break;
2598 state|=InactiveWidgetState;
2599 break;
2600 }
2601 case MapNotify:
2602 {
2603 mask&=(~CWX);
2604 mask&=(~CWY);
2605 break;
2606 }
2607 case MotionNotify:
2608 {
2609 /*
2610 Discard pending button motion events.
2611 */
2612 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
2613 if (slider_info.active)
2614 {
2615 /*
2616 Move slider matte.
2617 */
2618 slider_info.y=event.xmotion.y-
2619 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
2620 if (slider_info.y < slider_info.min_y)
2621 slider_info.y=slider_info.min_y;
2622 if (slider_info.y > slider_info.max_y)
2623 slider_info.y=slider_info.max_y;
2624 slider_info.id=0;
2625 if (slider_info.y != slider_info.min_y)
2626 slider_info.id=(int) ((colors*(slider_info.y-
2627 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
2628 state|=RedrawListState;
2629 break;
2630 }
2631 if (state & InactiveWidgetState)
2632 break;
2633 if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
2634 {
2635 /*
2636 Grab button status changed.
2637 */
2638 grab_info.raised=!grab_info.raised;
2639 XDrawBeveledButton(display,&windows->widget,&grab_info);
2640 break;
2641 }
2642 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
2643 {
2644 /*
2645 Reset button status changed.
2646 */
2647 reset_info.raised=!reset_info.raised;
2648 XDrawBeveledButton(display,&windows->widget,&reset_info);
2649 break;
2650 }
2651 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
2652 {
2653 /*
2654 Action button status changed.
2655 */
2656 action_info.raised=action_info.raised == MagickFalse ?
2657 MagickTrue : MagickFalse;
2658 XDrawBeveledButton(display,&windows->widget,&action_info);
2659 break;
2660 }
2661 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
2662 {
2663 /*
2664 Cancel button status changed.
2665 */
2666 cancel_info.raised=cancel_info.raised == MagickFalse ?
2667 MagickTrue : MagickFalse;
2668 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2669 break;
2670 }
2671 break;
2672 }
2673 case SelectionClear:
2674 {
2675 reply_info.highlight=MagickFalse;
2676 XDrawMatteText(display,&windows->widget,&reply_info);
2677 break;
2678 }
2679 case SelectionNotify:
2680 {
2681 Atom
2682 type;
2683
2684 int
2685 format;
2686
2687 unsigned char
2688 *data;
2689
cristyf2faecf2010-05-28 19:19:36 +00002690 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002691 after,
2692 length;
2693
2694 /*
2695 Obtain response from primary selection.
2696 */
2697 if (event.xselection.property == (Atom) None)
2698 break;
2699 status=XGetWindowProperty(display,event.xselection.requestor,
2700 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
2701 &format,&length,&after,&data);
2702 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2703 (length == 0))
2704 break;
cristy37e0b382011-06-07 13:31:21 +00002705 if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +00002706 (void) XBell(display,0);
2707 else
2708 {
2709 /*
2710 Insert primary selection in reply text.
2711 */
2712 *(data+length)='\0';
2713 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
2714 state);
2715 XDrawMatteText(display,&windows->widget,&reply_info);
2716 state|=JumpListState;
2717 state|=RedrawActionState;
2718 }
2719 (void) XFree((void *) data);
2720 break;
2721 }
2722 case SelectionRequest:
2723 {
2724 XSelectionEvent
2725 notify;
2726
2727 XSelectionRequestEvent
2728 *request;
2729
2730 if (reply_info.highlight == MagickFalse)
2731 break;
2732 /*
2733 Set primary selection.
2734 */
2735 request=(&(event.xselectionrequest));
2736 (void) XChangeProperty(request->display,request->requestor,
2737 request->property,request->target,8,PropModeReplace,
2738 (unsigned char *) primary_selection,Extent(primary_selection));
2739 notify.type=SelectionNotify;
2740 notify.send_event=MagickTrue;
2741 notify.display=request->display;
2742 notify.requestor=request->requestor;
2743 notify.selection=request->selection;
2744 notify.target=request->target;
2745 notify.time=request->time;
2746 if (request->property == None)
2747 notify.property=request->target;
2748 else
2749 notify.property=request->property;
2750 (void) XSendEvent(request->display,request->requestor,False,
2751 NoEventMask,(XEvent *) &notify);
2752 }
2753 default:
2754 break;
2755 }
2756 } while ((state & ExitState) == 0);
2757 XSetCursorState(display,windows,MagickFalse);
2758 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
2759 XCheckRefreshWindows(display,windows);
2760 /*
2761 Free color list.
2762 */
cristy49e2d862010-11-12 02:50:30 +00002763 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002764 colorlist[i]=DestroyString(colorlist[i]);
2765 if (colorlist != (char **) NULL)
2766 colorlist=(char **) RelinquishMagickMemory(colorlist);
2767 exception=DestroyExceptionInfo(exception);
2768 if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
2769 return;
2770 status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
2771 if (status != False)
2772 return;
2773 XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
2774 (void) CopyMagickString(reply,"gray",MaxTextExtent);
2775}
2776
2777/*
2778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2779% %
2780% %
2781% %
2782% X C o m m a n d W i d g e t %
2783% %
2784% %
2785% %
2786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2787%
2788% XCommandWidget() maps a menu and returns the command pointed to by the user
2789% when the button is released.
2790%
2791% The format of the XCommandWidget method is:
2792%
2793% int XCommandWidget(Display *display,XWindows *windows,
2794% const char **selections,XEvent *event)
2795%
2796% A description of each parameter follows:
2797%
2798% o selection_number: Specifies the number of the selection that the
2799% user choose.
2800%
2801% o display: Specifies a connection to an X server; returned from
2802% XOpenDisplay.
2803%
2804% o window: Specifies a pointer to a XWindows structure.
2805%
2806% o selections: Specifies a pointer to one or more strings that comprise
2807% the choices in the menu.
2808%
2809% o event: Specifies a pointer to a X11 XEvent structure.
2810%
2811*/
cristybcbda3f2011-09-03 13:01:22 +00002812MagickPrivate int XCommandWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00002813 const char **selections,XEvent *event)
2814{
2815#define tile_width 112
2816#define tile_height 70
2817
2818 static const unsigned char
2819 tile_bits[]=
2820 {
2821 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2822 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2823 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
2825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
2827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2828 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2829 0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2830 0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
2831 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
2832 0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
2833 0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
2834 0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
2835 0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
2836 0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
2837 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
2838 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
2839 0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
2840 0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
2841 0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
2842 0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
2843 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
2844 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
2845 0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
2846 0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
2847 0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
2848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
2849 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
2851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
2852 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2853 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2854 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2855 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
2856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
2857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
2858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
2859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2860 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
2861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
2862 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2863 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2864 0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2865 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
2866 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
2867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
2868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
2869 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
2870 0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
2871 0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
2872 0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
2873 0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
2874 0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
2875 0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
2876 0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
2877 0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
2878 0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
2879 0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
2880 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
2881 0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
2882 0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
2883 0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
2884 0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
2885 0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
2886 0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
2887 0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
2888 0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
2889 0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
2890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
2891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
2892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
2893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
2894 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2895 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2896 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2897 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2898 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
2899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
2900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
2901 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2902 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2903 };
2904
2905 int
2906 id,
2907 y;
2908
2909 register int
2910 i;
2911
2912 static unsigned int
2913 number_selections;
2914
2915 unsigned int
2916 height;
2917
cristybb503372010-05-27 20:51:26 +00002918 size_t
cristy3ed852e2009-09-05 21:47:34 +00002919 state;
2920
2921 XFontStruct
2922 *font_info;
2923
2924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2925 assert(display != (Display *) NULL);
2926 assert(windows != (XWindows *) NULL);
2927 font_info=windows->command.font_info;
2928 height=(unsigned int) (font_info->ascent+font_info->descent);
2929 id=(~0);
2930 state=DefaultState;
2931 if (event == (XEvent *) NULL)
2932 {
2933 unsigned int
2934 width;
2935
2936 XTextProperty
2937 window_name;
2938
2939 XWindowChanges
2940 window_changes;
2941
2942 /*
2943 Determine command window attributes.
2944 */
2945 assert(selections != (const char **) NULL);
2946 windows->command.width=0;
2947 for (i=0; selections[i] != (char *) NULL; i++)
2948 {
2949 width=WidgetTextWidth(font_info,(char *) selections[i]);
2950 if (width > windows->command.width)
2951 windows->command.width=width;
2952 }
2953 number_selections=(unsigned int) i;
2954 windows->command.width+=3*QuantumMargin+10;
2955 if ((int) windows->command.width < (tile_width+QuantumMargin+10))
2956 windows->command.width=(unsigned int) (tile_width+QuantumMargin+10);
2957 windows->command.height=(unsigned int) (number_selections*
2958 (((3*height) >> 1)+10)+tile_height+20);
2959 windows->command.min_width=windows->command.width;
2960 windows->command.min_height=windows->command.height;
2961 XConstrainWindowPosition(display,&windows->command);
2962 if (windows->command.id != (Window) NULL)
2963 {
2964 Status
2965 status;
2966
2967 /*
2968 Reconfigure command window.
2969 */
2970 status=XStringListToTextProperty(&windows->command.name,1,
2971 &window_name);
2972 if (status != False)
2973 {
2974 XSetWMName(display,windows->command.id,&window_name);
2975 XSetWMIconName(display,windows->command.id,&window_name);
2976 (void) XFree((void *) window_name.value);
2977 }
2978 window_changes.width=(int) windows->command.width;
2979 window_changes.height=(int) windows->command.height;
2980 (void) XReconfigureWMWindow(display,windows->command.id,
2981 windows->command.screen,(unsigned int) (CWWidth | CWHeight),
2982 &window_changes);
2983 }
2984 /*
2985 Allocate selection info memory.
2986 */
2987 if (selection_info != (XWidgetInfo *) NULL)
2988 selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
2989 selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
2990 sizeof(*selection_info));
2991 if (selection_info == (XWidgetInfo *) NULL)
2992 {
2993 ThrowXWindowFatalException(ResourceLimitError,
2994 "MemoryAllocationFailed","...");
2995 return(id);
2996 }
2997 state|=UpdateConfigurationState | RedrawWidgetState;
2998 }
2999 /*
3000 Wait for next event.
3001 */
3002 if (event != (XEvent *) NULL)
3003 switch (event->type)
3004 {
3005 case ButtonPress:
3006 {
3007 for (i=0; i < (int) number_selections; i++)
3008 {
3009 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3010 continue;
3011 if (i >= (int) windows->command.data)
3012 {
3013 selection_info[i].raised=MagickFalse;
3014 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3015 break;
3016 }
3017 submenu_info=selection_info[i];
3018 submenu_info.active=MagickTrue;
3019 toggle_info.y=
3020 submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
3021 id=i;
3022 (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
3023 event);
3024 break;
3025 }
3026 break;
3027 }
3028 case ButtonRelease:
3029 {
3030 for (i=0; i < (int) number_selections; i++)
3031 {
3032 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3033 continue;
3034 id=i;
3035 if (id >= (int) windows->command.data)
3036 {
3037 selection_info[id].raised=MagickTrue;
3038 XDrawBeveledButton(display,&windows->command,&selection_info[id]);
3039 break;
3040 }
3041 break;
3042 }
3043 break;
3044 }
3045 case ClientMessage:
3046 {
3047 /*
3048 If client window delete message, withdraw command widget.
3049 */
3050 if (event->xclient.message_type != windows->wm_protocols)
3051 break;
3052 if (*event->xclient.data.l != (int) windows->wm_delete_window)
3053 break;
3054 (void) XWithdrawWindow(display,windows->command.id,
3055 windows->command.screen);
3056 break;
3057 }
3058 case ConfigureNotify:
3059 {
3060 /*
3061 Update widget configuration.
3062 */
3063 if (event->xconfigure.window != windows->command.id)
3064 break;
3065 if (event->xconfigure.send_event != 0)
3066 {
3067 windows->command.x=event->xconfigure.x;
3068 windows->command.y=event->xconfigure.y;
3069 }
3070 if ((event->xconfigure.width == (int) windows->command.width) &&
3071 (event->xconfigure.height == (int) windows->command.height))
3072 break;
3073 windows->command.width=(unsigned int)
3074 MagickMax(event->xconfigure.width,(int) windows->command.min_width);
3075 windows->command.height=(unsigned int)
3076 MagickMax(event->xconfigure.height,(int) windows->command.min_height);
3077 state|=UpdateConfigurationState;
3078 break;
3079 }
3080 case Expose:
3081 {
3082 if (event->xexpose.window != windows->command.id)
3083 break;
3084 if (event->xexpose.count != 0)
3085 break;
3086 state|=RedrawWidgetState;
3087 break;
3088 }
3089 case MotionNotify:
3090 {
3091 /*
3092 Return the ID of the highlighted menu entry.
3093 */
3094 for ( ; ; )
3095 {
3096 for (i=0; i < (int) number_selections; i++)
3097 {
3098 if (i >= (int) windows->command.data)
3099 {
3100 if (selection_info[i].raised ==
3101 MatteIsActive(selection_info[i],event->xmotion))
3102 {
3103 /*
3104 Button status changed.
3105 */
3106 selection_info[i].raised=!selection_info[i].raised;
3107 XDrawBeveledButton(display,&windows->command,
3108 &selection_info[i]);
3109 }
3110 continue;
3111 }
3112 if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
3113 continue;
3114 submenu_info=selection_info[i];
3115 submenu_info.active=MagickTrue;
3116 toggle_info.raised=MagickTrue;
3117 toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
3118 (toggle_info.height >> 1);
3119 XDrawTriangleEast(display,&windows->command,&toggle_info);
3120 id=i;
3121 }
3122 XDelay(display,SuspendTime);
3123 if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
3124 break;
3125 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
3126 toggle_info.raised=MagickFalse;
3127 if (windows->command.data != 0)
3128 XDrawTriangleEast(display,&windows->command,&toggle_info);
3129 }
3130 break;
3131 }
3132 case MapNotify:
3133 {
3134 windows->command.mapped=MagickTrue;
3135 break;
3136 }
3137 case UnmapNotify:
3138 {
3139 windows->command.mapped=MagickFalse;
3140 break;
3141 }
3142 default:
3143 break;
3144 }
3145 if (state & UpdateConfigurationState)
3146 {
3147 /*
3148 Initialize button information.
3149 */
3150 assert(selections != (const char **) NULL);
3151 y=tile_height+20;
3152 for (i=0; i < (int) number_selections; i++)
3153 {
3154 XGetWidgetInfo(selections[i],&selection_info[i]);
3155 selection_info[i].center=MagickFalse;
3156 selection_info[i].bevel_width--;
3157 selection_info[i].height=(unsigned int) ((3*height) >> 1);
3158 selection_info[i].x=(QuantumMargin >> 1)+4;
3159 selection_info[i].width=(unsigned int)
3160 (windows->command.width-(selection_info[i].x << 1));
3161 selection_info[i].y=y;
3162 y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
3163 }
3164 XGetWidgetInfo((char *) NULL,&toggle_info);
3165 toggle_info.bevel_width--;
3166 toggle_info.width=(unsigned int)
3167 (((5*height) >> 3)-(toggle_info.bevel_width << 1));
3168 toggle_info.height=toggle_info.width;
3169 toggle_info.x=selection_info[0].x+selection_info[0].width-
3170 toggle_info.width-(QuantumMargin >> 1);
3171 if (windows->command.mapped)
3172 (void) XClearWindow(display,windows->command.id);
3173 }
3174 if (state & RedrawWidgetState)
3175 {
3176 Pixmap
3177 tile_pixmap;
3178
3179 /*
3180 Draw command buttons.
3181 */
3182 tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
3183 (char *) tile_bits,tile_width,tile_height,1L,0L,1);
3184 if (tile_pixmap != (Pixmap) NULL)
3185 {
3186 (void) XCopyPlane(display,tile_pixmap,windows->command.id,
3187 windows->command.annotate_context,0,0,tile_width,tile_height,
3188 (int) ((windows->command.width-tile_width) >> 1),10,1L);
3189 (void) XFreePixmap(display,tile_pixmap);
3190 }
3191 for (i=0; i < (int) number_selections; i++)
3192 {
3193 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3194 if (i >= (int) windows->command.data)
3195 continue;
3196 toggle_info.raised=i == id ? MagickTrue : MagickFalse;
3197 toggle_info.y=selection_info[i].y+
3198 (selection_info[i].height >> 1)-(toggle_info.height >> 1);
3199 XDrawTriangleEast(display,&windows->command,&toggle_info);
3200 }
3201 XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
3202 }
3203 return(id);
3204}
3205
3206/*
3207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3208% %
3209% %
3210% %
3211% X C o n f i r m W i d g e t %
3212% %
3213% %
3214% %
3215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3216%
3217% XConfirmWidget() displays a Confirm widget with a notice to the user. The
3218% function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
3219%
3220% The format of the XConfirmWidget method is:
3221%
3222% int XConfirmWidget(Display *display,XWindows *windows,
3223% const char *reason,const char *description)
3224%
3225% A description of each parameter follows:
3226%
3227% o display: Specifies a connection to an X server; returned from
3228% XOpenDisplay.
3229%
3230% o window: Specifies a pointer to a XWindows structure.
3231%
3232% o reason: Specifies the message to display before terminating the
3233% program.
3234%
3235% o description: Specifies any description to the message.
3236%
3237*/
cristybcbda3f2011-09-03 13:01:22 +00003238MagickPrivate int XConfirmWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00003239 const char *reason,const char *description)
3240{
3241#define CancelButtonText "Cancel"
3242#define DismissButtonText "Dismiss"
3243#define YesButtonText "Yes"
3244
3245 int
3246 confirm,
3247 x,
3248 y;
3249
3250 Status
3251 status;
3252
3253 unsigned int
3254 height,
3255 width;
3256
cristybb503372010-05-27 20:51:26 +00003257 size_t
cristy3ed852e2009-09-05 21:47:34 +00003258 state;
3259
3260 XEvent
3261 event;
3262
3263 XFontStruct
3264 *font_info;
3265
3266 XTextProperty
3267 window_name;
3268
3269 XWidgetInfo
3270 cancel_info,
3271 dismiss_info,
3272 yes_info;
3273
3274 XWindowChanges
3275 window_changes;
3276
3277 /*
3278 Determine Confirm widget attributes.
3279 */
3280 assert(display != (Display *) NULL);
3281 assert(windows != (XWindows *) NULL);
3282 assert(reason != (char *) NULL);
3283 assert(description != (char *) NULL);
3284 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
3285 XCheckRefreshWindows(display,windows);
3286 font_info=windows->widget.font_info;
3287 width=WidgetTextWidth(font_info,CancelButtonText);
3288 if (WidgetTextWidth(font_info,DismissButtonText) > width)
3289 width=WidgetTextWidth(font_info,DismissButtonText);
3290 if (WidgetTextWidth(font_info,YesButtonText) > width)
3291 width=WidgetTextWidth(font_info,YesButtonText);
3292 width<<=1;
3293 if (description != (char *) NULL)
3294 if (WidgetTextWidth(font_info,(char *) description) > width)
3295 width=WidgetTextWidth(font_info,(char *) description);
3296 height=(unsigned int) (font_info->ascent+font_info->descent);
3297 /*
3298 Position Confirm widget.
3299 */
3300 windows->widget.width=(unsigned int) (width+9*QuantumMargin);
3301 windows->widget.min_width=(unsigned int) (9*QuantumMargin+
3302 WidgetTextWidth(font_info,CancelButtonText)+
3303 WidgetTextWidth(font_info,DismissButtonText)+
3304 WidgetTextWidth(font_info,YesButtonText));
3305 if (windows->widget.width < windows->widget.min_width)
3306 windows->widget.width=windows->widget.min_width;
3307 windows->widget.height=(unsigned int) (12*height);
3308 windows->widget.min_height=(unsigned int) (7*height);
3309 if (windows->widget.height < windows->widget.min_height)
3310 windows->widget.height=windows->widget.min_height;
3311 XConstrainWindowPosition(display,&windows->widget);
3312 /*
3313 Map Confirm widget.
3314 */
3315 (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
3316 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3317 if (status != False)
3318 {
3319 XSetWMName(display,windows->widget.id,&window_name);
3320 XSetWMIconName(display,windows->widget.id,&window_name);
3321 (void) XFree((void *) window_name.value);
3322 }
3323 window_changes.width=(int) windows->widget.width;
3324 window_changes.height=(int) windows->widget.height;
3325 window_changes.x=windows->widget.x;
3326 window_changes.y=windows->widget.y;
3327 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3328 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3329 (void) XMapRaised(display,windows->widget.id);
3330 windows->widget.mapped=MagickFalse;
3331 /*
3332 Respond to X events.
3333 */
3334 confirm=0;
3335 state=UpdateConfigurationState;
3336 XSetCursorState(display,windows,MagickTrue);
3337 do
3338 {
3339 if (state & UpdateConfigurationState)
3340 {
3341 /*
3342 Initialize button information.
3343 */
3344 XGetWidgetInfo(CancelButtonText,&cancel_info);
3345 cancel_info.width=(unsigned int) QuantumMargin+
3346 WidgetTextWidth(font_info,CancelButtonText);
3347 cancel_info.height=(unsigned int) ((3*height) >> 1);
3348 cancel_info.x=(int) (windows->widget.width-cancel_info.width-
3349 QuantumMargin);
3350 cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
3351 dismiss_info=cancel_info;
3352 dismiss_info.text=(char *) DismissButtonText;
3353 if (LocaleCompare(description,"Do you want to save it") == 0)
3354 dismiss_info.text=(char *) "Don't Save";
3355 dismiss_info.width=(unsigned int) QuantumMargin+
3356 WidgetTextWidth(font_info,dismiss_info.text);
3357 dismiss_info.x=(int)
3358 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
3359 yes_info=cancel_info;
3360 yes_info.text=(char *) YesButtonText;
3361 if (LocaleCompare(description,"Do you want to save it") == 0)
3362 yes_info.text=(char *) "Save";
3363 yes_info.width=(unsigned int) QuantumMargin+
3364 WidgetTextWidth(font_info,yes_info.text);
3365 if (yes_info.width < cancel_info.width)
3366 yes_info.width=cancel_info.width;
3367 yes_info.x=QuantumMargin;
3368 state&=(~UpdateConfigurationState);
3369 }
3370 if (state & RedrawWidgetState)
3371 {
3372 /*
3373 Redraw Confirm widget.
3374 */
3375 width=WidgetTextWidth(font_info,(char *) reason);
3376 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3377 y=(int) ((windows->widget.height >> 1)-(height << 1));
3378 (void) XDrawString(display,windows->widget.id,
3379 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
3380 if (description != (char *) NULL)
3381 {
3382 char
3383 question[MaxTextExtent];
3384
3385 (void) CopyMagickString(question,description,MaxTextExtent);
3386 (void) ConcatenateMagickString(question,"?",MaxTextExtent);
3387 width=WidgetTextWidth(font_info,question);
3388 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3389 y+=height;
3390 (void) XDrawString(display,windows->widget.id,
3391 windows->widget.annotate_context,x,y,question,Extent(question));
3392 }
3393 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3394 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3395 XDrawBeveledButton(display,&windows->widget,&yes_info);
3396 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3397 state&=(~RedrawWidgetState);
3398 }
3399 /*
3400 Wait for next event.
3401 */
3402 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3403 switch (event.type)
3404 {
3405 case ButtonPress:
3406 {
3407 if (MatteIsActive(cancel_info,event.xbutton))
3408 {
3409 /*
3410 User pressed No button.
3411 */
3412 cancel_info.raised=MagickFalse;
3413 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3414 break;
3415 }
3416 if (MatteIsActive(dismiss_info,event.xbutton))
3417 {
3418 /*
3419 User pressed Dismiss button.
3420 */
3421 dismiss_info.raised=MagickFalse;
3422 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3423 break;
3424 }
3425 if (MatteIsActive(yes_info,event.xbutton))
3426 {
3427 /*
3428 User pressed Yes button.
3429 */
3430 yes_info.raised=MagickFalse;
3431 XDrawBeveledButton(display,&windows->widget,&yes_info);
3432 break;
3433 }
3434 break;
3435 }
3436 case ButtonRelease:
3437 {
3438 if (windows->widget.mapped == MagickFalse)
3439 break;
3440 if (cancel_info.raised == MagickFalse)
3441 {
3442 if (event.xbutton.window == windows->widget.id)
3443 if (MatteIsActive(cancel_info,event.xbutton))
3444 {
3445 confirm=0;
3446 state|=ExitState;
3447 }
3448 cancel_info.raised=MagickTrue;
3449 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3450 }
3451 if (dismiss_info.raised == MagickFalse)
3452 {
3453 if (event.xbutton.window == windows->widget.id)
3454 if (MatteIsActive(dismiss_info,event.xbutton))
3455 {
3456 confirm=(-1);
3457 state|=ExitState;
3458 }
3459 dismiss_info.raised=MagickTrue;
3460 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3461 }
3462 if (yes_info.raised == MagickFalse)
3463 {
3464 if (event.xbutton.window == windows->widget.id)
3465 if (MatteIsActive(yes_info,event.xbutton))
3466 {
3467 confirm=1;
3468 state|=ExitState;
3469 }
3470 yes_info.raised=MagickTrue;
3471 XDrawBeveledButton(display,&windows->widget,&yes_info);
3472 }
3473 break;
3474 }
3475 case ClientMessage:
3476 {
3477 /*
3478 If client window delete message, exit.
3479 */
3480 if (event.xclient.message_type != windows->wm_protocols)
3481 break;
3482 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3483 {
3484 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3485 (Time) event.xclient.data.l[1]);
3486 break;
3487 }
3488 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3489 break;
3490 if (event.xclient.window == windows->widget.id)
3491 {
3492 state|=ExitState;
3493 break;
3494 }
3495 break;
3496 }
3497 case ConfigureNotify:
3498 {
3499 /*
3500 Update widget configuration.
3501 */
3502 if (event.xconfigure.window != windows->widget.id)
3503 break;
3504 if ((event.xconfigure.width == (int) windows->widget.width) &&
3505 (event.xconfigure.height == (int) windows->widget.height))
3506 break;
3507 windows->widget.width=(unsigned int)
3508 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3509 windows->widget.height=(unsigned int)
3510 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3511 state|=UpdateConfigurationState;
3512 break;
3513 }
3514 case EnterNotify:
3515 {
3516 if (event.xcrossing.window != windows->widget.id)
3517 break;
3518 state&=(~InactiveWidgetState);
3519 break;
3520 }
3521 case Expose:
3522 {
3523 if (event.xexpose.window != windows->widget.id)
3524 break;
3525 if (event.xexpose.count != 0)
3526 break;
3527 state|=RedrawWidgetState;
3528 break;
3529 }
3530 case KeyPress:
3531 {
3532 static char
3533 command[MaxTextExtent];
3534
3535 static KeySym
3536 key_symbol;
3537
3538 /*
3539 Respond to a user key press.
3540 */
3541 if (event.xkey.window != windows->widget.id)
3542 break;
3543 (void) XLookupString((XKeyEvent *) &event.xkey,command,
3544 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3545 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
3546 {
3547 yes_info.raised=MagickFalse;
3548 XDrawBeveledButton(display,&windows->widget,&yes_info);
3549 confirm=1;
3550 state|=ExitState;
3551 break;
3552 }
3553 break;
3554 }
3555 case LeaveNotify:
3556 {
3557 if (event.xcrossing.window != windows->widget.id)
3558 break;
3559 state|=InactiveWidgetState;
3560 break;
3561 }
3562 case MotionNotify:
3563 {
3564 /*
3565 Discard pending button motion events.
3566 */
3567 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
3568 if (state & InactiveWidgetState)
3569 break;
3570 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
3571 {
3572 /*
3573 Cancel button status changed.
3574 */
3575 cancel_info.raised=cancel_info.raised == MagickFalse ?
3576 MagickTrue : MagickFalse;
3577 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3578 break;
3579 }
3580 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
3581 {
3582 /*
3583 Dismiss button status changed.
3584 */
3585 dismiss_info.raised=cancel_info.raised == MagickFalse ?
3586 MagickTrue : MagickFalse;
3587 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3588 break;
3589 }
3590 if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
3591 {
3592 /*
3593 Yes button status changed.
3594 */
3595 yes_info.raised=yes_info.raised == MagickFalse ?
3596 MagickTrue : MagickFalse;
3597 XDrawBeveledButton(display,&windows->widget,&yes_info);
3598 break;
3599 }
3600 break;
3601 }
3602 default:
3603 break;
3604 }
3605 } while ((state & ExitState) == 0);
3606 XSetCursorState(display,windows,MagickFalse);
3607 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
3608 XCheckRefreshWindows(display,windows);
3609 return(confirm);
3610}
3611
3612/*
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614% %
3615% %
3616% %
3617% X D i a l o g W i d g e t %
3618% %
3619% %
3620% %
3621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3622%
3623% XDialogWidget() displays a Dialog widget with a query to the user. The user
3624% keys a reply and presses the Ok or Cancel button to exit. The typed text is
3625% returned as the reply function parameter.
3626%
3627% The format of the XDialogWidget method is:
3628%
3629% int XDialogWidget(Display *display,XWindows *windows,const char *action,
3630% const char *query,char *reply)
3631%
3632% A description of each parameter follows:
3633%
3634% o display: Specifies a connection to an X server; returned from
3635% XOpenDisplay.
3636%
3637% o window: Specifies a pointer to a XWindows structure.
3638%
3639% o action: Specifies a pointer to the action of this widget.
3640%
3641% o query: Specifies a pointer to the query to present to the user.
3642%
3643% o reply: the response from the user is returned in this parameter.
3644%
3645*/
cristybcbda3f2011-09-03 13:01:22 +00003646MagickPrivate int XDialogWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00003647 const char *action,const char *query,char *reply)
3648{
3649#define CancelButtonText "Cancel"
3650
3651 char
3652 primary_selection[MaxTextExtent];
3653
3654 int
3655 x;
3656
3657 register int
3658 i;
3659
3660 static MagickBooleanType
3661 raised = MagickFalse;
3662
3663 Status
3664 status;
3665
3666 unsigned int
3667 anomaly,
3668 height,
3669 width;
3670
cristybb503372010-05-27 20:51:26 +00003671 size_t
cristy3ed852e2009-09-05 21:47:34 +00003672 state;
3673
3674 XEvent
3675 event;
3676
3677 XFontStruct
3678 *font_info;
3679
3680 XTextProperty
3681 window_name;
3682
3683 XWidgetInfo
3684 action_info,
3685 cancel_info,
3686 reply_info,
3687 special_info,
3688 text_info;
3689
3690 XWindowChanges
3691 window_changes;
3692
3693 /*
3694 Determine Dialog widget attributes.
3695 */
3696 assert(display != (Display *) NULL);
3697 assert(windows != (XWindows *) NULL);
3698 assert(action != (char *) NULL);
3699 assert(query != (char *) NULL);
3700 assert(reply != (char *) NULL);
3701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
3702 XCheckRefreshWindows(display,windows);
3703 font_info=windows->widget.font_info;
3704 width=WidgetTextWidth(font_info,(char *) action);
3705 if (WidgetTextWidth(font_info,CancelButtonText) > width)
3706 width=WidgetTextWidth(font_info,CancelButtonText);
3707 width+=(3*QuantumMargin) >> 1;
3708 height=(unsigned int) (font_info->ascent+font_info->descent);
3709 /*
3710 Position Dialog widget.
3711 */
cristy49e2d862010-11-12 02:50:30 +00003712 windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int)
3713 WidgetTextWidth(font_info,(char *) query));
cristy3ed852e2009-09-05 21:47:34 +00003714 if (windows->widget.width < WidgetTextWidth(font_info,reply))
3715 windows->widget.width=WidgetTextWidth(font_info,reply);
3716 windows->widget.width+=6*QuantumMargin;
3717 windows->widget.min_width=(unsigned int)
3718 (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
3719 if (windows->widget.width < windows->widget.min_width)
3720 windows->widget.width=windows->widget.min_width;
3721 windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
3722 windows->widget.min_height=windows->widget.height;
3723 if (windows->widget.height < windows->widget.min_height)
3724 windows->widget.height=windows->widget.min_height;
3725 XConstrainWindowPosition(display,&windows->widget);
3726 /*
3727 Map Dialog widget.
3728 */
3729 (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
3730 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3731 if (status != False)
3732 {
3733 XSetWMName(display,windows->widget.id,&window_name);
3734 XSetWMIconName(display,windows->widget.id,&window_name);
3735 (void) XFree((void *) window_name.value);
3736 }
3737 window_changes.width=(int) windows->widget.width;
3738 window_changes.height=(int) windows->widget.height;
3739 window_changes.x=windows->widget.x;
3740 window_changes.y=windows->widget.y;
3741 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3742 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3743 (void) XMapRaised(display,windows->widget.id);
3744 windows->widget.mapped=MagickFalse;
3745 /*
3746 Respond to X events.
3747 */
3748 anomaly=(LocaleCompare(action,"Background") == 0) ||
3749 (LocaleCompare(action,"New") == 0) ||
3750 (LocaleCompare(action,"Quantize") == 0) ||
3751 (LocaleCompare(action,"Resize") == 0) ||
3752 (LocaleCompare(action,"Save") == 0) ||
3753 (LocaleCompare(action,"Shade") == 0);
3754 state=UpdateConfigurationState;
3755 XSetCursorState(display,windows,MagickTrue);
3756 do
3757 {
3758 if (state & UpdateConfigurationState)
3759 {
3760 /*
3761 Initialize button information.
3762 */
3763 XGetWidgetInfo(CancelButtonText,&cancel_info);
3764 cancel_info.width=width;
3765 cancel_info.height=(unsigned int) ((3*height) >> 1);
3766 cancel_info.x=(int)
3767 (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
3768 cancel_info.y=(int)
3769 (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
3770 XGetWidgetInfo(action,&action_info);
3771 action_info.width=width;
3772 action_info.height=(unsigned int) ((3*height) >> 1);
3773 action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
3774 (action_info.bevel_width << 1));
3775 action_info.y=cancel_info.y;
3776 /*
3777 Initialize reply information.
3778 */
3779 XGetWidgetInfo(reply,&reply_info);
3780 reply_info.raised=MagickFalse;
3781 reply_info.bevel_width--;
3782 reply_info.width=windows->widget.width-(3*QuantumMargin);
3783 reply_info.height=height << 1;
3784 reply_info.x=(3*QuantumMargin) >> 1;
3785 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
3786 /*
3787 Initialize option information.
3788 */
3789 XGetWidgetInfo("Dither",&special_info);
3790 special_info.raised=raised;
3791 special_info.bevel_width--;
3792 special_info.width=(unsigned int) QuantumMargin >> 1;
3793 special_info.height=(unsigned int) QuantumMargin >> 1;
3794 special_info.x=reply_info.x;
3795 special_info.y=action_info.y+action_info.height-special_info.height;
3796 if (LocaleCompare(action,"Background") == 0)
3797 special_info.text=(char *) "Backdrop";
3798 if (LocaleCompare(action,"New") == 0)
3799 special_info.text=(char *) "Gradation";
3800 if (LocaleCompare(action,"Resize") == 0)
3801 special_info.text=(char *) "Constrain ratio";
3802 if (LocaleCompare(action,"Save") == 0)
3803 special_info.text=(char *) "Non-progressive";
3804 if (LocaleCompare(action,"Shade") == 0)
3805 special_info.text=(char *) "Color shading";
3806 /*
3807 Initialize text information.
3808 */
3809 XGetWidgetInfo(query,&text_info);
3810 text_info.width=reply_info.width;
3811 text_info.height=height;
3812 text_info.x=reply_info.x-(QuantumMargin >> 1);
3813 text_info.y=QuantumMargin;
3814 text_info.center=MagickFalse;
3815 state&=(~UpdateConfigurationState);
3816 }
3817 if (state & RedrawWidgetState)
3818 {
3819 /*
3820 Redraw Dialog widget.
3821 */
3822 XDrawWidgetText(display,&windows->widget,&text_info);
3823 XDrawBeveledMatte(display,&windows->widget,&reply_info);
3824 XDrawMatteText(display,&windows->widget,&reply_info);
3825 if (anomaly)
3826 XDrawBeveledButton(display,&windows->widget,&special_info);
3827 XDrawBeveledButton(display,&windows->widget,&action_info);
3828 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3829 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3830 state&=(~RedrawWidgetState);
3831 }
3832 /*
3833 Wait for next event.
3834 */
3835 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3836 switch (event.type)
3837 {
3838 case ButtonPress:
3839 {
3840 if (anomaly)
3841 if (MatteIsActive(special_info,event.xbutton))
3842 {
3843 /*
3844 Option button status changed.
3845 */
3846 special_info.raised=!special_info.raised;
3847 XDrawBeveledButton(display,&windows->widget,&special_info);
3848 break;
3849 }
3850 if (MatteIsActive(action_info,event.xbutton))
3851 {
3852 /*
3853 User pressed Action button.
3854 */
3855 action_info.raised=MagickFalse;
3856 XDrawBeveledButton(display,&windows->widget,&action_info);
3857 break;
3858 }
3859 if (MatteIsActive(cancel_info,event.xbutton))
3860 {
3861 /*
3862 User pressed Cancel button.
3863 */
3864 cancel_info.raised=MagickFalse;
3865 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3866 break;
3867 }
3868 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
3869 break;
3870 if (event.xbutton.button != Button2)
3871 {
3872 static Time
3873 click_time;
3874
3875 /*
3876 Move text cursor to position of button press.
3877 */
3878 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
3879 for (i=1; i <= Extent(reply_info.marker); i++)
3880 if (XTextWidth(font_info,reply_info.marker,i) > x)
3881 break;
3882 reply_info.cursor=reply_info.marker+i-1;
3883 if (event.xbutton.time > (click_time+DoubleClick))
3884 reply_info.highlight=MagickFalse;
3885 else
3886 {
3887 /*
3888 Become the XA_PRIMARY selection owner.
3889 */
3890 (void) CopyMagickString(primary_selection,reply_info.text,
3891 MaxTextExtent);
3892 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
3893 event.xbutton.time);
3894 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
3895 windows->widget.id ? MagickTrue : MagickFalse;
3896 }
3897 XDrawMatteText(display,&windows->widget,&reply_info);
3898 click_time=event.xbutton.time;
3899 break;
3900 }
3901 /*
3902 Request primary selection.
3903 */
3904 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
3905 windows->widget.id,event.xbutton.time);
3906 break;
3907 }
3908 case ButtonRelease:
3909 {
3910 if (windows->widget.mapped == MagickFalse)
3911 break;
3912 if (action_info.raised == MagickFalse)
3913 {
3914 if (event.xbutton.window == windows->widget.id)
3915 if (MatteIsActive(action_info,event.xbutton))
3916 state|=ExitState;
3917 action_info.raised=MagickTrue;
3918 XDrawBeveledButton(display,&windows->widget,&action_info);
3919 }
3920 if (cancel_info.raised == MagickFalse)
3921 {
3922 if (event.xbutton.window == windows->widget.id)
3923 if (MatteIsActive(cancel_info,event.xbutton))
3924 {
3925 *reply_info.text='\0';
3926 state|=ExitState;
3927 }
3928 cancel_info.raised=MagickTrue;
3929 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3930 }
3931 break;
3932 }
3933 case ClientMessage:
3934 {
3935 /*
3936 If client window delete message, exit.
3937 */
3938 if (event.xclient.message_type != windows->wm_protocols)
3939 break;
3940 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3941 {
3942 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3943 (Time) event.xclient.data.l[1]);
3944 break;
3945 }
3946 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3947 break;
3948 if (event.xclient.window == windows->widget.id)
3949 {
3950 *reply_info.text='\0';
3951 state|=ExitState;
3952 break;
3953 }
3954 break;
3955 }
3956 case ConfigureNotify:
3957 {
3958 /*
3959 Update widget configuration.
3960 */
3961 if (event.xconfigure.window != windows->widget.id)
3962 break;
3963 if ((event.xconfigure.width == (int) windows->widget.width) &&
3964 (event.xconfigure.height == (int) windows->widget.height))
3965 break;
3966 windows->widget.width=(unsigned int)
3967 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3968 windows->widget.height=(unsigned int)
3969 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3970 state|=UpdateConfigurationState;
3971 break;
3972 }
3973 case EnterNotify:
3974 {
3975 if (event.xcrossing.window != windows->widget.id)
3976 break;
3977 state&=(~InactiveWidgetState);
3978 break;
3979 }
3980 case Expose:
3981 {
3982 if (event.xexpose.window != windows->widget.id)
3983 break;
3984 if (event.xexpose.count != 0)
3985 break;
3986 state|=RedrawWidgetState;
3987 break;
3988 }
3989 case KeyPress:
3990 {
3991 static char
3992 command[MaxTextExtent];
3993
3994 static int
3995 length;
3996
3997 static KeySym
3998 key_symbol;
3999
4000 /*
4001 Respond to a user key press.
4002 */
4003 if (event.xkey.window != windows->widget.id)
4004 break;
4005 length=XLookupString((XKeyEvent *) &event.xkey,command,
4006 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4007 *(command+length)='\0';
4008 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
4009 {
4010 action_info.raised=MagickFalse;
4011 XDrawBeveledButton(display,&windows->widget,&action_info);
4012 state|=ExitState;
4013 break;
4014 }
4015 if (key_symbol == XK_Control_L)
4016 {
4017 state|=ControlState;
4018 break;
4019 }
4020 if (state & ControlState)
4021 switch ((int) key_symbol)
4022 {
4023 case XK_u:
4024 case XK_U:
4025 {
4026 /*
4027 Erase the entire line of text.
4028 */
4029 *reply_info.text='\0';
4030 reply_info.cursor=reply_info.text;
4031 reply_info.marker=reply_info.text;
4032 reply_info.highlight=MagickFalse;
4033 break;
4034 }
4035 default:
4036 break;
4037 }
4038 XEditText(display,&reply_info,key_symbol,command,state);
4039 XDrawMatteText(display,&windows->widget,&reply_info);
4040 break;
4041 }
4042 case KeyRelease:
4043 {
4044 static char
4045 command[MaxTextExtent];
4046
4047 static KeySym
4048 key_symbol;
4049
4050 /*
4051 Respond to a user key release.
4052 */
4053 if (event.xkey.window != windows->widget.id)
4054 break;
4055 (void) XLookupString((XKeyEvent *) &event.xkey,command,
4056 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4057 if (key_symbol == XK_Control_L)
4058 state&=(~ControlState);
4059 break;
4060 }
4061 case LeaveNotify:
4062 {
4063 if (event.xcrossing.window != windows->widget.id)
4064 break;
4065 state|=InactiveWidgetState;
4066 break;
4067 }
4068 case MotionNotify:
4069 {
4070 /*
4071 Discard pending button motion events.
4072 */
4073 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
4074 if (state & InactiveWidgetState)
4075 break;
4076 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
4077 {
4078 /*
4079 Action button status changed.
4080 */
4081 action_info.raised=action_info.raised == MagickFalse ?
4082 MagickTrue : MagickFalse;
4083 XDrawBeveledButton(display,&windows->widget,&action_info);
4084 break;
4085 }
4086 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
4087 {
4088 /*
4089 Cancel button status changed.
4090 */
4091 cancel_info.raised=cancel_info.raised == MagickFalse ?
4092 MagickTrue : MagickFalse;
4093 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4094 break;
4095 }
4096 break;
4097 }
4098 case SelectionClear:
4099 {
4100 reply_info.highlight=MagickFalse;
4101 XDrawMatteText(display,&windows->widget,&reply_info);
4102 break;
4103 }
4104 case SelectionNotify:
4105 {
4106 Atom
4107 type;
4108
4109 int
4110 format;
4111
4112 unsigned char
4113 *data;
4114
cristyf2faecf2010-05-28 19:19:36 +00004115 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00004116 after,
4117 length;
4118
4119 /*
4120 Obtain response from primary selection.
4121 */
4122 if (event.xselection.property == (Atom) None)
4123 break;
4124 status=XGetWindowProperty(display,event.xselection.requestor,
4125 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
4126 &format,&length,&after,&data);
4127 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
4128 (length == 0))
4129 break;
cristy37e0b382011-06-07 13:31:21 +00004130 if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +00004131 (void) XBell(display,0);
4132 else
4133 {
4134 /*
4135 Insert primary selection in reply text.
4136 */
4137 *(data+length)='\0';
4138 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
4139 state);
4140 XDrawMatteText(display,&windows->widget,&reply_info);
4141 }
4142 (void) XFree((void *) data);
4143 break;
4144 }
4145 case SelectionRequest:
4146 {
4147 XSelectionEvent
4148 notify;
4149
4150 XSelectionRequestEvent
4151 *request;
4152
4153 if (reply_info.highlight == MagickFalse)
4154 break;
4155 /*
4156 Set primary selection.
4157 */
4158 request=(&(event.xselectionrequest));
4159 (void) XChangeProperty(request->display,request->requestor,
4160 request->property,request->target,8,PropModeReplace,
4161 (unsigned char *) primary_selection,Extent(primary_selection));
4162 notify.type=SelectionNotify;
4163 notify.display=request->display;
4164 notify.requestor=request->requestor;
4165 notify.selection=request->selection;
4166 notify.target=request->target;
4167 notify.time=request->time;
4168 if (request->property == None)
4169 notify.property=request->target;
4170 else
4171 notify.property=request->property;
4172 (void) XSendEvent(request->display,request->requestor,False,0,
4173 (XEvent *) &notify);
4174 }
4175 default:
4176 break;
4177 }
4178 } while ((state & ExitState) == 0);
4179 XSetCursorState(display,windows,MagickFalse);
4180 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
4181 XCheckRefreshWindows(display,windows);
4182 if (anomaly)
4183 if (special_info.raised)
4184 if (*reply != '\0')
4185 raised=MagickTrue;
4186 return(raised == MagickFalse);
4187}
4188
4189/*
4190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4191% %
4192% %
4193% %
4194% X F i l e B r o w s e r W i d g e t %
4195% %
4196% %
4197% %
4198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4199%
4200% XFileBrowserWidget() displays a File Browser widget with a file query to the
4201% user. The user keys a reply and presses the Action or Cancel button to
4202% exit. The typed text is returned as the reply function parameter.
4203%
4204% The format of the XFileBrowserWidget method is:
4205%
4206% void XFileBrowserWidget(Display *display,XWindows *windows,
4207% const char *action,char *reply)
4208%
4209% A description of each parameter follows:
4210%
4211% o display: Specifies a connection to an X server; returned from
4212% XOpenDisplay.
4213%
4214% o window: Specifies a pointer to a XWindows structure.
4215%
4216% o action: Specifies a pointer to the action of this widget.
4217%
4218% o reply: the response from the user is returned in this parameter.
4219%
4220*/
cristybcbda3f2011-09-03 13:01:22 +00004221MagickPrivate void XFileBrowserWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00004222 const char *action,char *reply)
4223{
4224#define CancelButtonText "Cancel"
4225#define DirectoryText "Directory:"
4226#define FilenameText "File name:"
4227#define GrabButtonText "Grab"
4228#define FormatButtonText "Format"
4229#define HomeButtonText "Home"
4230#define UpButtonText "Up"
4231
4232 char
cristy00976d82011-02-20 20:31:28 +00004233 *directory,
cristy3ed852e2009-09-05 21:47:34 +00004234 **filelist,
4235 home_directory[MaxTextExtent],
4236 primary_selection[MaxTextExtent],
4237 text[MaxTextExtent],
4238 working_path[MaxTextExtent];
4239
4240 int
4241 x,
4242 y;
4243
cristyecd0ab52010-05-30 14:59:20 +00004244 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004245 i;
4246
4247 static char
4248 glob_pattern[MaxTextExtent] = "*",
4249 format[MaxTextExtent] = "miff";
4250
4251 static MagickStatusType
4252 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
4253
4254 Status
4255 status;
4256
4257 unsigned int
4258 anomaly,
4259 height,
4260 text_width,
4261 visible_files,
4262 width;
4263
cristybb503372010-05-27 20:51:26 +00004264 size_t
cristy3ed852e2009-09-05 21:47:34 +00004265 delay,
4266 files,
4267 state;
4268
4269 XEvent
4270 event;
4271
4272 XFontStruct
4273 *font_info;
4274
4275 XTextProperty
4276 window_name;
4277
4278 XWidgetInfo
4279 action_info,
4280 cancel_info,
4281 expose_info,
4282 special_info,
4283 list_info,
4284 home_info,
4285 north_info,
4286 reply_info,
4287 scroll_info,
4288 selection_info,
4289 slider_info,
4290 south_info,
4291 text_info,
4292 up_info;
4293
4294 XWindowChanges
4295 window_changes;
4296
4297 /*
4298 Read filelist from current directory.
4299 */
4300 assert(display != (Display *) NULL);
4301 assert(windows != (XWindows *) NULL);
4302 assert(action != (char *) NULL);
4303 assert(reply != (char *) NULL);
4304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
4305 XSetCursorState(display,windows,MagickTrue);
4306 XCheckRefreshWindows(display,windows);
cristy00976d82011-02-20 20:31:28 +00004307 directory=getcwd(home_directory,MaxTextExtent);
4308 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +00004309 (void) CopyMagickString(working_path,home_directory,MaxTextExtent);
4310 filelist=ListFiles(working_path,glob_pattern,&files);
4311 if (filelist == (char **) NULL)
4312 {
4313 /*
4314 Directory read failed.
4315 */
4316 XNoticeWidget(display,windows,"Unable to read directory:",working_path);
4317 (void) XDialogWidget(display,windows,action,"Enter filename:",reply);
4318 return;
4319 }
4320 /*
4321 Determine File Browser widget attributes.
4322 */
4323 font_info=windows->widget.font_info;
4324 text_width=0;
cristybb503372010-05-27 20:51:26 +00004325 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004326 if (WidgetTextWidth(font_info,filelist[i]) > text_width)
4327 text_width=WidgetTextWidth(font_info,filelist[i]);
4328 width=WidgetTextWidth(font_info,(char *) action);
4329 if (WidgetTextWidth(font_info,GrabButtonText) > width)
4330 width=WidgetTextWidth(font_info,GrabButtonText);
4331 if (WidgetTextWidth(font_info,FormatButtonText) > width)
4332 width=WidgetTextWidth(font_info,FormatButtonText);
4333 if (WidgetTextWidth(font_info,CancelButtonText) > width)
4334 width=WidgetTextWidth(font_info,CancelButtonText);
4335 if (WidgetTextWidth(font_info,HomeButtonText) > width)
4336 width=WidgetTextWidth(font_info,HomeButtonText);
4337 if (WidgetTextWidth(font_info,UpButtonText) > width)
4338 width=WidgetTextWidth(font_info,UpButtonText);
4339 width+=QuantumMargin;
4340 if (WidgetTextWidth(font_info,DirectoryText) > width)
4341 width=WidgetTextWidth(font_info,DirectoryText);
4342 if (WidgetTextWidth(font_info,FilenameText) > width)
4343 width=WidgetTextWidth(font_info,FilenameText);
4344 height=(unsigned int) (font_info->ascent+font_info->descent);
4345 /*
4346 Position File Browser widget.
4347 */
4348 windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
4349 6*QuantumMargin;
4350 windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
4351 if (windows->widget.width < windows->widget.min_width)
4352 windows->widget.width=windows->widget.min_width;
4353 windows->widget.height=(unsigned int)
4354 (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
4355 windows->widget.min_height=(unsigned int)
4356 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
4357 if (windows->widget.height < windows->widget.min_height)
4358 windows->widget.height=windows->widget.min_height;
4359 XConstrainWindowPosition(display,&windows->widget);
4360 /*
4361 Map File Browser widget.
4362 */
4363 (void) CopyMagickString(windows->widget.name,"Browse and Select a File",
4364 MaxTextExtent);
4365 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
4366 if (status != False)
4367 {
4368 XSetWMName(display,windows->widget.id,&window_name);
4369 XSetWMIconName(display,windows->widget.id,&window_name);
4370 (void) XFree((void *) window_name.value);
4371 }
4372 window_changes.width=(int) windows->widget.width;
4373 window_changes.height=(int) windows->widget.height;
4374 window_changes.x=windows->widget.x;
4375 window_changes.y=windows->widget.y;
4376 (void) XReconfigureWMWindow(display,windows->widget.id,
4377 windows->widget.screen,mask,&window_changes);
4378 (void) XMapRaised(display,windows->widget.id);
4379 windows->widget.mapped=MagickFalse;
4380 /*
4381 Respond to X events.
4382 */
4383 XGetWidgetInfo((char *) NULL,&slider_info);
4384 XGetWidgetInfo((char *) NULL,&north_info);
4385 XGetWidgetInfo((char *) NULL,&south_info);
4386 XGetWidgetInfo((char *) NULL,&expose_info);
4387 visible_files=0;
4388 anomaly=(LocaleCompare(action,"Composite") == 0) ||
4389 (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0);
4390 *reply='\0';
4391 delay=SuspendTime << 2;
4392 state=UpdateConfigurationState;
4393 do
4394 {
4395 if (state & UpdateConfigurationState)
4396 {
4397 int
4398 id;
4399
4400 /*
4401 Initialize button information.
4402 */
4403 XGetWidgetInfo(CancelButtonText,&cancel_info);
4404 cancel_info.width=width;
4405 cancel_info.height=(unsigned int) ((3*height) >> 1);
4406 cancel_info.x=(int)
4407 (windows->widget.width-cancel_info.width-QuantumMargin-2);
4408 cancel_info.y=(int)
4409 (windows->widget.height-cancel_info.height-QuantumMargin);
4410 XGetWidgetInfo(action,&action_info);
4411 action_info.width=width;
4412 action_info.height=(unsigned int) ((3*height) >> 1);
4413 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
4414 (action_info.bevel_width << 1));
4415 action_info.y=cancel_info.y;
4416 XGetWidgetInfo(GrabButtonText,&special_info);
4417 special_info.width=width;
4418 special_info.height=(unsigned int) ((3*height) >> 1);
4419 special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+
4420 (special_info.bevel_width << 1));
4421 special_info.y=action_info.y;
4422 if (anomaly == MagickFalse)
4423 {
4424 register char
4425 *p;
4426
4427 special_info.text=(char *) FormatButtonText;
4428 p=reply+Extent(reply)-1;
4429 while ((p > (reply+1)) && (*(p-1) != '.'))
4430 p--;
4431 if ((p > (reply+1)) && (*(p-1) == '.'))
4432 (void) CopyMagickString(format,p,MaxTextExtent);
4433 }
4434 XGetWidgetInfo(UpButtonText,&up_info);
4435 up_info.width=width;
4436 up_info.height=(unsigned int) ((3*height) >> 1);
4437 up_info.x=QuantumMargin;
4438 up_info.y=((5*QuantumMargin) >> 1)+height;
4439 XGetWidgetInfo(HomeButtonText,&home_info);
4440 home_info.width=width;
4441 home_info.height=(unsigned int) ((3*height) >> 1);
4442 home_info.x=QuantumMargin;
4443 home_info.y=up_info.y+up_info.height+QuantumMargin;
4444 /*
4445 Initialize reply information.
4446 */
4447 XGetWidgetInfo(reply,&reply_info);
4448 reply_info.raised=MagickFalse;
4449 reply_info.bevel_width--;
4450 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
4451 reply_info.height=height << 1;
4452 reply_info.x=(int) (width+(QuantumMargin << 1));
4453 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
4454 /*
4455 Initialize scroll information.
4456 */
4457 XGetWidgetInfo((char *) NULL,&scroll_info);
4458 scroll_info.bevel_width--;
4459 scroll_info.width=height;
4460 scroll_info.height=(unsigned int)
4461 (reply_info.y-up_info.y-(QuantumMargin >> 1));
4462 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
4463 scroll_info.y=up_info.y-reply_info.bevel_width;
4464 scroll_info.raised=MagickFalse;
4465 scroll_info.trough=MagickTrue;
4466 north_info=scroll_info;
4467 north_info.raised=MagickTrue;
4468 north_info.width-=(north_info.bevel_width << 1);
4469 north_info.height=north_info.width-1;
4470 north_info.x+=north_info.bevel_width;
4471 north_info.y+=north_info.bevel_width;
4472 south_info=north_info;
4473 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
4474 south_info.height;
4475 id=slider_info.id;
4476 slider_info=north_info;
4477 slider_info.id=id;
4478 slider_info.width-=2;
4479 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
4480 slider_info.bevel_width+2;
4481 slider_info.height=scroll_info.height-((slider_info.min_y-
4482 scroll_info.y+1) << 1)+4;
4483 visible_files=scroll_info.height/(height+(height >> 3));
4484 if (files > visible_files)
4485 slider_info.height=(unsigned int)
4486 ((visible_files*slider_info.height)/files);
4487 slider_info.max_y=south_info.y-south_info.bevel_width-
4488 slider_info.bevel_width-2;
4489 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
4490 slider_info.y=slider_info.min_y;
4491 expose_info=scroll_info;
4492 expose_info.y=slider_info.y;
4493 /*
4494 Initialize list information.
4495 */
4496 XGetWidgetInfo((char *) NULL,&list_info);
4497 list_info.raised=MagickFalse;
4498 list_info.bevel_width--;
4499 list_info.width=(unsigned int)
4500 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
4501 list_info.height=scroll_info.height;
4502 list_info.x=reply_info.x;
4503 list_info.y=scroll_info.y;
4504 if (windows->widget.mapped == MagickFalse)
4505 state|=JumpListState;
4506 /*
4507 Initialize text information.
4508 */
4509 *text='\0';
4510 XGetWidgetInfo(text,&text_info);
4511 text_info.center=MagickFalse;
4512 text_info.width=reply_info.width;
4513 text_info.height=height;
4514 text_info.x=list_info.x-(QuantumMargin >> 1);
4515 text_info.y=QuantumMargin;
4516 /*
4517 Initialize selection information.
4518 */
4519 XGetWidgetInfo((char *) NULL,&selection_info);
4520 selection_info.center=MagickFalse;
4521 selection_info.width=list_info.width;
4522 selection_info.height=(unsigned int) ((9*height) >> 3);
4523 selection_info.x=list_info.x;
4524 state&=(~UpdateConfigurationState);
4525 }
4526 if (state & RedrawWidgetState)
4527 {
4528 /*
4529 Redraw File Browser window.
4530 */
4531 x=QuantumMargin;
4532 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
4533 (void) XDrawString(display,windows->widget.id,
4534 windows->widget.annotate_context,x,y,DirectoryText,
4535 Extent(DirectoryText));
4536 (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4537 (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4538 MaxTextExtent);
4539 (void) ConcatenateMagickString(text_info.text,glob_pattern,
4540 MaxTextExtent);
4541 XDrawWidgetText(display,&windows->widget,&text_info);
4542 XDrawBeveledButton(display,&windows->widget,&up_info);
4543 XDrawBeveledButton(display,&windows->widget,&home_info);
4544 XDrawBeveledMatte(display,&windows->widget,&list_info);
4545 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4546 XDrawTriangleNorth(display,&windows->widget,&north_info);
4547 XDrawBeveledButton(display,&windows->widget,&slider_info);
4548 XDrawTriangleSouth(display,&windows->widget,&south_info);
4549 x=QuantumMargin;
4550 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
4551 (void) XDrawString(display,windows->widget.id,
4552 windows->widget.annotate_context,x,y,FilenameText,
4553 Extent(FilenameText));
4554 XDrawBeveledMatte(display,&windows->widget,&reply_info);
4555 XDrawMatteText(display,&windows->widget,&reply_info);
4556 XDrawBeveledButton(display,&windows->widget,&special_info);
4557 XDrawBeveledButton(display,&windows->widget,&action_info);
4558 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4559 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4560 selection_info.id=(~0);
4561 state|=RedrawListState;
4562 state&=(~RedrawWidgetState);
4563 }
4564 if (state & UpdateListState)
4565 {
4566 char
4567 **checklist;
4568
cristybb503372010-05-27 20:51:26 +00004569 size_t
cristy3ed852e2009-09-05 21:47:34 +00004570 number_files;
4571
4572 /*
4573 Update file list.
4574 */
4575 checklist=ListFiles(working_path,glob_pattern,&number_files);
4576 if (checklist == (char **) NULL)
4577 {
4578 /*
4579 Reply is a filename, exit.
4580 */
4581 action_info.raised=MagickFalse;
4582 XDrawBeveledButton(display,&windows->widget,&action_info);
4583 break;
4584 }
cristybb503372010-05-27 20:51:26 +00004585 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004586 filelist[i]=DestroyString(filelist[i]);
4587 if (filelist != (char **) NULL)
4588 filelist=(char **) RelinquishMagickMemory(filelist);
4589 filelist=checklist;
4590 files=number_files;
4591 /*
4592 Update file list.
4593 */
4594 slider_info.height=
4595 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
4596 if (files > visible_files)
4597 slider_info.height=(unsigned int)
4598 ((visible_files*slider_info.height)/files);
4599 slider_info.max_y=south_info.y-south_info.bevel_width-
4600 slider_info.bevel_width-2;
4601 slider_info.id=0;
4602 slider_info.y=slider_info.min_y;
4603 expose_info.y=slider_info.y;
4604 selection_info.id=(~0);
4605 list_info.id=(~0);
4606 state|=RedrawListState;
4607 /*
4608 Redraw directory name & reply.
4609 */
4610 if (IsGlob(reply_info.text) == MagickFalse)
4611 {
4612 *reply_info.text='\0';
4613 reply_info.cursor=reply_info.text;
4614 }
4615 (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4616 (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4617 MaxTextExtent);
4618 (void) ConcatenateMagickString(text_info.text,glob_pattern,
4619 MaxTextExtent);
4620 XDrawWidgetText(display,&windows->widget,&text_info);
4621 XDrawMatteText(display,&windows->widget,&reply_info);
4622 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4623 XDrawTriangleNorth(display,&windows->widget,&north_info);
4624 XDrawBeveledButton(display,&windows->widget,&slider_info);
4625 XDrawTriangleSouth(display,&windows->widget,&south_info);
4626 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4627 state&=(~UpdateListState);
4628 }
4629 if (state & JumpListState)
4630 {
4631 /*
4632 Jump scroll to match user filename.
4633 */
4634 list_info.id=(~0);
cristybb503372010-05-27 20:51:26 +00004635 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004636 if (LocaleCompare(filelist[i],reply) >= 0)
4637 {
cristy49e2d862010-11-12 02:50:30 +00004638 list_info.id=(int)
4639 (LocaleCompare(filelist[i],reply) == 0 ? i : ~0);
cristy3ed852e2009-09-05 21:47:34 +00004640 break;
4641 }
cristy49e2d862010-11-12 02:50:30 +00004642 if ((i < (ssize_t) slider_info.id) ||
4643 (i >= (ssize_t) (slider_info.id+visible_files)))
4644 slider_info.id=(int) i-(visible_files >> 1);
cristy3ed852e2009-09-05 21:47:34 +00004645 selection_info.id=(~0);
4646 state|=RedrawListState;
4647 state&=(~JumpListState);
4648 }
4649 if (state & RedrawListState)
4650 {
4651 /*
4652 Determine slider id and position.
4653 */
4654 if (slider_info.id >= (int) (files-visible_files))
4655 slider_info.id=(int) (files-visible_files);
4656 if ((slider_info.id < 0) || (files <= visible_files))
4657 slider_info.id=0;
4658 slider_info.y=slider_info.min_y;
4659 if (files > 0)
cristydfe2b662010-08-22 16:17:24 +00004660 slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
cristy8891f9c2010-06-04 23:32:17 +00004661 slider_info.min_y+1)/files);
cristy3ed852e2009-09-05 21:47:34 +00004662 if (slider_info.id != selection_info.id)
4663 {
4664 /*
4665 Redraw scroll bar and file names.
4666 */
4667 selection_info.id=slider_info.id;
4668 selection_info.y=list_info.y+(height >> 3)+2;
cristy49e2d862010-11-12 02:50:30 +00004669 for (i=0; i < (ssize_t) visible_files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004670 {
cristy49e2d862010-11-12 02:50:30 +00004671 selection_info.raised=(int) (slider_info.id+i) != list_info.id ?
cristy3ed852e2009-09-05 21:47:34 +00004672 MagickTrue : MagickFalse;
4673 selection_info.text=(char *) NULL;
cristybb503372010-05-27 20:51:26 +00004674 if ((slider_info.id+i) < (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004675 selection_info.text=filelist[slider_info.id+i];
4676 XDrawWidgetText(display,&windows->widget,&selection_info);
4677 selection_info.y+=(int) selection_info.height;
4678 }
4679 /*
4680 Update slider.
4681 */
4682 if (slider_info.y > expose_info.y)
4683 {
4684 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
4685 expose_info.y=slider_info.y-expose_info.height-
4686 slider_info.bevel_width-1;
4687 }
4688 else
4689 {
4690 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
4691 expose_info.y=slider_info.y+slider_info.height+
4692 slider_info.bevel_width+1;
4693 }
4694 XDrawTriangleNorth(display,&windows->widget,&north_info);
4695 XDrawMatte(display,&windows->widget,&expose_info);
4696 XDrawBeveledButton(display,&windows->widget,&slider_info);
4697 XDrawTriangleSouth(display,&windows->widget,&south_info);
4698 expose_info.y=slider_info.y;
4699 }
4700 state&=(~RedrawListState);
4701 }
4702 /*
4703 Wait for next event.
4704 */
4705 if (north_info.raised && south_info.raised)
4706 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
4707 else
4708 {
4709 /*
4710 Brief delay before advancing scroll bar.
4711 */
4712 XDelay(display,delay);
4713 delay=SuspendTime;
4714 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
4715 if (north_info.raised == MagickFalse)
4716 if (slider_info.id > 0)
4717 {
4718 /*
4719 Move slider up.
4720 */
4721 slider_info.id--;
4722 state|=RedrawListState;
4723 }
4724 if (south_info.raised == MagickFalse)
cristy49e2d862010-11-12 02:50:30 +00004725 if (slider_info.id < (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004726 {
4727 /*
4728 Move slider down.
4729 */
4730 slider_info.id++;
4731 state|=RedrawListState;
4732 }
4733 if (event.type != ButtonRelease)
4734 continue;
4735 }
4736 switch (event.type)
4737 {
4738 case ButtonPress:
4739 {
4740 if (MatteIsActive(slider_info,event.xbutton))
4741 {
4742 /*
4743 Track slider.
4744 */
4745 slider_info.active=MagickTrue;
4746 break;
4747 }
4748 if (MatteIsActive(north_info,event.xbutton))
4749 if (slider_info.id > 0)
4750 {
4751 /*
4752 Move slider up.
4753 */
4754 north_info.raised=MagickFalse;
4755 slider_info.id--;
4756 state|=RedrawListState;
4757 break;
4758 }
4759 if (MatteIsActive(south_info,event.xbutton))
cristy49e2d862010-11-12 02:50:30 +00004760 if (slider_info.id < (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004761 {
4762 /*
4763 Move slider down.
4764 */
4765 south_info.raised=MagickFalse;
4766 slider_info.id++;
4767 state|=RedrawListState;
4768 break;
4769 }
4770 if (MatteIsActive(scroll_info,event.xbutton))
4771 {
4772 /*
4773 Move slider.
4774 */
4775 if (event.xbutton.y < slider_info.y)
4776 slider_info.id-=(visible_files-1);
4777 else
4778 slider_info.id+=(visible_files-1);
4779 state|=RedrawListState;
4780 break;
4781 }
4782 if (MatteIsActive(list_info,event.xbutton))
4783 {
4784 int
4785 id;
4786
4787 /*
4788 User pressed file matte.
4789 */
4790 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
4791 selection_info.height;
cristy49e2d862010-11-12 02:50:30 +00004792 if (id >= (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004793 break;
4794 (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
4795 reply_info.highlight=MagickFalse;
4796 reply_info.marker=reply_info.text;
4797 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4798 XDrawMatteText(display,&windows->widget,&reply_info);
4799 if (id == list_info.id)
4800 {
4801 register char
4802 *p;
4803
cristy3ed852e2009-09-05 21:47:34 +00004804 p=reply_info.text+strlen(reply_info.text)-1;
4805 if (*p == *DirectorySeparator)
4806 ChopPathComponents(reply_info.text,1);
4807 (void) ConcatenateMagickString(working_path,DirectorySeparator,
4808 MaxTextExtent);
4809 (void) ConcatenateMagickString(working_path,reply_info.text,
4810 MaxTextExtent);
4811 *reply='\0';
4812 state|=UpdateListState;
4813 }
4814 selection_info.id=(~0);
4815 list_info.id=id;
4816 state|=RedrawListState;
4817 break;
4818 }
4819 if (MatteIsActive(up_info,event.xbutton))
4820 {
4821 /*
4822 User pressed Up button.
4823 */
4824 up_info.raised=MagickFalse;
4825 XDrawBeveledButton(display,&windows->widget,&up_info);
4826 break;
4827 }
4828 if (MatteIsActive(home_info,event.xbutton))
4829 {
4830 /*
4831 User pressed Home button.
4832 */
4833 home_info.raised=MagickFalse;
4834 XDrawBeveledButton(display,&windows->widget,&home_info);
4835 break;
4836 }
4837 if (MatteIsActive(special_info,event.xbutton))
4838 {
4839 /*
4840 User pressed Special button.
4841 */
4842 special_info.raised=MagickFalse;
4843 XDrawBeveledButton(display,&windows->widget,&special_info);
4844 break;
4845 }
4846 if (MatteIsActive(action_info,event.xbutton))
4847 {
4848 /*
4849 User pressed action button.
4850 */
4851 action_info.raised=MagickFalse;
4852 XDrawBeveledButton(display,&windows->widget,&action_info);
4853 break;
4854 }
4855 if (MatteIsActive(cancel_info,event.xbutton))
4856 {
4857 /*
4858 User pressed Cancel button.
4859 */
4860 cancel_info.raised=MagickFalse;
4861 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4862 break;
4863 }
4864 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
4865 break;
4866 if (event.xbutton.button != Button2)
4867 {
4868 static Time
4869 click_time;
4870
4871 /*
4872 Move text cursor to position of button press.
4873 */
4874 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
cristy49e2d862010-11-12 02:50:30 +00004875 for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++)
4876 if (XTextWidth(font_info,reply_info.marker,(int) i) > x)
cristy3ed852e2009-09-05 21:47:34 +00004877 break;
4878 reply_info.cursor=reply_info.marker+i-1;
4879 if (event.xbutton.time > (click_time+DoubleClick))
4880 reply_info.highlight=MagickFalse;
4881 else
4882 {
4883 /*
4884 Become the XA_PRIMARY selection owner.
4885 */
4886 (void) CopyMagickString(primary_selection,reply_info.text,
4887 MaxTextExtent);
4888 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
4889 event.xbutton.time);
4890 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
4891 windows->widget.id ? MagickTrue : MagickFalse;
4892 }
4893 XDrawMatteText(display,&windows->widget,&reply_info);
4894 click_time=event.xbutton.time;
4895 break;
4896 }
4897 /*
4898 Request primary selection.
4899 */
4900 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
4901 windows->widget.id,event.xbutton.time);
4902 break;
4903 }
4904 case ButtonRelease:
4905 {
4906 if (windows->widget.mapped == MagickFalse)
4907 break;
4908 if (north_info.raised == MagickFalse)
4909 {
4910 /*
4911 User released up button.
4912 */
4913 delay=SuspendTime << 2;
4914 north_info.raised=MagickTrue;
4915 XDrawTriangleNorth(display,&windows->widget,&north_info);
4916 }
4917 if (south_info.raised == MagickFalse)
4918 {
4919 /*
4920 User released down button.
4921 */
4922 delay=SuspendTime << 2;
4923 south_info.raised=MagickTrue;
4924 XDrawTriangleSouth(display,&windows->widget,&south_info);
4925 }
4926 if (slider_info.active)
4927 {
4928 /*
4929 Stop tracking slider.
4930 */
4931 slider_info.active=MagickFalse;
4932 break;
4933 }
4934 if (up_info.raised == MagickFalse)
4935 {
4936 if (event.xbutton.window == windows->widget.id)
4937 if (MatteIsActive(up_info,event.xbutton))
4938 {
4939 ChopPathComponents(working_path,1);
4940 if (*working_path == '\0')
4941 (void) CopyMagickString(working_path,DirectorySeparator,
4942 MaxTextExtent);
4943 state|=UpdateListState;
4944 }
4945 up_info.raised=MagickTrue;
4946 XDrawBeveledButton(display,&windows->widget,&up_info);
4947 }
4948 if (home_info.raised == MagickFalse)
4949 {
4950 if (event.xbutton.window == windows->widget.id)
4951 if (MatteIsActive(home_info,event.xbutton))
4952 {
4953 (void) CopyMagickString(working_path,home_directory,
4954 MaxTextExtent);
4955 state|=UpdateListState;
4956 }
4957 home_info.raised=MagickTrue;
4958 XDrawBeveledButton(display,&windows->widget,&home_info);
4959 }
4960 if (special_info.raised == MagickFalse)
4961 {
4962 if (anomaly == MagickFalse)
4963 {
4964 char
4965 **formats;
4966
4967 ExceptionInfo
4968 *exception;
4969
cristybb503372010-05-27 20:51:26 +00004970 size_t
cristy3ed852e2009-09-05 21:47:34 +00004971 number_formats;
4972
4973 /*
4974 Let user select image format.
4975 */
4976 exception=AcquireExceptionInfo();
4977 formats=GetMagickList("*",&number_formats,exception);
4978 exception=DestroyExceptionInfo(exception);
4979 (void) XCheckDefineCursor(display,windows->widget.id,
4980 windows->widget.busy_cursor);
4981 windows->popup.x=windows->widget.x+60;
4982 windows->popup.y=windows->widget.y+60;
4983 XListBrowserWidget(display,windows,&windows->popup,
4984 (const char **) formats,"Select","Select image format type:",
4985 format);
4986 XSetCursorState(display,windows,MagickTrue);
4987 (void) XCheckDefineCursor(display,windows->widget.id,
4988 windows->widget.cursor);
4989 LocaleLower(format);
4990 AppendImageFormat(format,reply_info.text);
4991 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4992 XDrawMatteText(display,&windows->widget,&reply_info);
4993 special_info.raised=MagickTrue;
4994 XDrawBeveledButton(display,&windows->widget,&special_info);
cristy49e2d862010-11-12 02:50:30 +00004995 for (i=0; i < (ssize_t) number_formats; i++)
cristy3ed852e2009-09-05 21:47:34 +00004996 formats[i]=DestroyString(formats[i]);
4997 formats=(char **) RelinquishMagickMemory(formats);
4998 break;
4999 }
5000 if (event.xbutton.window == windows->widget.id)
5001 if (MatteIsActive(special_info,event.xbutton))
5002 {
5003 (void) CopyMagickString(working_path,"x:",MaxTextExtent);
5004 state|=ExitState;
5005 }
5006 special_info.raised=MagickTrue;
5007 XDrawBeveledButton(display,&windows->widget,&special_info);
5008 }
5009 if (action_info.raised == MagickFalse)
5010 {
5011 if (event.xbutton.window == windows->widget.id)
5012 {
5013 if (MatteIsActive(action_info,event.xbutton))
5014 {
5015 if (*reply_info.text == '\0')
5016 (void) XBell(display,0);
5017 else
5018 state|=ExitState;
5019 }
5020 }
5021 action_info.raised=MagickTrue;
5022 XDrawBeveledButton(display,&windows->widget,&action_info);
5023 }
5024 if (cancel_info.raised == MagickFalse)
5025 {
5026 if (event.xbutton.window == windows->widget.id)
5027 if (MatteIsActive(cancel_info,event.xbutton))
5028 {
5029 *reply_info.text='\0';
5030 *reply='\0';
5031 state|=ExitState;
5032 }
5033 cancel_info.raised=MagickTrue;
5034 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5035 }
5036 break;
5037 }
5038 case ClientMessage:
5039 {
5040 /*
5041 If client window delete message, exit.
5042 */
5043 if (event.xclient.message_type != windows->wm_protocols)
5044 break;
5045 if (*event.xclient.data.l == (int) windows->wm_take_focus)
5046 {
5047 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
5048 (Time) event.xclient.data.l[1]);
5049 break;
5050 }
5051 if (*event.xclient.data.l != (int) windows->wm_delete_window)
5052 break;
5053 if (event.xclient.window == windows->widget.id)
5054 {
5055 *reply_info.text='\0';
5056 state|=ExitState;
5057 break;
5058 }
5059 break;
5060 }
5061 case ConfigureNotify:
5062 {
5063 /*
5064 Update widget configuration.
5065 */
5066 if (event.xconfigure.window != windows->widget.id)
5067 break;
5068 if ((event.xconfigure.width == (int) windows->widget.width) &&
5069 (event.xconfigure.height == (int) windows->widget.height))
5070 break;
5071 windows->widget.width=(unsigned int)
5072 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
5073 windows->widget.height=(unsigned int)
5074 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
5075 state|=UpdateConfigurationState;
5076 break;
5077 }
5078 case EnterNotify:
5079 {
5080 if (event.xcrossing.window != windows->widget.id)
5081 break;
5082 state&=(~InactiveWidgetState);
5083 break;
5084 }
5085 case Expose:
5086 {
5087 if (event.xexpose.window != windows->widget.id)
5088 break;
5089 if (event.xexpose.count != 0)
5090 break;
5091 state|=RedrawWidgetState;
5092 break;
5093 }
5094 case KeyPress:
5095 {
5096 static char
5097 command[MaxTextExtent];
5098
5099 static int
5100 length;
5101
5102 static KeySym
5103 key_symbol;
5104
5105 /*
5106 Respond to a user key press.
5107 */
5108 if (event.xkey.window != windows->widget.id)
5109 break;
5110 length=XLookupString((XKeyEvent *) &event.xkey,command,
5111 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5112 *(command+length)='\0';
5113 if (AreaIsActive(scroll_info,event.xkey))
5114 {
5115 /*
5116 Move slider.
5117 */
5118 switch ((int) key_symbol)
5119 {
5120 case XK_Home:
5121 case XK_KP_Home:
5122 {
5123 slider_info.id=0;
5124 break;
5125 }
5126 case XK_Up:
5127 case XK_KP_Up:
5128 {
5129 slider_info.id--;
5130 break;
5131 }
5132 case XK_Down:
5133 case XK_KP_Down:
5134 {
5135 slider_info.id++;
5136 break;
5137 }
5138 case XK_Prior:
5139 case XK_KP_Prior:
5140 {
5141 slider_info.id-=visible_files;
5142 break;
5143 }
5144 case XK_Next:
5145 case XK_KP_Next:
5146 {
5147 slider_info.id+=visible_files;
5148 break;
5149 }
5150 case XK_End:
5151 case XK_KP_End:
5152 {
5153 slider_info.id=(int) files;
5154 break;
5155 }
5156 }
5157 state|=RedrawListState;
5158 break;
5159 }
5160 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
5161 {
5162 /*
5163 Read new directory or glob patterm.
5164 */
5165 if (*reply_info.text == '\0')
5166 break;
5167 if (IsGlob(reply_info.text))
5168 (void) CopyMagickString(glob_pattern,reply_info.text,
5169 MaxTextExtent);
5170 else
5171 {
5172 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5173 MaxTextExtent);
5174 (void) ConcatenateMagickString(working_path,reply_info.text,
5175 MaxTextExtent);
5176 if (*working_path == '~')
5177 ExpandFilename(working_path);
5178 *reply='\0';
5179 }
5180 state|=UpdateListState;
5181 break;
5182 }
5183 if (key_symbol == XK_Control_L)
5184 {
5185 state|=ControlState;
5186 break;
5187 }
5188 if (state & ControlState)
5189 switch ((int) key_symbol)
5190 {
5191 case XK_u:
5192 case XK_U:
5193 {
5194 /*
5195 Erase the entire line of text.
5196 */
5197 *reply_info.text='\0';
5198 reply_info.cursor=reply_info.text;
5199 reply_info.marker=reply_info.text;
5200 reply_info.highlight=MagickFalse;
5201 break;
5202 }
5203 default:
5204 break;
5205 }
5206 XEditText(display,&reply_info,key_symbol,command,state);
5207 XDrawMatteText(display,&windows->widget,&reply_info);
5208 state|=JumpListState;
5209 break;
5210 }
5211 case KeyRelease:
5212 {
5213 static char
5214 command[MaxTextExtent];
5215
5216 static KeySym
5217 key_symbol;
5218
5219 /*
5220 Respond to a user key release.
5221 */
5222 if (event.xkey.window != windows->widget.id)
5223 break;
5224 (void) XLookupString((XKeyEvent *) &event.xkey,command,
5225 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5226 if (key_symbol == XK_Control_L)
5227 state&=(~ControlState);
5228 break;
5229 }
5230 case LeaveNotify:
5231 {
5232 if (event.xcrossing.window != windows->widget.id)
5233 break;
5234 state|=InactiveWidgetState;
5235 break;
5236 }
5237 case MapNotify:
5238 {
5239 mask&=(~CWX);
5240 mask&=(~CWY);
5241 break;
5242 }
5243 case MotionNotify:
5244 {
5245 /*
5246 Discard pending button motion events.
5247 */
5248 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
5249 if (slider_info.active)
5250 {
5251 /*
5252 Move slider matte.
5253 */
5254 slider_info.y=event.xmotion.y-
5255 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
5256 if (slider_info.y < slider_info.min_y)
5257 slider_info.y=slider_info.min_y;
5258 if (slider_info.y > slider_info.max_y)
5259 slider_info.y=slider_info.max_y;
5260 slider_info.id=0;
5261 if (slider_info.y != slider_info.min_y)
5262 slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
5263 (slider_info.max_y-slider_info.min_y+1));
5264 state|=RedrawListState;
5265 break;
5266 }
5267 if (state & InactiveWidgetState)
5268 break;
5269 if (up_info.raised == MatteIsActive(up_info,event.xmotion))
5270 {
5271 /*
5272 Up button status changed.
5273 */
5274 up_info.raised=!up_info.raised;
5275 XDrawBeveledButton(display,&windows->widget,&up_info);
5276 break;
5277 }
5278 if (home_info.raised == MatteIsActive(home_info,event.xmotion))
5279 {
5280 /*
5281 Home button status changed.
5282 */
5283 home_info.raised=!home_info.raised;
5284 XDrawBeveledButton(display,&windows->widget,&home_info);
5285 break;
5286 }
5287 if (special_info.raised == MatteIsActive(special_info,event.xmotion))
5288 {
5289 /*
5290 Grab button status changed.
5291 */
5292 special_info.raised=!special_info.raised;
5293 XDrawBeveledButton(display,&windows->widget,&special_info);
5294 break;
5295 }
5296 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
5297 {
5298 /*
5299 Action button status changed.
5300 */
5301 action_info.raised=action_info.raised == MagickFalse ?
5302 MagickTrue : MagickFalse;
5303 XDrawBeveledButton(display,&windows->widget,&action_info);
5304 break;
5305 }
5306 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
5307 {
5308 /*
5309 Cancel button status changed.
5310 */
5311 cancel_info.raised=cancel_info.raised == MagickFalse ?
5312 MagickTrue : MagickFalse;
5313 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5314 break;
5315 }
5316 break;
5317 }
5318 case SelectionClear:
5319 {
5320 reply_info.highlight=MagickFalse;
5321 XDrawMatteText(display,&windows->widget,&reply_info);
5322 break;
5323 }
5324 case SelectionNotify:
5325 {
5326 Atom
5327 type;
5328
5329 int
5330 format;
5331
5332 unsigned char
5333 *data;
5334
cristyf2faecf2010-05-28 19:19:36 +00005335 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00005336 after,
5337 length;
5338
5339 /*
5340 Obtain response from primary selection.
5341 */
5342 if (event.xselection.property == (Atom) None)
5343 break;
5344 status=XGetWindowProperty(display,event.xselection.requestor,
5345 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
5346 &format,&length,&after,&data);
5347 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
5348 (length == 0))
5349 break;
cristy37e0b382011-06-07 13:31:21 +00005350 if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +00005351 (void) XBell(display,0);
5352 else
5353 {
5354 /*
5355 Insert primary selection in reply text.
5356 */
5357 *(data+length)='\0';
5358 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
5359 state);
5360 XDrawMatteText(display,&windows->widget,&reply_info);
5361 state|=JumpListState;
5362 state|=RedrawActionState;
5363 }
5364 (void) XFree((void *) data);
5365 break;
5366 }
5367 case SelectionRequest:
5368 {
5369 XSelectionEvent
5370 notify;
5371
5372 XSelectionRequestEvent
5373 *request;
5374
5375 if (reply_info.highlight == MagickFalse)
5376 break;
5377 /*
5378 Set primary selection.
5379 */
5380 request=(&(event.xselectionrequest));
5381 (void) XChangeProperty(request->display,request->requestor,
5382 request->property,request->target,8,PropModeReplace,
5383 (unsigned char *) primary_selection,Extent(primary_selection));
5384 notify.type=SelectionNotify;
5385 notify.display=request->display;
5386 notify.requestor=request->requestor;
5387 notify.selection=request->selection;
5388 notify.target=request->target;
5389 notify.time=request->time;
5390 if (request->property == None)
5391 notify.property=request->target;
5392 else
5393 notify.property=request->property;
5394 (void) XSendEvent(request->display,request->requestor,False,0,
5395 (XEvent *) &notify);
5396 }
5397 default:
5398 break;
5399 }
5400 } while ((state & ExitState) == 0);
5401 XSetCursorState(display,windows,MagickFalse);
5402 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
5403 XCheckRefreshWindows(display,windows);
5404 /*
5405 Free file list.
5406 */
cristybb503372010-05-27 20:51:26 +00005407 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00005408 filelist[i]=DestroyString(filelist[i]);
5409 if (filelist != (char **) NULL)
5410 filelist=(char **) RelinquishMagickMemory(filelist);
5411 if (*reply != '\0')
5412 {
5413 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5414 MaxTextExtent);
5415 (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
5416 }
5417 (void) CopyMagickString(reply,working_path,MaxTextExtent);
5418 if (*reply == '~')
5419 ExpandFilename(reply);
5420}
5421
5422/*
5423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5424% %
5425% %
5426% %
5427% X F o n t B r o w s e r W i d g e t %
5428% %
5429% %
5430% %
5431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5432%
5433% XFontBrowserWidget() displays a Font Browser widget with a font query to the
5434% user. The user keys a reply and presses the Action or Cancel button to
5435% exit. The typed text is returned as the reply function parameter.
5436%
5437% The format of the XFontBrowserWidget method is:
5438%
5439% void XFontBrowserWidget(Display *display,XWindows *windows,
5440% const char *action,char *reply)
5441%
5442% A description of each parameter follows:
5443%
5444% o display: Specifies a connection to an X server; returned from
5445% XOpenDisplay.
5446%
5447% o window: Specifies a pointer to a XWindows structure.
5448%
5449% o action: Specifies a pointer to the action of this widget.
5450%
5451% o reply: the response from the user is returned in this parameter.
5452%
5453%
5454*/
5455
5456#if defined(__cplusplus) || defined(c_plusplus)
5457extern "C" {
5458#endif
5459
5460static int FontCompare(const void *x,const void *y)
5461{
5462 register char
5463 *p,
5464 *q;
5465
5466 p=(char *) *((char **) x);
5467 q=(char *) *((char **) y);
5468 while ((*p != '\0') && (*q != '\0') && (*p == *q))
5469 {
5470 p++;
5471 q++;
5472 }
5473 return(*p-(*q));
5474}
5475
5476#if defined(__cplusplus) || defined(c_plusplus)
5477}
5478#endif
5479
cristybcbda3f2011-09-03 13:01:22 +00005480MagickPrivate void XFontBrowserWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00005481 const char *action,char *reply)
5482{
5483#define BackButtonText "Back"
5484#define CancelButtonText "Cancel"
5485#define FontnameText "Name:"
5486#define FontPatternText "Pattern:"
5487#define ResetButtonText "Reset"
5488
5489 char
5490 back_pattern[MaxTextExtent],
5491 **fontlist,
5492 **listhead,
5493 primary_selection[MaxTextExtent],
5494 reset_pattern[MaxTextExtent],
5495 text[MaxTextExtent];
5496
5497 int
5498 fonts,
5499 x,
5500 y;
5501
5502 register int
5503 i;
5504
5505 static char
5506 glob_pattern[MaxTextExtent] = "*";
5507
5508 static MagickStatusType
5509 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
5510
5511 Status
5512 status;
5513
5514 unsigned int
5515 height,
5516 text_width,
5517 visible_fonts,
5518 width;
5519
cristybb503372010-05-27 20:51:26 +00005520 size_t
cristy3ed852e2009-09-05 21:47:34 +00005521 delay,
5522 state;
5523
5524 XEvent
5525 event;
5526
5527 XFontStruct
5528 *font_info;
5529
5530 XTextProperty
5531 window_name;
5532
5533 XWidgetInfo
5534 action_info,
5535 back_info,
5536 cancel_info,
5537 expose_info,
5538 list_info,
5539 mode_info,
5540 north_info,
5541 reply_info,
5542 reset_info,
5543 scroll_info,
5544 selection_info,
5545 slider_info,
5546 south_info,
5547 text_info;
5548
5549 XWindowChanges
5550 window_changes;
5551
5552 /*
5553 Get font list and sort in ascending order.
5554 */
5555 assert(display != (Display *) NULL);
5556 assert(windows != (XWindows *) NULL);
5557 assert(action != (char *) NULL);
5558 assert(reply != (char *) NULL);
5559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
5560 XSetCursorState(display,windows,MagickTrue);
5561 XCheckRefreshWindows(display,windows);
5562 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
5563 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
5564 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5565 if (fonts == 0)
5566 {
5567 /*
5568 Pattern failed, obtain all the fonts.
5569 */
5570 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5571 glob_pattern);
5572 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
5573 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5574 if (fontlist == (char **) NULL)
5575 {
5576 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5577 glob_pattern);
5578 return;
5579 }
5580 }
5581 /*
5582 Sort font list in ascending order.
5583 */
5584 listhead=fontlist;
5585 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
5586 if (fontlist == (char **) NULL)
5587 {
5588 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5589 "UnableToViewFonts");
5590 return;
5591 }
5592 for (i=0; i < fonts; i++)
5593 fontlist[i]=listhead[i];
5594 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5595 /*
5596 Determine Font Browser widget attributes.
5597 */
5598 font_info=windows->widget.font_info;
5599 text_width=0;
5600 for (i=0; i < fonts; i++)
5601 if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
5602 text_width=WidgetTextWidth(font_info,fontlist[i]);
5603 width=WidgetTextWidth(font_info,(char *) action);
5604 if (WidgetTextWidth(font_info,CancelButtonText) > width)
5605 width=WidgetTextWidth(font_info,CancelButtonText);
5606 if (WidgetTextWidth(font_info,ResetButtonText) > width)
5607 width=WidgetTextWidth(font_info,ResetButtonText);
5608 if (WidgetTextWidth(font_info,BackButtonText) > width)
5609 width=WidgetTextWidth(font_info,BackButtonText);
5610 width+=QuantumMargin;
5611 if (WidgetTextWidth(font_info,FontPatternText) > width)
5612 width=WidgetTextWidth(font_info,FontPatternText);
5613 if (WidgetTextWidth(font_info,FontnameText) > width)
5614 width=WidgetTextWidth(font_info,FontnameText);
5615 height=(unsigned int) (font_info->ascent+font_info->descent);
5616 /*
5617 Position Font Browser widget.
5618 */
5619 windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
5620 6*QuantumMargin;
5621 windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
5622 if (windows->widget.width < windows->widget.min_width)
5623 windows->widget.width=windows->widget.min_width;
5624 windows->widget.height=(unsigned int)
5625 (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
5626 windows->widget.min_height=(unsigned int)
5627 (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
5628 if (windows->widget.height < windows->widget.min_height)
5629 windows->widget.height=windows->widget.min_height;
5630 XConstrainWindowPosition(display,&windows->widget);
5631 /*
5632 Map Font Browser widget.
5633 */
5634 (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
5635 MaxTextExtent);
5636 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
5637 if (status != False)
5638 {
5639 XSetWMName(display,windows->widget.id,&window_name);
5640 XSetWMIconName(display,windows->widget.id,&window_name);
5641 (void) XFree((void *) window_name.value);
5642 }
5643 window_changes.width=(int) windows->widget.width;
5644 window_changes.height=(int) windows->widget.height;
5645 window_changes.x=windows->widget.x;
5646 window_changes.y=windows->widget.y;
5647 (void) XReconfigureWMWindow(display,windows->widget.id,
5648 windows->widget.screen,mask,&window_changes);
5649 (void) XMapRaised(display,windows->widget.id);
5650 windows->widget.mapped=MagickFalse;
5651 /*
5652 Respond to X events.
5653 */
5654 XGetWidgetInfo((char *) NULL,&slider_info);
5655 XGetWidgetInfo((char *) NULL,&north_info);
5656 XGetWidgetInfo((char *) NULL,&south_info);
5657 XGetWidgetInfo((char *) NULL,&expose_info);
5658 visible_fonts=0;
5659 delay=SuspendTime << 2;
5660 state=UpdateConfigurationState;
5661 do
5662 {
5663 if (state & UpdateConfigurationState)
5664 {
5665 int
5666 id;
5667
5668 /*
5669 Initialize button information.
5670 */
5671 XGetWidgetInfo(CancelButtonText,&cancel_info);
5672 cancel_info.width=width;
5673 cancel_info.height=(unsigned int) ((3*height) >> 1);
5674 cancel_info.x=(int)
5675 (windows->widget.width-cancel_info.width-QuantumMargin-2);
5676 cancel_info.y=(int)
5677 (windows->widget.height-cancel_info.height-QuantumMargin);
5678 XGetWidgetInfo(action,&action_info);
5679 action_info.width=width;
5680 action_info.height=(unsigned int) ((3*height) >> 1);
5681 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
5682 (action_info.bevel_width << 1));
5683 action_info.y=cancel_info.y;
5684 XGetWidgetInfo(BackButtonText,&back_info);
5685 back_info.width=width;
5686 back_info.height=(unsigned int) ((3*height) >> 1);
5687 back_info.x=QuantumMargin;
5688 back_info.y=((5*QuantumMargin) >> 1)+height;
5689 XGetWidgetInfo(ResetButtonText,&reset_info);
5690 reset_info.width=width;
5691 reset_info.height=(unsigned int) ((3*height) >> 1);
5692 reset_info.x=QuantumMargin;
5693 reset_info.y=back_info.y+back_info.height+QuantumMargin;
5694 /*
5695 Initialize reply information.
5696 */
5697 XGetWidgetInfo(reply,&reply_info);
5698 reply_info.raised=MagickFalse;
5699 reply_info.bevel_width--;
5700 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
5701 reply_info.height=height << 1;
5702 reply_info.x=(int) (width+(QuantumMargin << 1));
5703 reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
5704 /*
5705 Initialize mode information.
5706 */
5707 XGetWidgetInfo(reply,&mode_info);
5708 mode_info.bevel_width=0;
5709 mode_info.width=(unsigned int)
5710 (action_info.x-reply_info.x-QuantumMargin);
5711 mode_info.height=action_info.height << 1;
5712 mode_info.x=reply_info.x;
5713 mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
5714 /*
5715 Initialize scroll information.
5716 */
5717 XGetWidgetInfo((char *) NULL,&scroll_info);
5718 scroll_info.bevel_width--;
5719 scroll_info.width=height;
5720 scroll_info.height=(unsigned int)
5721 (reply_info.y-back_info.y-(QuantumMargin >> 1));
5722 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
5723 scroll_info.y=back_info.y-reply_info.bevel_width;
5724 scroll_info.raised=MagickFalse;
5725 scroll_info.trough=MagickTrue;
5726 north_info=scroll_info;
5727 north_info.raised=MagickTrue;
5728 north_info.width-=(north_info.bevel_width << 1);
5729 north_info.height=north_info.width-1;
5730 north_info.x+=north_info.bevel_width;
5731 north_info.y+=north_info.bevel_width;
5732 south_info=north_info;
5733 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
5734 south_info.height;
5735 id=slider_info.id;
5736 slider_info=north_info;
5737 slider_info.id=id;
5738 slider_info.width-=2;
5739 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
5740 slider_info.bevel_width+2;
5741 slider_info.height=scroll_info.height-((slider_info.min_y-
5742 scroll_info.y+1) << 1)+4;
5743 visible_fonts=scroll_info.height/(height+(height >> 3));
5744 if (fonts > (int) visible_fonts)
5745 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5746 slider_info.max_y=south_info.y-south_info.bevel_width-
5747 slider_info.bevel_width-2;
5748 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
5749 slider_info.y=slider_info.min_y;
5750 expose_info=scroll_info;
5751 expose_info.y=slider_info.y;
5752 /*
5753 Initialize list information.
5754 */
5755 XGetWidgetInfo((char *) NULL,&list_info);
5756 list_info.raised=MagickFalse;
5757 list_info.bevel_width--;
5758 list_info.width=(unsigned int)
5759 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
5760 list_info.height=scroll_info.height;
5761 list_info.x=reply_info.x;
5762 list_info.y=scroll_info.y;
5763 if (windows->widget.mapped == MagickFalse)
5764 state|=JumpListState;
5765 /*
5766 Initialize text information.
5767 */
5768 *text='\0';
5769 XGetWidgetInfo(text,&text_info);
5770 text_info.center=MagickFalse;
5771 text_info.width=reply_info.width;
5772 text_info.height=height;
5773 text_info.x=list_info.x-(QuantumMargin >> 1);
5774 text_info.y=QuantumMargin;
5775 /*
5776 Initialize selection information.
5777 */
5778 XGetWidgetInfo((char *) NULL,&selection_info);
5779 selection_info.center=MagickFalse;
5780 selection_info.width=list_info.width;
5781 selection_info.height=(unsigned int) ((9*height) >> 3);
5782 selection_info.x=list_info.x;
5783 state&=(~UpdateConfigurationState);
5784 }
5785 if (state & RedrawWidgetState)
5786 {
5787 /*
5788 Redraw Font Browser window.
5789 */
5790 x=QuantumMargin;
5791 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
5792 (void) XDrawString(display,windows->widget.id,
5793 windows->widget.annotate_context,x,y,FontPatternText,
5794 Extent(FontPatternText));
5795 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5796 XDrawWidgetText(display,&windows->widget,&text_info);
5797 XDrawBeveledButton(display,&windows->widget,&back_info);
5798 XDrawBeveledButton(display,&windows->widget,&reset_info);
5799 XDrawBeveledMatte(display,&windows->widget,&list_info);
5800 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5801 XDrawTriangleNorth(display,&windows->widget,&north_info);
5802 XDrawBeveledButton(display,&windows->widget,&slider_info);
5803 XDrawTriangleSouth(display,&windows->widget,&south_info);
5804 x=QuantumMargin;
5805 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
5806 (void) XDrawString(display,windows->widget.id,
5807 windows->widget.annotate_context,x,y,FontnameText,
5808 Extent(FontnameText));
5809 XDrawBeveledMatte(display,&windows->widget,&reply_info);
5810 XDrawMatteText(display,&windows->widget,&reply_info);
5811 XDrawBeveledButton(display,&windows->widget,&action_info);
5812 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5813 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5814 selection_info.id=(~0);
5815 state|=RedrawActionState;
5816 state|=RedrawListState;
5817 state&=(~RedrawWidgetState);
5818 }
5819 if (state & UpdateListState)
5820 {
5821 char
5822 **checklist;
5823
5824 int
5825 number_fonts;
5826
5827 /*
5828 Update font list.
5829 */
5830 checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
5831 if (checklist == (char **) NULL)
5832 {
5833 if ((strchr(glob_pattern,'*') == (char *) NULL) &&
5834 (strchr(glob_pattern,'?') == (char *) NULL))
5835 {
5836 /*
5837 Might be a scaleable font-- exit.
5838 */
5839 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
5840 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5841 action_info.raised=MagickFalse;
5842 XDrawBeveledButton(display,&windows->widget,&action_info);
5843 break;
5844 }
5845 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5846 (void) XBell(display,0);
5847 }
5848 else
5849 if (number_fonts == 1)
5850 {
5851 /*
5852 Reply is a single font name-- exit.
5853 */
5854 (void) CopyMagickString(reply,checklist[0],MaxTextExtent);
5855 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5856 (void) XFreeFontNames(checklist);
5857 action_info.raised=MagickFalse;
5858 XDrawBeveledButton(display,&windows->widget,&action_info);
5859 break;
5860 }
5861 else
5862 {
5863 (void) XFreeFontNames(listhead);
5864 fontlist=(char **) RelinquishMagickMemory(fontlist);
5865 fontlist=checklist;
5866 fonts=number_fonts;
5867 }
5868 /*
5869 Sort font list in ascending order.
5870 */
5871 listhead=fontlist;
5872 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,
5873 sizeof(*fontlist));
5874 if (fontlist == (char **) NULL)
5875 {
5876 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5877 "UnableToViewFonts");
5878 return;
5879 }
5880 for (i=0; i < fonts; i++)
5881 fontlist[i]=listhead[i];
5882 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5883 slider_info.height=
5884 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
5885 if (fonts > (int) visible_fonts)
5886 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5887 slider_info.max_y=south_info.y-south_info.bevel_width-
5888 slider_info.bevel_width-2;
5889 slider_info.id=0;
5890 slider_info.y=slider_info.min_y;
5891 expose_info.y=slider_info.y;
5892 selection_info.id=(~0);
5893 list_info.id=(~0);
5894 state|=RedrawListState;
5895 /*
5896 Redraw font name & reply.
5897 */
5898 *reply_info.text='\0';
5899 reply_info.cursor=reply_info.text;
5900 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5901 XDrawWidgetText(display,&windows->widget,&text_info);
5902 XDrawMatteText(display,&windows->widget,&reply_info);
5903 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5904 XDrawTriangleNorth(display,&windows->widget,&north_info);
5905 XDrawBeveledButton(display,&windows->widget,&slider_info);
5906 XDrawTriangleSouth(display,&windows->widget,&south_info);
5907 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5908 state&=(~UpdateListState);
5909 }
5910 if (state & JumpListState)
5911 {
5912 /*
5913 Jump scroll to match user font.
5914 */
5915 list_info.id=(~0);
5916 for (i=0; i < fonts; i++)
5917 if (LocaleCompare(fontlist[i],reply) >= 0)
5918 {
5919 list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0;
5920 break;
5921 }
5922 if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts)))
5923 slider_info.id=i-(visible_fonts >> 1);
5924 selection_info.id=(~0);
5925 state|=RedrawListState;
5926 state&=(~JumpListState);
5927 }
5928 if (state & RedrawListState)
5929 {
5930 /*
5931 Determine slider id and position.
5932 */
5933 if (slider_info.id >= (int) (fonts-visible_fonts))
5934 slider_info.id=fonts-visible_fonts;
5935 if ((slider_info.id < 0) || (fonts <= (int) visible_fonts))
5936 slider_info.id=0;
5937 slider_info.y=slider_info.min_y;
5938 if (fonts > 0)
5939 slider_info.y+=
5940 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
5941 if (slider_info.id != selection_info.id)
5942 {
5943 /*
5944 Redraw scroll bar and file names.
5945 */
5946 selection_info.id=slider_info.id;
5947 selection_info.y=list_info.y+(height >> 3)+2;
5948 for (i=0; i < (int) visible_fonts; i++)
5949 {
5950 selection_info.raised=(slider_info.id+i) != list_info.id ?
5951 MagickTrue : MagickFalse;
5952 selection_info.text=(char *) NULL;
5953 if ((slider_info.id+i) < fonts)
5954 selection_info.text=fontlist[slider_info.id+i];
5955 XDrawWidgetText(display,&windows->widget,&selection_info);
5956 selection_info.y+=(int) selection_info.height;
5957 }
5958 /*
5959 Update slider.
5960 */
5961 if (slider_info.y > expose_info.y)
5962 {
5963 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
5964 expose_info.y=slider_info.y-expose_info.height-
5965 slider_info.bevel_width-1;
5966 }
5967 else
5968 {
5969 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
5970 expose_info.y=slider_info.y+slider_info.height+
5971 slider_info.bevel_width+1;
5972 }
5973 XDrawTriangleNorth(display,&windows->widget,&north_info);
5974 XDrawMatte(display,&windows->widget,&expose_info);
5975 XDrawBeveledButton(display,&windows->widget,&slider_info);
5976 XDrawTriangleSouth(display,&windows->widget,&south_info);
5977 expose_info.y=slider_info.y;
5978 }
5979 state&=(~RedrawListState);
5980 }
5981 if (state & RedrawActionState)
5982 {
5983 XFontStruct
5984 *save_info;
5985
5986 /*
5987 Display the selected font in a drawing area.
5988 */
5989 save_info=windows->widget.font_info;
5990 font_info=XLoadQueryFont(display,reply_info.text);
5991 if (font_info != (XFontStruct *) NULL)
5992 {
5993 windows->widget.font_info=font_info;
5994 (void) XSetFont(display,windows->widget.widget_context,
5995 font_info->fid);
5996 }
5997 XDrawBeveledButton(display,&windows->widget,&mode_info);
5998 windows->widget.font_info=save_info;
5999 if (font_info != (XFontStruct *) NULL)
6000 {
6001 (void) XSetFont(display,windows->widget.widget_context,
6002 windows->widget.font_info->fid);
6003 (void) XFreeFont(display,font_info);
6004 }
6005 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
6006 XDrawMatteText(display,&windows->widget,&reply_info);
6007 state&=(~RedrawActionState);
6008 }
6009 /*
6010 Wait for next event.
6011 */
6012 if (north_info.raised && south_info.raised)
6013 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
6014 else
6015 {
6016 /*
6017 Brief delay before advancing scroll bar.
6018 */
6019 XDelay(display,delay);
6020 delay=SuspendTime;
6021 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
6022 if (north_info.raised == MagickFalse)
6023 if (slider_info.id > 0)
6024 {
6025 /*
6026 Move slider up.
6027 */
6028 slider_info.id--;
6029 state|=RedrawListState;
6030 }
6031 if (south_info.raised == MagickFalse)
6032 if (slider_info.id < fonts)
6033 {
6034 /*
6035 Move slider down.
6036 */
6037 slider_info.id++;
6038 state|=RedrawListState;
6039 }
6040 if (event.type != ButtonRelease)
6041 continue;
6042 }
6043 switch (event.type)
6044 {
6045 case ButtonPress:
6046 {
6047 if (MatteIsActive(slider_info,event.xbutton))
6048 {
6049 /*
6050 Track slider.
6051 */
6052 slider_info.active=MagickTrue;
6053 break;
6054 }
6055 if (MatteIsActive(north_info,event.xbutton))
6056 if (slider_info.id > 0)
6057 {
6058 /*
6059 Move slider up.
6060 */
6061 north_info.raised=MagickFalse;
6062 slider_info.id--;
6063 state|=RedrawListState;
6064 break;
6065 }
6066 if (MatteIsActive(south_info,event.xbutton))
6067 if (slider_info.id < fonts)
6068 {
6069 /*
6070 Move slider down.
6071 */
6072 south_info.raised=MagickFalse;
6073 slider_info.id++;
6074 state|=RedrawListState;
6075 break;
6076 }
6077 if (MatteIsActive(scroll_info,event.xbutton))
6078 {
6079 /*
6080 Move slider.
6081 */
6082 if (event.xbutton.y < slider_info.y)
6083 slider_info.id-=(visible_fonts-1);
6084 else
6085 slider_info.id+=(visible_fonts-1);
6086 state|=RedrawListState;
6087 break;
6088 }
6089 if (MatteIsActive(list_info,event.xbutton))
6090 {
6091 int
6092 id;
6093
6094 /*
6095 User pressed list matte.
6096 */
6097 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
6098 selection_info.height;
6099 if (id >= (int) fonts)
6100 break;
6101 (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent);
6102 reply_info.highlight=MagickFalse;
6103 reply_info.marker=reply_info.text;
6104 reply_info.cursor=reply_info.text+Extent(reply_info.text);
6105 XDrawMatteText(display,&windows->widget,&reply_info);
6106 state|=RedrawActionState;
6107 if (id == list_info.id)
6108 {
6109 (void) CopyMagickString(glob_pattern,reply_info.text,
6110 MaxTextExtent);
6111 state|=UpdateListState;
6112 }
6113 selection_info.id=(~0);
6114 list_info.id=id;
6115 state|=RedrawListState;
6116 break;
6117 }
6118 if (MatteIsActive(back_info,event.xbutton))
6119 {
6120 /*
6121 User pressed Back button.
6122 */
6123 back_info.raised=MagickFalse;
6124 XDrawBeveledButton(display,&windows->widget,&back_info);
6125 break;
6126 }
6127 if (MatteIsActive(reset_info,event.xbutton))
6128 {
6129 /*
6130 User pressed Reset button.
6131 */
6132 reset_info.raised=MagickFalse;
6133 XDrawBeveledButton(display,&windows->widget,&reset_info);
6134 break;
6135 }
6136 if (MatteIsActive(action_info,event.xbutton))
6137 {
6138 /*
6139 User pressed action button.
6140 */
6141 action_info.raised=MagickFalse;
6142 XDrawBeveledButton(display,&windows->widget,&action_info);
6143 break;
6144 }
6145 if (MatteIsActive(cancel_info,event.xbutton))
6146 {
6147 /*
6148 User pressed Cancel button.
6149 */
6150 cancel_info.raised=MagickFalse;
6151 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6152 break;
6153 }
6154 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
6155 break;
6156 if (event.xbutton.button != Button2)
6157 {
6158 static Time
6159 click_time;
6160
6161 /*
6162 Move text cursor to position of button press.
6163 */
6164 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
6165 for (i=1; i <= Extent(reply_info.marker); i++)
6166 if (XTextWidth(font_info,reply_info.marker,i) > x)
6167 break;
6168 reply_info.cursor=reply_info.marker+i-1;
6169 if (event.xbutton.time > (click_time+DoubleClick))
6170 reply_info.highlight=MagickFalse;
6171 else
6172 {
6173 /*
6174 Become the XA_PRIMARY selection owner.
6175 */
6176 (void) CopyMagickString(primary_selection,reply_info.text,
6177 MaxTextExtent);
6178 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
6179 event.xbutton.time);
6180 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
6181 windows->widget.id ? MagickTrue : MagickFalse;
6182 }
6183 XDrawMatteText(display,&windows->widget,&reply_info);
6184 click_time=event.xbutton.time;
6185 break;
6186 }
6187 /*
6188 Request primary selection.
6189 */
6190 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
6191 windows->widget.id,event.xbutton.time);
6192 break;
6193 }
6194 case ButtonRelease:
6195 {
6196 if (windows->widget.mapped == MagickFalse)
6197 break;
6198 if (north_info.raised == MagickFalse)
6199 {
6200 /*
6201 User released up button.
6202 */
6203 delay=SuspendTime << 2;
6204 north_info.raised=MagickTrue;
6205 XDrawTriangleNorth(display,&windows->widget,&north_info);
6206 }
6207 if (south_info.raised == MagickFalse)
6208 {
6209 /*
6210 User released down button.
6211 */
6212 delay=SuspendTime << 2;
6213 south_info.raised=MagickTrue;
6214 XDrawTriangleSouth(display,&windows->widget,&south_info);
6215 }
6216 if (slider_info.active)
6217 {
6218 /*
6219 Stop tracking slider.
6220 */
6221 slider_info.active=MagickFalse;
6222 break;
6223 }
6224 if (back_info.raised == MagickFalse)
6225 {
6226 if (event.xbutton.window == windows->widget.id)
6227 if (MatteIsActive(back_info,event.xbutton))
6228 {
6229 (void) CopyMagickString(glob_pattern,back_pattern,
6230 MaxTextExtent);
6231 state|=UpdateListState;
6232 }
6233 back_info.raised=MagickTrue;
6234 XDrawBeveledButton(display,&windows->widget,&back_info);
6235 }
6236 if (reset_info.raised == MagickFalse)
6237 {
6238 if (event.xbutton.window == windows->widget.id)
6239 if (MatteIsActive(reset_info,event.xbutton))
6240 {
6241 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6242 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
6243 state|=UpdateListState;
6244 }
6245 reset_info.raised=MagickTrue;
6246 XDrawBeveledButton(display,&windows->widget,&reset_info);
6247 }
6248 if (action_info.raised == MagickFalse)
6249 {
6250 if (event.xbutton.window == windows->widget.id)
6251 {
6252 if (MatteIsActive(action_info,event.xbutton))
6253 {
6254 if (*reply_info.text == '\0')
6255 (void) XBell(display,0);
6256 else
6257 state|=ExitState;
6258 }
6259 }
6260 action_info.raised=MagickTrue;
6261 XDrawBeveledButton(display,&windows->widget,&action_info);
6262 }
6263 if (cancel_info.raised == MagickFalse)
6264 {
6265 if (event.xbutton.window == windows->widget.id)
6266 if (MatteIsActive(cancel_info,event.xbutton))
6267 {
6268 *reply_info.text='\0';
6269 state|=ExitState;
6270 }
6271 cancel_info.raised=MagickTrue;
6272 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6273 }
6274 break;
6275 }
6276 case ClientMessage:
6277 {
6278 /*
6279 If client window delete message, exit.
6280 */
6281 if (event.xclient.message_type != windows->wm_protocols)
6282 break;
6283 if (*event.xclient.data.l == (int) windows->wm_take_focus)
6284 {
6285 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
6286 (Time) event.xclient.data.l[1]);
6287 break;
6288 }
6289 if (*event.xclient.data.l != (int) windows->wm_delete_window)
6290 break;
6291 if (event.xclient.window == windows->widget.id)
6292 {
6293 *reply_info.text='\0';
6294 state|=ExitState;
6295 break;
6296 }
6297 break;
6298 }
6299 case ConfigureNotify:
6300 {
6301 /*
6302 Update widget configuration.
6303 */
6304 if (event.xconfigure.window != windows->widget.id)
6305 break;
6306 if ((event.xconfigure.width == (int) windows->widget.width) &&
6307 (event.xconfigure.height == (int) windows->widget.height))
6308 break;
6309 windows->widget.width=(unsigned int)
6310 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
6311 windows->widget.height=(unsigned int)
6312 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
6313 state|=UpdateConfigurationState;
6314 break;
6315 }
6316 case EnterNotify:
6317 {
6318 if (event.xcrossing.window != windows->widget.id)
6319 break;
6320 state&=(~InactiveWidgetState);
6321 break;
6322 }
6323 case Expose:
6324 {
6325 if (event.xexpose.window != windows->widget.id)
6326 break;
6327 if (event.xexpose.count != 0)
6328 break;
6329 state|=RedrawWidgetState;
6330 break;
6331 }
6332 case KeyPress:
6333 {
6334 static char
6335 command[MaxTextExtent];
6336
6337 static int
6338 length;
6339
6340 static KeySym
6341 key_symbol;
6342
6343 /*
6344 Respond to a user key press.
6345 */
6346 if (event.xkey.window != windows->widget.id)
6347 break;
6348 length=XLookupString((XKeyEvent *) &event.xkey,command,
6349 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6350 *(command+length)='\0';
6351 if (AreaIsActive(scroll_info,event.xkey))
6352 {
6353 /*
6354 Move slider.
6355 */
6356 switch ((int) key_symbol)
6357 {
6358 case XK_Home:
6359 case XK_KP_Home:
6360 {
6361 slider_info.id=0;
6362 break;
6363 }
6364 case XK_Up:
6365 case XK_KP_Up:
6366 {
6367 slider_info.id--;
6368 break;
6369 }
6370 case XK_Down:
6371 case XK_KP_Down:
6372 {
6373 slider_info.id++;
6374 break;
6375 }
6376 case XK_Prior:
6377 case XK_KP_Prior:
6378 {
6379 slider_info.id-=visible_fonts;
6380 break;
6381 }
6382 case XK_Next:
6383 case XK_KP_Next:
6384 {
6385 slider_info.id+=visible_fonts;
6386 break;
6387 }
6388 case XK_End:
6389 case XK_KP_End:
6390 {
6391 slider_info.id=fonts;
6392 break;
6393 }
6394 }
6395 state|=RedrawListState;
6396 break;
6397 }
6398 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
6399 {
6400 /*
6401 Read new font or glob patterm.
6402 */
6403 if (*reply_info.text == '\0')
6404 break;
6405 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6406 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
6407 state|=UpdateListState;
6408 break;
6409 }
6410 if (key_symbol == XK_Control_L)
6411 {
6412 state|=ControlState;
6413 break;
6414 }
6415 if (state & ControlState)
6416 switch ((int) key_symbol)
6417 {
6418 case XK_u:
6419 case XK_U:
6420 {
6421 /*
6422 Erase the entire line of text.
6423 */
6424 *reply_info.text='\0';
6425 reply_info.cursor=reply_info.text;
6426 reply_info.marker=reply_info.text;
6427 reply_info.highlight=MagickFalse;
6428 break;
6429 }
6430 default:
6431 break;
6432 }
6433 XEditText(display,&reply_info,key_symbol,command,state);
6434 XDrawMatteText(display,&windows->widget,&reply_info);
6435 state|=JumpListState;
6436 break;
6437 }
6438 case KeyRelease:
6439 {
6440 static char
6441 command[MaxTextExtent];
6442
6443 static KeySym
6444 key_symbol;
6445
6446 /*
6447 Respond to a user key release.
6448 */
6449 if (event.xkey.window != windows->widget.id)
6450 break;
6451 (void) XLookupString((XKeyEvent *) &event.xkey,command,
6452 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6453 if (key_symbol == XK_Control_L)
6454 state&=(~ControlState);
6455 break;
6456 }
6457 case LeaveNotify:
6458 {
6459 if (event.xcrossing.window != windows->widget.id)
6460 break;
6461 state|=InactiveWidgetState;
6462 break;
6463 }
6464 case MapNotify:
6465 {
6466 mask&=(~CWX);
6467 mask&=(~CWY);
6468 break;
6469 }
6470 case MotionNotify:
6471 {
6472 /*
6473 Discard pending button motion events.
6474 */
6475 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
6476 if (slider_info.active)
6477 {
6478 /*
6479 Move slider matte.
6480 */
6481 slider_info.y=event.xmotion.y-
6482 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
6483 if (slider_info.y < slider_info.min_y)
6484 slider_info.y=slider_info.min_y;
6485 if (slider_info.y > slider_info.max_y)
6486 slider_info.y=slider_info.max_y;
6487 slider_info.id=0;
6488 if (slider_info.y != slider_info.min_y)
6489 slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
6490 (slider_info.max_y-slider_info.min_y+1);
6491 state|=RedrawListState;
6492 break;
6493 }
6494 if (state & InactiveWidgetState)
6495 break;
6496 if (back_info.raised == MatteIsActive(back_info,event.xmotion))
6497 {
6498 /*
6499 Back button status changed.
6500 */
6501 back_info.raised=!back_info.raised;
6502 XDrawBeveledButton(display,&windows->widget,&back_info);
6503 break;
6504 }
6505 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
6506 {
6507 /*
6508 Reset button status changed.
6509 */
6510 reset_info.raised=!reset_info.raised;
6511 XDrawBeveledButton(display,&windows->widget,&reset_info);
6512 break;
6513 }
6514 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
6515 {
6516 /*
6517 Action button status changed.
6518 */
6519 action_info.raised=action_info.raised == MagickFalse ?
6520 MagickTrue : MagickFalse;
6521 XDrawBeveledButton(display,&windows->widget,&action_info);
6522 break;
6523 }
6524 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
6525 {
6526 /*
6527 Cancel button status changed.
6528 */
6529 cancel_info.raised=cancel_info.raised == MagickFalse ?
6530 MagickTrue : MagickFalse;
6531 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6532 break;
6533 }
6534 break;
6535 }
6536 case SelectionClear:
6537 {
6538 reply_info.highlight=MagickFalse;
6539 XDrawMatteText(display,&windows->widget,&reply_info);
6540 break;
6541 }
6542 case SelectionNotify:
6543 {
6544 Atom
6545 type;
6546
6547 int
6548 format;
6549
6550 unsigned char
6551 *data;
6552
cristyf2faecf2010-05-28 19:19:36 +00006553 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00006554 after,
6555 length;
6556
6557 /*
6558 Obtain response from primary selection.
6559 */
6560 if (event.xselection.property == (Atom) None)
6561 break;
6562 status=XGetWindowProperty(display,event.xselection.requestor,
6563 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
6564 &format,&length,&after,&data);
6565 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
6566 (length == 0))
6567 break;
cristy37e0b382011-06-07 13:31:21 +00006568 if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +00006569 (void) XBell(display,0);
6570 else
6571 {
6572 /*
6573 Insert primary selection in reply text.
6574 */
6575 *(data+length)='\0';
6576 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
6577 state);
6578 XDrawMatteText(display,&windows->widget,&reply_info);
6579 state|=JumpListState;
6580 state|=RedrawActionState;
6581 }
6582 (void) XFree((void *) data);
6583 break;
6584 }
6585 case SelectionRequest:
6586 {
6587 XSelectionEvent
6588 notify;
6589
6590 XSelectionRequestEvent
6591 *request;
6592
6593 /*
6594 Set XA_PRIMARY selection.
6595 */
6596 request=(&(event.xselectionrequest));
6597 (void) XChangeProperty(request->display,request->requestor,
6598 request->property,request->target,8,PropModeReplace,
6599 (unsigned char *) primary_selection,Extent(primary_selection));
6600 notify.type=SelectionNotify;
6601 notify.display=request->display;
6602 notify.requestor=request->requestor;
6603 notify.selection=request->selection;
6604 notify.target=request->target;
6605 notify.time=request->time;
6606 if (request->property == None)
6607 notify.property=request->target;
6608 else
6609 notify.property=request->property;
6610 (void) XSendEvent(request->display,request->requestor,False,0,
6611 (XEvent *) &notify);
6612 }
6613 default:
6614 break;
6615 }
6616 } while ((state & ExitState) == 0);
6617 XSetCursorState(display,windows,MagickFalse);
6618 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
6619 XCheckRefreshWindows(display,windows);
6620 /*
6621 Free font list.
6622 */
6623 (void) XFreeFontNames(listhead);
6624 fontlist=(char **) RelinquishMagickMemory(fontlist);
6625}
6626
6627/*
6628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6629% %
6630% %
6631% %
6632% X I n f o W i d g e t %
6633% %
6634% %
6635% %
6636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6637%
6638% XInfoWidget() displays text in the Info widget. The purpose is to inform
6639% the user that what activity is currently being performed (e.g. reading
6640% an image, rotating an image, etc.).
6641%
6642% The format of the XInfoWidget method is:
6643%
6644% void XInfoWidget(Display *display,XWindows *windows,const char *activity)
6645%
6646% A description of each parameter follows:
6647%
6648% o display: Specifies a connection to an X server; returned from
6649% XOpenDisplay.
6650%
6651% o window: Specifies a pointer to a XWindows structure.
6652%
6653% o activity: This character string reflects the current activity and is
6654% displayed in the Info widget.
6655%
6656*/
cristybcbda3f2011-09-03 13:01:22 +00006657MagickPrivate void XInfoWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00006658 const char *activity)
6659{
6660 unsigned int
6661 height,
6662 margin,
6663 width;
6664
6665 XFontStruct
6666 *font_info;
6667
6668 XWindowChanges
6669 window_changes;
6670
6671 /*
6672 Map Info widget.
6673 */
6674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
6675 assert(display != (Display *) NULL);
6676 assert(windows != (XWindows *) NULL);
6677 assert(activity != (char *) NULL);
6678 font_info=windows->info.font_info;
6679 width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4;
6680 height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4);
6681 if ((windows->info.width != width) || (windows->info.height != height))
6682 {
6683 /*
6684 Size Info widget to accommodate the activity text.
6685 */
6686 windows->info.width=width;
6687 windows->info.height=height;
6688 window_changes.width=(int) width;
6689 window_changes.height=(int) height;
6690 (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen,
6691 (unsigned int) (CWWidth | CWHeight),&window_changes);
6692 }
6693 if (windows->info.mapped == MagickFalse)
6694 {
6695 (void) XMapRaised(display,windows->info.id);
6696 windows->info.mapped=MagickTrue;
6697 }
6698 /*
6699 Initialize Info matte information.
6700 */
6701 height=(unsigned int) (font_info->ascent+font_info->descent);
6702 XGetWidgetInfo(activity,&monitor_info);
6703 monitor_info.bevel_width--;
6704 margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2;
6705 monitor_info.center=MagickFalse;
6706 monitor_info.x=(int) margin;
6707 monitor_info.y=(int) margin;
6708 monitor_info.width=windows->info.width-(margin << 1);
6709 monitor_info.height=windows->info.height-(margin << 1)+1;
6710 /*
6711 Draw Info widget.
6712 */
6713 monitor_info.raised=MagickFalse;
6714 XDrawBeveledMatte(display,&windows->info,&monitor_info);
6715 monitor_info.raised=MagickTrue;
6716 XDrawWidgetText(display,&windows->info,&monitor_info);
6717}
6718
6719/*
6720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6721% %
6722% %
6723% %
6724% X L i s t B r o w s e r W i d g e t %
6725% %
6726% %
6727% %
6728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6729%
6730% XListBrowserWidget() displays a List Browser widget with a query to the
6731% user. The user keys a reply or select a reply from the list. Finally, the
6732% user presses the Action or Cancel button to exit. The typed text is
6733% returned as the reply function parameter.
6734%
6735% The format of the XListBrowserWidget method is:
6736%
6737% void XListBrowserWidget(Display *display,XWindows *windows,
6738% XWindowInfo *window_info,const char **list,const char *action,
6739% const char *query,char *reply)
6740%
6741% A description of each parameter follows:
6742%
6743% o display: Specifies a connection to an X server; returned from
6744% XOpenDisplay.
6745%
6746% o window: Specifies a pointer to a XWindows structure.
6747%
6748% o list: Specifies a pointer to an array of strings. The user can
6749% select from these strings as a possible reply value.
6750%
6751% o action: Specifies a pointer to the action of this widget.
6752%
6753% o query: Specifies a pointer to the query to present to the user.
6754%
6755% o reply: the response from the user is returned in this parameter.
6756%
6757*/
cristybcbda3f2011-09-03 13:01:22 +00006758MagickPrivate void XListBrowserWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00006759 XWindowInfo *window_info,const char **list,const char *action,
6760 const char *query,char *reply)
6761{
6762#define CancelButtonText "Cancel"
6763
6764 char
6765 primary_selection[MaxTextExtent];
6766
6767 int
6768 x;
6769
6770 register int
6771 i;
6772
6773 static MagickStatusType
6774 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
6775
6776 Status
6777 status;
6778
6779 unsigned int
6780 entries,
6781 height,
6782 text_width,
6783 visible_entries,
6784 width;
6785
cristybb503372010-05-27 20:51:26 +00006786 size_t
cristy3ed852e2009-09-05 21:47:34 +00006787 delay,
6788 state;
6789
6790 XEvent
6791 event;
6792
6793 XFontStruct
6794 *font_info;
6795
6796 XTextProperty
6797 window_name;
6798
6799 XWidgetInfo
6800 action_info,
6801 cancel_info,
6802 expose_info,
6803 list_info,
6804 north_info,
6805 reply_info,
6806 scroll_info,
6807 selection_info,
6808 slider_info,
6809 south_info,
6810 text_info;
6811
6812 XWindowChanges
6813 window_changes;
6814
6815 /*
6816 Count the number of entries in the list.
6817 */
6818 assert(display != (Display *) NULL);
6819 assert(windows != (XWindows *) NULL);
6820 assert(window_info != (XWindowInfo *) NULL);
6821 assert(list != (const char **) NULL);
6822 assert(action != (char *) NULL);
6823 assert(query != (char *) NULL);
6824 assert(reply != (char *) NULL);
6825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
6826 XSetCursorState(display,windows,MagickTrue);
6827 XCheckRefreshWindows(display,windows);
6828 if (list == (const char **) NULL)
6829 {
6830 XNoticeWidget(display,windows,"No text to browse:",(char *) NULL);
6831 return;
6832 }
6833 for (entries=0; ; entries++)
6834 if (list[entries] == (char *) NULL)
6835 break;
6836 /*
6837 Determine Font Browser widget attributes.
6838 */
6839 font_info=window_info->font_info;
6840 text_width=WidgetTextWidth(font_info,(char *) query);
6841 for (i=0; i < (int) entries; i++)
6842 if (WidgetTextWidth(font_info,(char *) list[i]) > text_width)
6843 text_width=WidgetTextWidth(font_info,(char *) list[i]);
6844 width=WidgetTextWidth(font_info,(char *) action);
6845 if (WidgetTextWidth(font_info,CancelButtonText) > width)
6846 width=WidgetTextWidth(font_info,CancelButtonText);
6847 width+=QuantumMargin;
6848 height=(unsigned int) (font_info->ascent+font_info->descent);
6849 /*
6850 Position List Browser widget.
6851 */
6852 window_info->width=(unsigned int) MagickMin((int) text_width,(int)
6853 MaxTextWidth)+((9*QuantumMargin) >> 1);
6854 window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
6855 if (window_info->width < window_info->min_width)
6856 window_info->width=window_info->min_width;
6857 window_info->height=(unsigned int)
6858 (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
6859 window_info->min_height=(unsigned int)
6860 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
6861 if (window_info->height < window_info->min_height)
6862 window_info->height=window_info->min_height;
6863 XConstrainWindowPosition(display,window_info);
6864 /*
6865 Map List Browser widget.
6866 */
6867 (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent);
6868 status=XStringListToTextProperty(&window_info->name,1,&window_name);
6869 if (status != False)
6870 {
6871 XSetWMName(display,window_info->id,&window_name);
6872 XSetWMIconName(display,windows->widget.id,&window_name);
6873 (void) XFree((void *) window_name.value);
6874 }
6875 window_changes.width=(int) window_info->width;
6876 window_changes.height=(int) window_info->height;
6877 window_changes.x=window_info->x;
6878 window_changes.y=window_info->y;
6879 (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
6880 &window_changes);
6881 (void) XMapRaised(display,window_info->id);
6882 window_info->mapped=MagickFalse;
6883 /*
6884 Respond to X events.
6885 */
6886 XGetWidgetInfo((char *) NULL,&slider_info);
6887 XGetWidgetInfo((char *) NULL,&north_info);
6888 XGetWidgetInfo((char *) NULL,&south_info);
6889 XGetWidgetInfo((char *) NULL,&expose_info);
6890 visible_entries=0;
6891 delay=SuspendTime << 2;
6892 state=UpdateConfigurationState;
6893 do
6894 {
6895 if (state & UpdateConfigurationState)
6896 {
6897 int
6898 id;
6899
6900 /*
6901 Initialize button information.
6902 */
6903 XGetWidgetInfo(CancelButtonText,&cancel_info);
6904 cancel_info.width=width;
6905 cancel_info.height=(unsigned int) ((3*height) >> 1);
6906 cancel_info.x=(int)
6907 (window_info->width-cancel_info.width-QuantumMargin-2);
6908 cancel_info.y=(int)
6909 (window_info->height-cancel_info.height-QuantumMargin);
6910 XGetWidgetInfo(action,&action_info);
6911 action_info.width=width;
6912 action_info.height=(unsigned int) ((3*height) >> 1);
6913 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
6914 (action_info.bevel_width << 1));
6915 action_info.y=cancel_info.y;
6916 /*
6917 Initialize reply information.
6918 */
6919 XGetWidgetInfo(reply,&reply_info);
6920 reply_info.raised=MagickFalse;
6921 reply_info.bevel_width--;
6922 reply_info.width=window_info->width-((4*QuantumMargin) >> 1);
6923 reply_info.height=height << 1;
6924 reply_info.x=QuantumMargin;
6925 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
6926 /*
6927 Initialize scroll information.
6928 */
6929 XGetWidgetInfo((char *) NULL,&scroll_info);
6930 scroll_info.bevel_width--;
6931 scroll_info.width=height;
6932 scroll_info.height=(unsigned int)
6933 (reply_info.y-((6*QuantumMargin) >> 1)-height);
6934 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
6935 scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width;
6936 scroll_info.raised=MagickFalse;
6937 scroll_info.trough=MagickTrue;
6938 north_info=scroll_info;
6939 north_info.raised=MagickTrue;
6940 north_info.width-=(north_info.bevel_width << 1);
6941 north_info.height=north_info.width-1;
6942 north_info.x+=north_info.bevel_width;
6943 north_info.y+=north_info.bevel_width;
6944 south_info=north_info;
6945 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
6946 south_info.height;
6947 id=slider_info.id;
6948 slider_info=north_info;
6949 slider_info.id=id;
6950 slider_info.width-=2;
6951 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
6952 slider_info.bevel_width+2;
6953 slider_info.height=scroll_info.height-((slider_info.min_y-
6954 scroll_info.y+1) << 1)+4;
6955 visible_entries=scroll_info.height/(height+(height >> 3));
6956 if (entries > visible_entries)
6957 slider_info.height=(visible_entries*slider_info.height)/entries;
6958 slider_info.max_y=south_info.y-south_info.bevel_width-
6959 slider_info.bevel_width-2;
6960 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
6961 slider_info.y=slider_info.min_y;
6962 expose_info=scroll_info;
6963 expose_info.y=slider_info.y;
6964 /*
6965 Initialize list information.
6966 */
6967 XGetWidgetInfo((char *) NULL,&list_info);
6968 list_info.raised=MagickFalse;
6969 list_info.bevel_width--;
6970 list_info.width=(unsigned int)
6971 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
6972 list_info.height=scroll_info.height;
6973 list_info.x=reply_info.x;
6974 list_info.y=scroll_info.y;
6975 if (window_info->mapped == MagickFalse)
6976 for (i=0; i < (int) entries; i++)
6977 if (LocaleCompare(list[i],reply) == 0)
6978 {
6979 list_info.id=i;
6980 slider_info.id=i-(visible_entries >> 1);
6981 if (slider_info.id < 0)
6982 slider_info.id=0;
6983 }
6984 /*
6985 Initialize text information.
6986 */
6987 XGetWidgetInfo(query,&text_info);
6988 text_info.width=reply_info.width;
6989 text_info.height=height;
6990 text_info.x=list_info.x-(QuantumMargin >> 1);
6991 text_info.y=QuantumMargin;
6992 /*
6993 Initialize selection information.
6994 */
6995 XGetWidgetInfo((char *) NULL,&selection_info);
6996 selection_info.center=MagickFalse;
6997 selection_info.width=list_info.width;
6998 selection_info.height=(unsigned int) ((9*height) >> 3);
6999 selection_info.x=list_info.x;
7000 state&=(~UpdateConfigurationState);
7001 }
7002 if (state & RedrawWidgetState)
7003 {
7004 /*
7005 Redraw List Browser window.
7006 */
7007 XDrawWidgetText(display,window_info,&text_info);
7008 XDrawBeveledMatte(display,window_info,&list_info);
7009 XDrawBeveledMatte(display,window_info,&scroll_info);
7010 XDrawTriangleNorth(display,window_info,&north_info);
7011 XDrawBeveledButton(display,window_info,&slider_info);
7012 XDrawTriangleSouth(display,window_info,&south_info);
7013 XDrawBeveledMatte(display,window_info,&reply_info);
7014 XDrawMatteText(display,window_info,&reply_info);
7015 XDrawBeveledButton(display,window_info,&action_info);
7016 XDrawBeveledButton(display,window_info,&cancel_info);
7017 XHighlightWidget(display,window_info,BorderOffset,BorderOffset);
7018 selection_info.id=(~0);
7019 state|=RedrawActionState;
7020 state|=RedrawListState;
7021 state&=(~RedrawWidgetState);
7022 }
7023 if (state & RedrawListState)
7024 {
7025 /*
7026 Determine slider id and position.
7027 */
7028 if (slider_info.id >= (int) (entries-visible_entries))
7029 slider_info.id=(int) (entries-visible_entries);
7030 if ((slider_info.id < 0) || (entries <= visible_entries))
7031 slider_info.id=0;
7032 slider_info.y=slider_info.min_y;
7033 if (entries > 0)
7034 slider_info.y+=
7035 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries;
7036 if (slider_info.id != selection_info.id)
7037 {
7038 /*
7039 Redraw scroll bar and file names.
7040 */
7041 selection_info.id=slider_info.id;
7042 selection_info.y=list_info.y+(height >> 3)+2;
7043 for (i=0; i < (int) visible_entries; i++)
7044 {
7045 selection_info.raised=(slider_info.id+i) != list_info.id ?
7046 MagickTrue : MagickFalse;
7047 selection_info.text=(char *) NULL;
7048 if ((slider_info.id+i) < (int) entries)
7049 selection_info.text=(char *) list[slider_info.id+i];
7050 XDrawWidgetText(display,window_info,&selection_info);
7051 selection_info.y+=(int) selection_info.height;
7052 }
7053 /*
7054 Update slider.
7055 */
7056 if (slider_info.y > expose_info.y)
7057 {
7058 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
7059 expose_info.y=slider_info.y-expose_info.height-
7060 slider_info.bevel_width-1;
7061 }
7062 else
7063 {
7064 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
7065 expose_info.y=slider_info.y+slider_info.height+
7066 slider_info.bevel_width+1;
7067 }
7068 XDrawTriangleNorth(display,window_info,&north_info);
7069 XDrawMatte(display,window_info,&expose_info);
7070 XDrawBeveledButton(display,window_info,&slider_info);
7071 XDrawTriangleSouth(display,window_info,&south_info);
7072 expose_info.y=slider_info.y;
7073 }
7074 state&=(~RedrawListState);
7075 }
7076 /*
7077 Wait for next event.
7078 */
7079 if (north_info.raised && south_info.raised)
7080 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7081 else
7082 {
7083 /*
7084 Brief delay before advancing scroll bar.
7085 */
7086 XDelay(display,delay);
7087 delay=SuspendTime;
7088 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
7089 if (north_info.raised == MagickFalse)
7090 if (slider_info.id > 0)
7091 {
7092 /*
7093 Move slider up.
7094 */
7095 slider_info.id--;
7096 state|=RedrawListState;
7097 }
7098 if (south_info.raised == MagickFalse)
7099 if (slider_info.id < (int) entries)
7100 {
7101 /*
7102 Move slider down.
7103 */
7104 slider_info.id++;
7105 state|=RedrawListState;
7106 }
7107 if (event.type != ButtonRelease)
7108 continue;
7109 }
7110 switch (event.type)
7111 {
7112 case ButtonPress:
7113 {
7114 if (MatteIsActive(slider_info,event.xbutton))
7115 {
7116 /*
7117 Track slider.
7118 */
7119 slider_info.active=MagickTrue;
7120 break;
7121 }
7122 if (MatteIsActive(north_info,event.xbutton))
7123 if (slider_info.id > 0)
7124 {
7125 /*
7126 Move slider up.
7127 */
7128 north_info.raised=MagickFalse;
7129 slider_info.id--;
7130 state|=RedrawListState;
7131 break;
7132 }
7133 if (MatteIsActive(south_info,event.xbutton))
7134 if (slider_info.id < (int) entries)
7135 {
7136 /*
7137 Move slider down.
7138 */
7139 south_info.raised=MagickFalse;
7140 slider_info.id++;
7141 state|=RedrawListState;
7142 break;
7143 }
7144 if (MatteIsActive(scroll_info,event.xbutton))
7145 {
7146 /*
7147 Move slider.
7148 */
7149 if (event.xbutton.y < slider_info.y)
7150 slider_info.id-=(visible_entries-1);
7151 else
7152 slider_info.id+=(visible_entries-1);
7153 state|=RedrawListState;
7154 break;
7155 }
7156 if (MatteIsActive(list_info,event.xbutton))
7157 {
7158 int
7159 id;
7160
7161 /*
7162 User pressed list matte.
7163 */
7164 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
7165 selection_info.height;
7166 if (id >= (int) entries)
7167 break;
7168 (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent);
7169 reply_info.highlight=MagickFalse;
7170 reply_info.marker=reply_info.text;
7171 reply_info.cursor=reply_info.text+Extent(reply_info.text);
7172 XDrawMatteText(display,window_info,&reply_info);
7173 selection_info.id=(~0);
7174 if (id == list_info.id)
7175 {
7176 action_info.raised=MagickFalse;
7177 XDrawBeveledButton(display,window_info,&action_info);
7178 state|=ExitState;
7179 }
7180 list_info.id=id;
7181 state|=RedrawListState;
7182 break;
7183 }
7184 if (MatteIsActive(action_info,event.xbutton))
7185 {
7186 /*
7187 User pressed action button.
7188 */
7189 action_info.raised=MagickFalse;
7190 XDrawBeveledButton(display,window_info,&action_info);
7191 break;
7192 }
7193 if (MatteIsActive(cancel_info,event.xbutton))
7194 {
7195 /*
7196 User pressed Cancel button.
7197 */
7198 cancel_info.raised=MagickFalse;
7199 XDrawBeveledButton(display,window_info,&cancel_info);
7200 break;
7201 }
7202 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7203 break;
7204 if (event.xbutton.button != Button2)
7205 {
7206 static Time
7207 click_time;
7208
7209 /*
7210 Move text cursor to position of button press.
7211 */
7212 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
7213 for (i=1; i <= Extent(reply_info.marker); i++)
7214 if (XTextWidth(font_info,reply_info.marker,i) > x)
7215 break;
7216 reply_info.cursor=reply_info.marker+i-1;
7217 if (event.xbutton.time > (click_time+DoubleClick))
7218 reply_info.highlight=MagickFalse;
7219 else
7220 {
7221 /*
7222 Become the XA_PRIMARY selection owner.
7223 */
7224 (void) CopyMagickString(primary_selection,reply_info.text,
7225 MaxTextExtent);
7226 (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id,
7227 event.xbutton.time);
7228 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
7229 window_info->id ? MagickTrue : MagickFalse;
7230 }
7231 XDrawMatteText(display,window_info,&reply_info);
7232 click_time=event.xbutton.time;
7233 break;
7234 }
7235 /*
7236 Request primary selection.
7237 */
7238 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
7239 window_info->id,event.xbutton.time);
7240 break;
7241 }
7242 case ButtonRelease:
7243 {
7244 if (window_info->mapped == MagickFalse)
7245 break;
7246 if (north_info.raised == MagickFalse)
7247 {
7248 /*
7249 User released up button.
7250 */
7251 delay=SuspendTime << 2;
7252 north_info.raised=MagickTrue;
7253 XDrawTriangleNorth(display,window_info,&north_info);
7254 }
7255 if (south_info.raised == MagickFalse)
7256 {
7257 /*
7258 User released down button.
7259 */
7260 delay=SuspendTime << 2;
7261 south_info.raised=MagickTrue;
7262 XDrawTriangleSouth(display,window_info,&south_info);
7263 }
7264 if (slider_info.active)
7265 {
7266 /*
7267 Stop tracking slider.
7268 */
7269 slider_info.active=MagickFalse;
7270 break;
7271 }
7272 if (action_info.raised == MagickFalse)
7273 {
7274 if (event.xbutton.window == window_info->id)
7275 {
7276 if (MatteIsActive(action_info,event.xbutton))
7277 {
7278 if (*reply_info.text == '\0')
7279 (void) XBell(display,0);
7280 else
7281 state|=ExitState;
7282 }
7283 }
7284 action_info.raised=MagickTrue;
7285 XDrawBeveledButton(display,window_info,&action_info);
7286 }
7287 if (cancel_info.raised == MagickFalse)
7288 {
7289 if (event.xbutton.window == window_info->id)
7290 if (MatteIsActive(cancel_info,event.xbutton))
7291 {
7292 *reply_info.text='\0';
7293 state|=ExitState;
7294 }
7295 cancel_info.raised=MagickTrue;
7296 XDrawBeveledButton(display,window_info,&cancel_info);
7297 }
7298 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7299 break;
7300 break;
7301 }
7302 case ClientMessage:
7303 {
7304 /*
7305 If client window delete message, exit.
7306 */
7307 if (event.xclient.message_type != windows->wm_protocols)
7308 break;
7309 if (*event.xclient.data.l == (int) windows->wm_take_focus)
7310 {
7311 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
7312 (Time) event.xclient.data.l[1]);
7313 break;
7314 }
7315 if (*event.xclient.data.l != (int) windows->wm_delete_window)
7316 break;
7317 if (event.xclient.window == window_info->id)
7318 {
7319 *reply_info.text='\0';
7320 state|=ExitState;
7321 break;
7322 }
7323 break;
7324 }
7325 case ConfigureNotify:
7326 {
7327 /*
7328 Update widget configuration.
7329 */
7330 if (event.xconfigure.window != window_info->id)
7331 break;
7332 if ((event.xconfigure.width == (int) window_info->width) &&
7333 (event.xconfigure.height == (int) window_info->height))
7334 break;
7335 window_info->width=(unsigned int)
7336 MagickMax(event.xconfigure.width,(int) window_info->min_width);
7337 window_info->height=(unsigned int)
7338 MagickMax(event.xconfigure.height,(int) window_info->min_height);
7339 state|=UpdateConfigurationState;
7340 break;
7341 }
7342 case EnterNotify:
7343 {
7344 if (event.xcrossing.window != window_info->id)
7345 break;
7346 state&=(~InactiveWidgetState);
7347 break;
7348 }
7349 case Expose:
7350 {
7351 if (event.xexpose.window != window_info->id)
7352 break;
7353 if (event.xexpose.count != 0)
7354 break;
7355 state|=RedrawWidgetState;
7356 break;
7357 }
7358 case KeyPress:
7359 {
7360 static char
7361 command[MaxTextExtent];
7362
7363 static int
7364 length;
7365
7366 static KeySym
7367 key_symbol;
7368
7369 /*
7370 Respond to a user key press.
7371 */
7372 if (event.xkey.window != window_info->id)
7373 break;
7374 length=XLookupString((XKeyEvent *) &event.xkey,command,
7375 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7376 *(command+length)='\0';
7377 if (AreaIsActive(scroll_info,event.xkey))
7378 {
7379 /*
7380 Move slider.
7381 */
7382 switch ((int) key_symbol)
7383 {
7384 case XK_Home:
7385 case XK_KP_Home:
7386 {
7387 slider_info.id=0;
7388 break;
7389 }
7390 case XK_Up:
7391 case XK_KP_Up:
7392 {
7393 slider_info.id--;
7394 break;
7395 }
7396 case XK_Down:
7397 case XK_KP_Down:
7398 {
7399 slider_info.id++;
7400 break;
7401 }
7402 case XK_Prior:
7403 case XK_KP_Prior:
7404 {
7405 slider_info.id-=visible_entries;
7406 break;
7407 }
7408 case XK_Next:
7409 case XK_KP_Next:
7410 {
7411 slider_info.id+=visible_entries;
7412 break;
7413 }
7414 case XK_End:
7415 case XK_KP_End:
7416 {
7417 slider_info.id=(int) entries;
7418 break;
7419 }
7420 }
7421 state|=RedrawListState;
7422 break;
7423 }
7424 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
7425 {
7426 /*
7427 Read new entry.
7428 */
7429 if (*reply_info.text == '\0')
7430 break;
7431 action_info.raised=MagickFalse;
7432 XDrawBeveledButton(display,window_info,&action_info);
7433 state|=ExitState;
7434 break;
7435 }
7436 if (key_symbol == XK_Control_L)
7437 {
7438 state|=ControlState;
7439 break;
7440 }
7441 if (state & ControlState)
7442 switch ((int) key_symbol)
7443 {
7444 case XK_u:
7445 case XK_U:
7446 {
7447 /*
7448 Erase the entire line of text.
7449 */
7450 *reply_info.text='\0';
7451 reply_info.cursor=reply_info.text;
7452 reply_info.marker=reply_info.text;
7453 reply_info.highlight=MagickFalse;
7454 break;
7455 }
7456 default:
7457 break;
7458 }
7459 XEditText(display,&reply_info,key_symbol,command,state);
7460 XDrawMatteText(display,window_info,&reply_info);
7461 break;
7462 }
7463 case KeyRelease:
7464 {
7465 static char
7466 command[MaxTextExtent];
7467
7468 static KeySym
7469 key_symbol;
7470
7471 /*
7472 Respond to a user key release.
7473 */
7474 if (event.xkey.window != window_info->id)
7475 break;
7476 (void) XLookupString((XKeyEvent *) &event.xkey,command,
7477 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7478 if (key_symbol == XK_Control_L)
7479 state&=(~ControlState);
7480 break;
7481 }
7482 case LeaveNotify:
7483 {
7484 if (event.xcrossing.window != window_info->id)
7485 break;
7486 state|=InactiveWidgetState;
7487 break;
7488 }
7489 case MapNotify:
7490 {
7491 mask&=(~CWX);
7492 mask&=(~CWY);
7493 break;
7494 }
7495 case MotionNotify:
7496 {
7497 /*
7498 Discard pending button motion events.
7499 */
7500 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7501 if (slider_info.active)
7502 {
7503 /*
7504 Move slider matte.
7505 */
7506 slider_info.y=event.xmotion.y-
7507 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
7508 if (slider_info.y < slider_info.min_y)
7509 slider_info.y=slider_info.min_y;
7510 if (slider_info.y > slider_info.max_y)
7511 slider_info.y=slider_info.max_y;
7512 slider_info.id=0;
7513 if (slider_info.y != slider_info.min_y)
7514 slider_info.id=(int) ((entries*(slider_info.y-
7515 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
7516 state|=RedrawListState;
7517 break;
7518 }
7519 if (state & InactiveWidgetState)
7520 break;
7521 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
7522 {
7523 /*
7524 Action button status changed.
7525 */
7526 action_info.raised=action_info.raised == MagickFalse ?
7527 MagickTrue : MagickFalse;
7528 XDrawBeveledButton(display,window_info,&action_info);
7529 break;
7530 }
7531 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
7532 {
7533 /*
7534 Cancel button status changed.
7535 */
7536 cancel_info.raised=cancel_info.raised == MagickFalse ?
7537 MagickTrue : MagickFalse;
7538 XDrawBeveledButton(display,window_info,&cancel_info);
7539 break;
7540 }
7541 break;
7542 }
7543 case SelectionClear:
7544 {
7545 reply_info.highlight=MagickFalse;
7546 XDrawMatteText(display,window_info,&reply_info);
7547 break;
7548 }
7549 case SelectionNotify:
7550 {
7551 Atom
7552 type;
7553
7554 int
7555 format;
7556
7557 unsigned char
7558 *data;
7559
cristyf2faecf2010-05-28 19:19:36 +00007560 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00007561 after,
7562 length;
7563
7564 /*
7565 Obtain response from primary selection.
7566 */
7567 if (event.xselection.property == (Atom) None)
7568 break;
7569 status=XGetWindowProperty(display,
7570 event.xselection.requestor,event.xselection.property,0L,2047L,
7571 MagickTrue,XA_STRING,&type,&format,&length,&after,&data);
7572 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
7573 (length == 0))
7574 break;
cristy37e0b382011-06-07 13:31:21 +00007575 if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +00007576 (void) XBell(display,0);
7577 else
7578 {
7579 /*
7580 Insert primary selection in reply text.
7581 */
7582 *(data+length)='\0';
7583 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
7584 state);
7585 XDrawMatteText(display,window_info,&reply_info);
7586 state|=RedrawActionState;
7587 }
7588 (void) XFree((void *) data);
7589 break;
7590 }
7591 case SelectionRequest:
7592 {
7593 XSelectionEvent
7594 notify;
7595
7596 XSelectionRequestEvent
7597 *request;
7598
7599 if (reply_info.highlight == MagickFalse)
7600 break;
7601 /*
7602 Set primary selection.
7603 */
7604 request=(&(event.xselectionrequest));
7605 (void) XChangeProperty(request->display,request->requestor,
7606 request->property,request->target,8,PropModeReplace,
7607 (unsigned char *) primary_selection,Extent(primary_selection));
7608 notify.type=SelectionNotify;
7609 notify.send_event=MagickTrue;
7610 notify.display=request->display;
7611 notify.requestor=request->requestor;
7612 notify.selection=request->selection;
7613 notify.target=request->target;
7614 notify.time=request->time;
7615 if (request->property == None)
7616 notify.property=request->target;
7617 else
7618 notify.property=request->property;
7619 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
7620 (XEvent *) &notify);
7621 }
7622 default:
7623 break;
7624 }
7625 } while ((state & ExitState) == 0);
7626 XSetCursorState(display,windows,MagickFalse);
7627 (void) XWithdrawWindow(display,window_info->id,window_info->screen);
7628 XCheckRefreshWindows(display,windows);
7629}
7630
7631/*
7632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7633% %
7634% %
7635% %
7636% X M e n u W i d g e t %
7637% %
7638% %
7639% %
7640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7641%
7642% XMenuWidget() maps a menu and returns the command pointed to by the user
7643% when the button is released.
7644%
7645% The format of the XMenuWidget method is:
7646%
7647% int XMenuWidget(Display *display,XWindows *windows,const char *title,
7648% const char **selections,char *item)
7649%
7650% A description of each parameter follows:
7651%
7652% o selection_number: Specifies the number of the selection that the
7653% user choose.
7654%
7655% o display: Specifies a connection to an X server; returned from
7656% XOpenDisplay.
7657%
7658% o window: Specifies a pointer to a XWindows structure.
7659%
7660% o title: Specifies a character string that describes the menu selections.
7661%
7662% o selections: Specifies a pointer to one or more strings that comprise
7663% the choices in the menu.
7664%
7665% o item: Specifies a character array. The item selected from the menu
7666% is returned here.
7667%
7668*/
cristybcbda3f2011-09-03 13:01:22 +00007669MagickPrivate int XMenuWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00007670 const char *title,const char **selections,char *item)
7671{
7672 Cursor
7673 cursor;
7674
7675 int
7676 id,
7677 x,
7678 y;
7679
7680 unsigned int
7681 height,
7682 number_selections,
7683 title_height,
7684 top_offset,
7685 width;
7686
cristybb503372010-05-27 20:51:26 +00007687 size_t
cristy3ed852e2009-09-05 21:47:34 +00007688 state;
7689
7690 XEvent
7691 event;
7692
7693 XFontStruct
7694 *font_info;
7695
7696 XSetWindowAttributes
7697 window_attributes;
7698
7699 XWidgetInfo
7700 highlight_info,
7701 menu_info,
7702 selection_info;
7703
7704 XWindowChanges
7705 window_changes;
7706
7707 /*
7708 Determine Menu widget attributes.
7709 */
7710 assert(display != (Display *) NULL);
7711 assert(windows != (XWindows *) NULL);
7712 assert(title != (char *) NULL);
7713 assert(selections != (const char **) NULL);
7714 assert(item != (char *) NULL);
7715 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
7716 font_info=windows->widget.font_info;
7717 windows->widget.width=submenu_info.active == 0 ?
7718 WidgetTextWidth(font_info,(char *) title) : 0;
7719 for (id=0; selections[id] != (char *) NULL; id++)
7720 {
7721 width=WidgetTextWidth(font_info,(char *) selections[id]);
7722 if (width > windows->widget.width)
7723 windows->widget.width=width;
7724 }
7725 number_selections=(unsigned int) id;
7726 XGetWidgetInfo((char *) NULL,&menu_info);
7727 title_height=(unsigned int) (submenu_info.active == 0 ?
7728 (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2);
7729 width=WidgetTextWidth(font_info,(char *) title);
7730 height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1);
7731 /*
7732 Position Menu widget.
7733 */
7734 windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1);
7735 top_offset=title_height+menu_info.bevel_width-1;
7736 windows->widget.height=top_offset+number_selections*height+4;
7737 windows->widget.min_width=windows->widget.width;
7738 windows->widget.min_height=windows->widget.height;
7739 XQueryPosition(display,windows->widget.root,&x,&y);
7740 windows->widget.x=x-(QuantumMargin >> 1);
7741 if (submenu_info.active != 0)
7742 {
7743 windows->widget.x=
7744 windows->command.x+windows->command.width-QuantumMargin;
7745 toggle_info.raised=MagickTrue;
7746 XDrawTriangleEast(display,&windows->command,&toggle_info);
7747 }
cristy49e2d862010-11-12 02:50:30 +00007748 windows->widget.y=submenu_info.active == 0 ? y-(int)
cristy3ed852e2009-09-05 21:47:34 +00007749 ((3*title_height) >> 2) : y;
7750 if (submenu_info.active != 0)
7751 windows->widget.y=windows->command.y+submenu_info.y;
7752 XConstrainWindowPosition(display,&windows->widget);
7753 /*
7754 Map Menu widget.
7755 */
7756 window_attributes.override_redirect=MagickTrue;
7757 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00007758 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00007759 window_changes.width=(int) windows->widget.width;
7760 window_changes.height=(int) windows->widget.height;
7761 window_changes.x=windows->widget.x;
7762 window_changes.y=windows->widget.y;
7763 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
7764 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
7765 (void) XMapRaised(display,windows->widget.id);
7766 windows->widget.mapped=MagickFalse;
7767 /*
7768 Respond to X events.
7769 */
7770 selection_info.height=height;
7771 cursor=XCreateFontCursor(display,XC_right_ptr);
7772 (void) XCheckDefineCursor(display,windows->image.id,cursor);
7773 (void) XCheckDefineCursor(display,windows->command.id,cursor);
7774 (void) XCheckDefineCursor(display,windows->widget.id,cursor);
7775 state=UpdateConfigurationState;
7776 do
7777 {
7778 if (state & UpdateConfigurationState)
7779 {
7780 /*
7781 Initialize selection information.
7782 */
7783 XGetWidgetInfo((char *) NULL,&menu_info);
7784 menu_info.bevel_width--;
7785 menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
7786 menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
7787 menu_info.x=(int) menu_info.bevel_width;
7788 menu_info.y=(int) menu_info.bevel_width;
7789 XGetWidgetInfo((char *) NULL,&selection_info);
7790 selection_info.center=MagickFalse;
7791 selection_info.width=menu_info.width;
7792 selection_info.height=height;
7793 selection_info.x=menu_info.x;
7794 highlight_info=selection_info;
7795 highlight_info.bevel_width--;
7796 highlight_info.width-=(highlight_info.bevel_width << 1);
7797 highlight_info.height-=(highlight_info.bevel_width << 1);
7798 highlight_info.x+=highlight_info.bevel_width;
7799 state&=(~UpdateConfigurationState);
7800 }
7801 if (state & RedrawWidgetState)
7802 {
7803 /*
7804 Redraw Menu widget.
7805 */
7806 if (submenu_info.active == 0)
7807 {
7808 y=(int) title_height;
7809 XSetBevelColor(display,&windows->widget,MagickFalse);
7810 (void) XDrawLine(display,windows->widget.id,
7811 windows->widget.widget_context,selection_info.x,y-1,
7812 (int) selection_info.width,y-1);
7813 XSetBevelColor(display,&windows->widget,MagickTrue);
7814 (void) XDrawLine(display,windows->widget.id,
7815 windows->widget.widget_context,selection_info.x,y,
7816 (int) selection_info.width,y);
7817 (void) XSetFillStyle(display,windows->widget.widget_context,
7818 FillSolid);
7819 }
7820 /*
7821 Draw menu selections.
7822 */
7823 selection_info.center=MagickTrue;
7824 selection_info.y=(int) menu_info.bevel_width;
7825 selection_info.text=(char *) title;
7826 if (submenu_info.active == 0)
7827 XDrawWidgetText(display,&windows->widget,&selection_info);
7828 selection_info.center=MagickFalse;
7829 selection_info.y=(int) top_offset;
7830 for (id=0; id < (int) number_selections; id++)
7831 {
7832 selection_info.text=(char *) selections[id];
7833 XDrawWidgetText(display,&windows->widget,&selection_info);
7834 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7835 if (id == selection_info.id)
7836 XDrawBevel(display,&windows->widget,&highlight_info);
7837 selection_info.y+=(int) selection_info.height;
7838 }
7839 XDrawBevel(display,&windows->widget,&menu_info);
7840 state&=(~RedrawWidgetState);
7841 }
7842 if (number_selections > 2)
7843 {
7844 /*
7845 Redraw Menu line.
7846 */
7847 y=(int) (top_offset+selection_info.height*(number_selections-1));
7848 XSetBevelColor(display,&windows->widget,MagickFalse);
7849 (void) XDrawLine(display,windows->widget.id,
7850 windows->widget.widget_context,selection_info.x,y-1,
7851 (int) selection_info.width,y-1);
7852 XSetBevelColor(display,&windows->widget,MagickTrue);
7853 (void) XDrawLine(display,windows->widget.id,
7854 windows->widget.widget_context,selection_info.x,y,
7855 (int) selection_info.width,y);
7856 (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
7857 }
7858 /*
7859 Wait for next event.
7860 */
7861 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7862 switch (event.type)
7863 {
7864 case ButtonPress:
7865 {
7866 if (event.xbutton.window != windows->widget.id)
7867 {
7868 /*
7869 exit menu.
7870 */
7871 if (event.xbutton.window == windows->command.id)
7872 (void) XPutBackEvent(display,&event);
7873 selection_info.id=(~0);
7874 *item='\0';
7875 state|=ExitState;
7876 break;
7877 }
7878 state&=(~InactiveWidgetState);
7879 id=(event.xbutton.y-top_offset)/(int) selection_info.height;
7880 selection_info.id=id;
7881 if ((id < 0) || (id >= (int) number_selections))
7882 break;
7883 /*
7884 Highlight this selection.
7885 */
7886 selection_info.y=(int) (top_offset+id*selection_info.height);
7887 selection_info.text=(char *) selections[id];
7888 XDrawWidgetText(display,&windows->widget,&selection_info);
7889 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7890 XDrawBevel(display,&windows->widget,&highlight_info);
7891 break;
7892 }
7893 case ButtonRelease:
7894 {
7895 if (windows->widget.mapped == MagickFalse)
7896 break;
7897 if (event.xbutton.window == windows->command.id)
7898 if ((state & InactiveWidgetState) == 0)
7899 break;
7900 /*
7901 exit menu.
7902 */
7903 XSetCursorState(display,windows,MagickFalse);
7904 *item='\0';
7905 state|=ExitState;
7906 break;
7907 }
7908 case ConfigureNotify:
7909 {
7910 /*
7911 Update widget configuration.
7912 */
7913 if (event.xconfigure.window != windows->widget.id)
7914 break;
7915 if ((event.xconfigure.width == (int) windows->widget.width) &&
7916 (event.xconfigure.height == (int) windows->widget.height))
7917 break;
7918 windows->widget.width=(unsigned int)
7919 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
7920 windows->widget.height=(unsigned int)
7921 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
7922 state|=UpdateConfigurationState;
7923 break;
7924 }
7925 case EnterNotify:
7926 {
7927 if (event.xcrossing.window != windows->widget.id)
7928 break;
7929 if (event.xcrossing.state == 0)
7930 break;
7931 state&=(~InactiveWidgetState);
7932 id=((event.xcrossing.y-top_offset)/(int) selection_info.height);
7933 if ((selection_info.id >= 0) &&
7934 (selection_info.id < (int) number_selections))
7935 {
7936 /*
7937 Unhighlight last selection.
7938 */
7939 if (id == selection_info.id)
7940 break;
7941 selection_info.y=(int)
7942 (top_offset+selection_info.id*selection_info.height);
7943 selection_info.text=(char *) selections[selection_info.id];
7944 XDrawWidgetText(display,&windows->widget,&selection_info);
7945 }
7946 if ((id < 0) || (id >= (int) number_selections))
7947 break;
7948 /*
7949 Highlight this selection.
7950 */
7951 selection_info.id=id;
7952 selection_info.y=(int)
7953 (top_offset+selection_info.id*selection_info.height);
7954 selection_info.text=(char *) selections[selection_info.id];
7955 XDrawWidgetText(display,&windows->widget,&selection_info);
7956 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7957 XDrawBevel(display,&windows->widget,&highlight_info);
7958 break;
7959 }
7960 case Expose:
7961 {
7962 if (event.xexpose.window != windows->widget.id)
7963 break;
7964 if (event.xexpose.count != 0)
7965 break;
7966 state|=RedrawWidgetState;
7967 break;
7968 }
7969 case LeaveNotify:
7970 {
7971 if (event.xcrossing.window != windows->widget.id)
7972 break;
7973 state|=InactiveWidgetState;
7974 id=selection_info.id;
7975 if ((id < 0) || (id >= (int) number_selections))
7976 break;
7977 /*
7978 Unhighlight last selection.
7979 */
7980 selection_info.y=(int) (top_offset+id*selection_info.height);
7981 selection_info.id=(~0);
7982 selection_info.text=(char *) selections[id];
7983 XDrawWidgetText(display,&windows->widget,&selection_info);
7984 break;
7985 }
7986 case MotionNotify:
7987 {
7988 /*
7989 Discard pending button motion events.
7990 */
7991 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7992 if (submenu_info.active != 0)
7993 if (event.xmotion.window == windows->command.id)
7994 {
7995 if ((state & InactiveWidgetState) == 0)
7996 {
7997 if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
7998 {
7999 selection_info.id=(~0);
8000 *item='\0';
8001 state|=ExitState;
8002 break;
8003 }
8004 }
8005 else
8006 if (WindowIsActive(windows->command,event.xmotion))
8007 {
8008 selection_info.id=(~0);
8009 *item='\0';
8010 state|=ExitState;
8011 break;
8012 }
8013 }
8014 if (event.xmotion.window != windows->widget.id)
8015 break;
8016 if (state & InactiveWidgetState)
8017 break;
8018 id=(event.xmotion.y-top_offset)/(int) selection_info.height;
8019 if ((selection_info.id >= 0) &&
8020 (selection_info.id < (int) number_selections))
8021 {
8022 /*
8023 Unhighlight last selection.
8024 */
8025 if (id == selection_info.id)
8026 break;
8027 selection_info.y=(int)
8028 (top_offset+selection_info.id*selection_info.height);
8029 selection_info.text=(char *) selections[selection_info.id];
8030 XDrawWidgetText(display,&windows->widget,&selection_info);
8031 }
8032 selection_info.id=id;
8033 if ((id < 0) || (id >= (int) number_selections))
8034 break;
8035 /*
8036 Highlight this selection.
8037 */
8038 selection_info.y=(int) (top_offset+id*selection_info.height);
8039 selection_info.text=(char *) selections[id];
8040 XDrawWidgetText(display,&windows->widget,&selection_info);
8041 highlight_info.y=selection_info.y+highlight_info.bevel_width;
8042 XDrawBevel(display,&windows->widget,&highlight_info);
8043 break;
8044 }
8045 default:
8046 break;
8047 }
8048 } while ((state & ExitState) == 0);
8049 (void) XFreeCursor(display,cursor);
8050 window_attributes.override_redirect=MagickFalse;
8051 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00008052 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00008053 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8054 XCheckRefreshWindows(display,windows);
8055 if (submenu_info.active != 0)
8056 {
8057 submenu_info.active=MagickFalse;
8058 toggle_info.raised=MagickFalse;
8059 XDrawTriangleEast(display,&windows->command,&toggle_info);
8060 }
8061 if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
8062 return(~0);
8063 (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent);
8064 return(selection_info.id);
8065}
8066
8067/*
8068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8069% %
8070% %
8071% %
8072% X N o t i c e W i d g e t %
8073% %
8074% %
8075% %
8076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8077%
8078% XNoticeWidget() displays a Notice widget with a notice to the user. The
8079% function returns when the user presses the "Dismiss" button.
8080%
8081% The format of the XNoticeWidget method is:
8082%
8083% void XNoticeWidget(Display *display,XWindows *windows,
8084% const char *reason,const char *description)
8085%
8086% A description of each parameter follows:
8087%
8088% o display: Specifies a connection to an X server; returned from
8089% XOpenDisplay.
8090%
8091% o window: Specifies a pointer to a XWindows structure.
8092%
8093% o reason: Specifies the message to display before terminating the
8094% program.
8095%
8096% o description: Specifies any description to the message.
8097%
8098*/
cristybcbda3f2011-09-03 13:01:22 +00008099MagickPrivate void XNoticeWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00008100 const char *reason,const char *description)
8101{
8102#define DismissButtonText "Dismiss"
8103#define Timeout 8
8104
8105 const char
8106 *text;
8107
8108 int
8109 x,
8110 y;
8111
8112 Status
8113 status;
8114
8115 time_t
8116 timer;
8117
8118 unsigned int
8119 height,
8120 width;
8121
cristybb503372010-05-27 20:51:26 +00008122 size_t
cristy3ed852e2009-09-05 21:47:34 +00008123 state;
8124
8125 XEvent
8126 event;
8127
8128 XFontStruct
8129 *font_info;
8130
8131 XTextProperty
8132 window_name;
8133
8134 XWidgetInfo
8135 dismiss_info;
8136
8137 XWindowChanges
8138 window_changes;
8139
8140 /*
8141 Determine Notice widget attributes.
8142 */
8143 assert(display != (Display *) NULL);
8144 assert(windows != (XWindows *) NULL);
8145 assert(reason != (char *) NULL);
8146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
8147 XDelay(display,SuspendTime << 3); /* avoid surpise with delay */
8148 XSetCursorState(display,windows,MagickTrue);
8149 XCheckRefreshWindows(display,windows);
8150 font_info=windows->widget.font_info;
8151 width=WidgetTextWidth(font_info,DismissButtonText);
8152 text=GetLocaleExceptionMessage(XServerError,reason);
8153 if (text != (char *) NULL)
8154 if (WidgetTextWidth(font_info,(char *) text) > width)
8155 width=WidgetTextWidth(font_info,(char *) text);
8156 if (description != (char *) NULL)
8157 {
8158 text=GetLocaleExceptionMessage(XServerError,description);
8159 if (text != (char *) NULL)
8160 if (WidgetTextWidth(font_info,(char *) text) > width)
8161 width=WidgetTextWidth(font_info,(char *) text);
8162 }
8163 height=(unsigned int) (font_info->ascent+font_info->descent);
8164 /*
8165 Position Notice widget.
8166 */
8167 windows->widget.width=width+4*QuantumMargin;
8168 windows->widget.min_width=width+QuantumMargin;
8169 if (windows->widget.width < windows->widget.min_width)
8170 windows->widget.width=windows->widget.min_width;
8171 windows->widget.height=(unsigned int) (12*height);
8172 windows->widget.min_height=(unsigned int) (7*height);
8173 if (windows->widget.height < windows->widget.min_height)
8174 windows->widget.height=windows->widget.min_height;
8175 XConstrainWindowPosition(display,&windows->widget);
8176 /*
8177 Map Notice widget.
8178 */
8179 (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent);
8180 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8181 if (status != False)
8182 {
8183 XSetWMName(display,windows->widget.id,&window_name);
8184 XSetWMIconName(display,windows->widget.id,&window_name);
8185 (void) XFree((void *) window_name.value);
8186 }
8187 window_changes.width=(int) windows->widget.width;
8188 window_changes.height=(int) windows->widget.height;
8189 window_changes.x=windows->widget.x;
8190 window_changes.y=windows->widget.y;
8191 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8192 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8193 (void) XMapRaised(display,windows->widget.id);
8194 windows->widget.mapped=MagickFalse;
8195 (void) XBell(display,0);
8196 /*
8197 Respond to X events.
8198 */
8199 timer=time((time_t *) NULL)+Timeout;
8200 state=UpdateConfigurationState;
8201 do
8202 {
8203 if (time((time_t *) NULL) > timer)
8204 break;
8205 if (state & UpdateConfigurationState)
8206 {
8207 /*
8208 Initialize Dismiss button information.
8209 */
8210 XGetWidgetInfo(DismissButtonText,&dismiss_info);
8211 dismiss_info.width=(unsigned int) QuantumMargin+
8212 WidgetTextWidth(font_info,DismissButtonText);
8213 dismiss_info.height=(unsigned int) ((3*height) >> 1);
8214 dismiss_info.x=(int)
8215 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
8216 dismiss_info.y=(int)
8217 (windows->widget.height-(dismiss_info.height << 1));
8218 state&=(~UpdateConfigurationState);
8219 }
8220 if (state & RedrawWidgetState)
8221 {
8222 /*
8223 Redraw Notice widget.
8224 */
8225 width=WidgetTextWidth(font_info,(char *) reason);
8226 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8227 y=(int) ((windows->widget.height >> 1)-(height << 1));
8228 (void) XDrawString(display,windows->widget.id,
8229 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
8230 if (description != (char *) NULL)
8231 {
8232 width=WidgetTextWidth(font_info,(char *) description);
8233 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8234 y+=height;
8235 (void) XDrawString(display,windows->widget.id,
8236 windows->widget.annotate_context,x,y,(char *) description,
8237 Extent(description));
8238 }
8239 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8240 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8241 state&=(~RedrawWidgetState);
8242 }
8243 /*
8244 Wait for next event.
8245 */
8246 if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
8247 {
8248 /*
8249 Do not block if delay > 0.
8250 */
8251 XDelay(display,SuspendTime << 2);
8252 continue;
8253 }
8254 switch (event.type)
8255 {
8256 case ButtonPress:
8257 {
8258 if (MatteIsActive(dismiss_info,event.xbutton))
8259 {
8260 /*
8261 User pressed Dismiss button.
8262 */
8263 dismiss_info.raised=MagickFalse;
8264 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8265 break;
8266 }
8267 break;
8268 }
8269 case ButtonRelease:
8270 {
8271 if (windows->widget.mapped == MagickFalse)
8272 break;
8273 if (dismiss_info.raised == MagickFalse)
8274 {
8275 if (event.xbutton.window == windows->widget.id)
8276 if (MatteIsActive(dismiss_info,event.xbutton))
8277 state|=ExitState;
8278 dismiss_info.raised=MagickTrue;
8279 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8280 }
8281 break;
8282 }
8283 case ClientMessage:
8284 {
8285 /*
8286 If client window delete message, exit.
8287 */
8288 if (event.xclient.message_type != windows->wm_protocols)
8289 break;
8290 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8291 {
8292 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8293 (Time) event.xclient.data.l[1]);
8294 break;
8295 }
8296 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8297 break;
8298 if (event.xclient.window == windows->widget.id)
8299 {
8300 state|=ExitState;
8301 break;
8302 }
8303 break;
8304 }
8305 case ConfigureNotify:
8306 {
8307 /*
8308 Update widget configuration.
8309 */
8310 if (event.xconfigure.window != windows->widget.id)
8311 break;
8312 if ((event.xconfigure.width == (int) windows->widget.width) &&
8313 (event.xconfigure.height == (int) windows->widget.height))
8314 break;
8315 windows->widget.width=(unsigned int)
8316 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8317 windows->widget.height=(unsigned int)
8318 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8319 state|=UpdateConfigurationState;
8320 break;
8321 }
8322 case EnterNotify:
8323 {
8324 if (event.xcrossing.window != windows->widget.id)
8325 break;
8326 state&=(~InactiveWidgetState);
8327 break;
8328 }
8329 case Expose:
8330 {
8331 if (event.xexpose.window != windows->widget.id)
8332 break;
8333 if (event.xexpose.count != 0)
8334 break;
8335 state|=RedrawWidgetState;
8336 break;
8337 }
8338 case KeyPress:
8339 {
8340 static char
8341 command[MaxTextExtent];
8342
8343 static KeySym
8344 key_symbol;
8345
8346 /*
8347 Respond to a user key press.
8348 */
8349 if (event.xkey.window != windows->widget.id)
8350 break;
8351 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8352 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8353 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8354 {
8355 dismiss_info.raised=MagickFalse;
8356 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8357 state|=ExitState;
8358 break;
8359 }
8360 break;
8361 }
8362 case LeaveNotify:
8363 {
8364 if (event.xcrossing.window != windows->widget.id)
8365 break;
8366 state|=InactiveWidgetState;
8367 break;
8368 }
8369 case MotionNotify:
8370 {
8371 /*
8372 Discard pending button motion events.
8373 */
8374 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8375 if (state & InactiveWidgetState)
8376 break;
8377 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
8378 {
8379 /*
8380 Dismiss button status changed.
8381 */
8382 dismiss_info.raised=
8383 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8384 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8385 break;
8386 }
8387 break;
8388 }
8389 default:
8390 break;
8391 }
8392 } while ((state & ExitState) == 0);
8393 XSetCursorState(display,windows,MagickFalse);
8394 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8395 XCheckRefreshWindows(display,windows);
8396}
8397
8398/*
8399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8400% %
8401% %
8402% %
8403% X P r e f e r e n c e s W i d g e t %
8404% %
8405% %
8406% %
8407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8408%
8409% XPreferencesWidget() displays a Preferences widget with program preferences.
8410% If the user presses the Apply button, the preferences are stored in a
8411% configuration file in the users' home directory.
8412%
8413% The format of the XPreferencesWidget method is:
8414%
8415% MagickBooleanType XPreferencesWidget(Display *display,
8416% XResourceInfo *resource_info,XWindows *windows)
8417%
8418% A description of each parameter follows:
8419%
8420% o display: Specifies a connection to an X server; returned from
8421% XOpenDisplay.
8422%
8423% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8424%
8425% o window: Specifies a pointer to a XWindows structure.
8426%
8427*/
cristybcbda3f2011-09-03 13:01:22 +00008428MagickPrivate MagickBooleanType XPreferencesWidget(Display *display,
cristy3ed852e2009-09-05 21:47:34 +00008429 XResourceInfo *resource_info,XWindows *windows)
8430{
8431#define ApplyButtonText "Apply"
8432#define CacheButtonText "%lu mega-bytes of memory in the undo edit cache "
8433#define CancelButtonText "Cancel"
8434#define NumberPreferences 8
8435
8436 static const char
8437 *Preferences[] =
8438 {
8439 "display image centered on a backdrop",
8440 "confirm on program exit",
8441 "confirm on image edits",
8442 "correct image for display gamma",
8443 "display warning messages",
8444 "apply Floyd/Steinberg error diffusion to image",
8445 "use a shared colormap for colormapped X visuals",
8446 "display images as an X server pixmap"
8447 };
8448
8449 char
8450 cache[MaxTextExtent];
8451
8452 int
8453 x,
8454 y;
8455
8456 register int
8457 i;
8458
8459 Status
8460 status;
8461
8462 unsigned int
8463 height,
8464 text_width,
8465 width;
8466
cristybb503372010-05-27 20:51:26 +00008467 size_t
cristy3ed852e2009-09-05 21:47:34 +00008468 state;
8469
8470 XEvent
8471 event;
8472
8473 XFontStruct
8474 *font_info;
8475
8476 XTextProperty
8477 window_name;
8478
8479 XWidgetInfo
8480 apply_info,
8481 cache_info,
8482 cancel_info,
8483 preferences_info[NumberPreferences];
8484
8485 XWindowChanges
8486 window_changes;
8487
8488 /*
8489 Determine Preferences widget attributes.
8490 */
8491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
8492 assert(display != (Display *) NULL);
8493 assert(resource_info != (XResourceInfo *) NULL);
8494 assert(windows != (XWindows *) NULL);
8495 XCheckRefreshWindows(display,windows);
8496 font_info=windows->widget.font_info;
8497 text_width=WidgetTextWidth(font_info,CacheButtonText);
8498 for (i=0; i < NumberPreferences; i++)
8499 if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
8500 text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
8501 width=WidgetTextWidth(font_info,ApplyButtonText);
8502 if (WidgetTextWidth(font_info,CancelButtonText) > width)
8503 width=WidgetTextWidth(font_info,CancelButtonText);
8504 width+=(unsigned int) QuantumMargin;
8505 height=(unsigned int) (font_info->ascent+font_info->descent);
8506 /*
8507 Position Preferences widget.
8508 */
8509 windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
8510 (int) text_width)+6*QuantumMargin);
8511 windows->widget.min_width=(width << 1)+QuantumMargin;
8512 if (windows->widget.width < windows->widget.min_width)
8513 windows->widget.width=windows->widget.min_width;
8514 windows->widget.height=(unsigned int)
8515 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8516 windows->widget.min_height=(unsigned int)
8517 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8518 if (windows->widget.height < windows->widget.min_height)
8519 windows->widget.height=windows->widget.min_height;
8520 XConstrainWindowPosition(display,&windows->widget);
8521 /*
8522 Map Preferences widget.
8523 */
8524 (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent);
8525 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8526 if (status != False)
8527 {
8528 XSetWMName(display,windows->widget.id,&window_name);
8529 XSetWMIconName(display,windows->widget.id,&window_name);
8530 (void) XFree((void *) window_name.value);
8531 }
8532 window_changes.width=(int) windows->widget.width;
8533 window_changes.height=(int) windows->widget.height;
8534 window_changes.x=windows->widget.x;
8535 window_changes.y=windows->widget.y;
8536 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8537 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8538 (void) XMapRaised(display,windows->widget.id);
8539 windows->widget.mapped=MagickFalse;
8540 /*
8541 Respond to X events.
8542 */
8543 state=UpdateConfigurationState;
8544 XSetCursorState(display,windows,MagickTrue);
8545 do
8546 {
8547 if (state & UpdateConfigurationState)
8548 {
8549 /*
8550 Initialize button information.
8551 */
8552 XGetWidgetInfo(CancelButtonText,&cancel_info);
8553 cancel_info.width=width;
8554 cancel_info.height=(unsigned int) (3*height) >> 1;
8555 cancel_info.x=(int) windows->widget.width-cancel_info.width-
8556 (QuantumMargin << 1);
8557 cancel_info.y=(int) windows->widget.height-
8558 cancel_info.height-QuantumMargin;
8559 XGetWidgetInfo(ApplyButtonText,&apply_info);
8560 apply_info.width=width;
8561 apply_info.height=(unsigned int) (3*height) >> 1;
8562 apply_info.x=QuantumMargin << 1;
8563 apply_info.y=cancel_info.y;
8564 y=(int) (height << 1);
8565 for (i=0; i < NumberPreferences; i++)
8566 {
8567 XGetWidgetInfo(Preferences[i],&preferences_info[i]);
8568 preferences_info[i].bevel_width--;
8569 preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
8570 preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
8571 preferences_info[i].x=QuantumMargin << 1;
8572 preferences_info[i].y=y;
8573 y+=height+(QuantumMargin >> 1);
8574 }
8575 preferences_info[0].raised=resource_info->backdrop ==
8576 MagickFalse ? MagickTrue : MagickFalse;
8577 preferences_info[1].raised=resource_info->confirm_exit ==
8578 MagickFalse ? MagickTrue : MagickFalse;
8579 preferences_info[2].raised=resource_info->confirm_edit ==
8580 MagickFalse ? MagickTrue : MagickFalse;
8581 preferences_info[3].raised=resource_info->gamma_correct ==
8582 MagickFalse ? MagickTrue : MagickFalse;
8583 preferences_info[4].raised=resource_info->display_warnings ==
8584 MagickFalse ? MagickTrue : MagickFalse;
8585 preferences_info[5].raised=resource_info->quantize_info->dither ==
8586 MagickFalse ? MagickTrue : MagickFalse;
8587 preferences_info[6].raised=resource_info->colormap !=
8588 SharedColormap ? MagickTrue : MagickFalse;
8589 preferences_info[7].raised=resource_info->use_pixmap ==
8590 MagickFalse ? MagickTrue : MagickFalse;
cristyb51dff52011-05-19 16:55:47 +00008591 (void) FormatLocaleString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008592 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008593 XGetWidgetInfo(cache,&cache_info);
8594 cache_info.bevel_width--;
8595 cache_info.width=(unsigned int) QuantumMargin >> 1;
8596 cache_info.height=(unsigned int) QuantumMargin >> 1;
8597 cache_info.x=QuantumMargin << 1;
8598 cache_info.y=y;
8599 state&=(~UpdateConfigurationState);
8600 }
8601 if (state & RedrawWidgetState)
8602 {
8603 /*
8604 Redraw Preferences widget.
8605 */
8606 XDrawBeveledButton(display,&windows->widget,&apply_info);
8607 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8608 for (i=0; i < NumberPreferences; i++)
8609 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8610 XDrawTriangleEast(display,&windows->widget,&cache_info);
8611 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8612 state&=(~RedrawWidgetState);
8613 }
8614 /*
8615 Wait for next event.
8616 */
8617 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
8618 switch (event.type)
8619 {
8620 case ButtonPress:
8621 {
8622 if (MatteIsActive(apply_info,event.xbutton))
8623 {
8624 /*
8625 User pressed Apply button.
8626 */
8627 apply_info.raised=MagickFalse;
8628 XDrawBeveledButton(display,&windows->widget,&apply_info);
8629 break;
8630 }
8631 if (MatteIsActive(cancel_info,event.xbutton))
8632 {
8633 /*
8634 User pressed Cancel button.
8635 */
8636 cancel_info.raised=MagickFalse;
8637 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8638 break;
8639 }
8640 for (i=0; i < NumberPreferences; i++)
8641 if (MatteIsActive(preferences_info[i],event.xbutton))
8642 {
8643 /*
8644 User pressed a Preferences button.
8645 */
8646 preferences_info[i].raised=preferences_info[i].raised ==
8647 MagickFalse ? MagickTrue : MagickFalse;
8648 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8649 break;
8650 }
8651 if (MatteIsActive(cache_info,event.xbutton))
8652 {
8653 /*
8654 User pressed Cache button.
8655 */
8656 x=cache_info.x+cache_info.width+cache_info.bevel_width+
8657 (QuantumMargin >> 1);
8658 y=cache_info.y+((cache_info.height-height) >> 1);
8659 width=WidgetTextWidth(font_info,cache);
8660 (void) XClearArea(display,windows->widget.id,x,y,width,height,
8661 False);
8662 resource_info->undo_cache<<=1;
8663 if (resource_info->undo_cache > 256)
8664 resource_info->undo_cache=1;
cristyb51dff52011-05-19 16:55:47 +00008665 (void) FormatLocaleString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008666 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008667 cache_info.raised=MagickFalse;
8668 XDrawTriangleEast(display,&windows->widget,&cache_info);
8669 break;
8670 }
8671 break;
8672 }
8673 case ButtonRelease:
8674 {
8675 if (windows->widget.mapped == MagickFalse)
8676 break;
8677 if (apply_info.raised == MagickFalse)
8678 {
8679 if (event.xbutton.window == windows->widget.id)
8680 if (MatteIsActive(apply_info,event.xbutton))
8681 state|=ExitState;
8682 apply_info.raised=MagickTrue;
8683 XDrawBeveledButton(display,&windows->widget,&apply_info);
8684 apply_info.raised=MagickFalse;
8685 }
8686 if (cancel_info.raised == MagickFalse)
8687 {
8688 if (event.xbutton.window == windows->widget.id)
8689 if (MatteIsActive(cancel_info,event.xbutton))
8690 state|=ExitState;
8691 cancel_info.raised=MagickTrue;
8692 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8693 }
8694 if (cache_info.raised == MagickFalse)
8695 {
8696 cache_info.raised=MagickTrue;
8697 XDrawTriangleEast(display,&windows->widget,&cache_info);
8698 }
8699 break;
8700 }
8701 case ClientMessage:
8702 {
8703 /*
8704 If client window delete message, exit.
8705 */
8706 if (event.xclient.message_type != windows->wm_protocols)
8707 break;
8708 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8709 {
8710 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8711 (Time) event.xclient.data.l[1]);
8712 break;
8713 }
8714 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8715 break;
8716 if (event.xclient.window == windows->widget.id)
8717 {
8718 state|=ExitState;
8719 break;
8720 }
8721 break;
8722 }
8723 case ConfigureNotify:
8724 {
8725 /*
8726 Update widget configuration.
8727 */
8728 if (event.xconfigure.window != windows->widget.id)
8729 break;
8730 if ((event.xconfigure.width == (int) windows->widget.width) &&
8731 (event.xconfigure.height == (int) windows->widget.height))
8732 break;
8733 windows->widget.width=(unsigned int)
8734 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8735 windows->widget.height=(unsigned int)
8736 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8737 state|=UpdateConfigurationState;
8738 break;
8739 }
8740 case EnterNotify:
8741 {
8742 if (event.xcrossing.window != windows->widget.id)
8743 break;
8744 state&=(~InactiveWidgetState);
8745 break;
8746 }
8747 case Expose:
8748 {
8749 if (event.xexpose.window != windows->widget.id)
8750 break;
8751 if (event.xexpose.count != 0)
8752 break;
8753 state|=RedrawWidgetState;
8754 break;
8755 }
8756 case KeyPress:
8757 {
8758 static char
8759 command[MaxTextExtent];
8760
8761 static KeySym
8762 key_symbol;
8763
8764 /*
8765 Respond to a user key press.
8766 */
8767 if (event.xkey.window != windows->widget.id)
8768 break;
8769 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8770 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8771 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8772 {
8773 apply_info.raised=MagickFalse;
8774 XDrawBeveledButton(display,&windows->widget,&apply_info);
8775 state|=ExitState;
8776 break;
8777 }
8778 break;
8779 }
8780 case LeaveNotify:
8781 {
8782 if (event.xcrossing.window != windows->widget.id)
8783 break;
8784 state|=InactiveWidgetState;
8785 break;
8786 }
8787 case MotionNotify:
8788 {
8789 /*
8790 Discard pending button motion events.
8791 */
8792 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8793 if (state & InactiveWidgetState)
8794 break;
8795 if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
8796 {
8797 /*
8798 Apply button status changed.
8799 */
8800 apply_info.raised=
8801 apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8802 XDrawBeveledButton(display,&windows->widget,&apply_info);
8803 break;
8804 }
8805 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
8806 {
8807 /*
8808 Cancel button status changed.
8809 */
8810 cancel_info.raised=
8811 cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8812 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8813 break;
8814 }
8815 break;
8816 }
8817 default:
8818 break;
8819 }
8820 } while ((state & ExitState) == 0);
8821 XSetCursorState(display,windows,MagickFalse);
8822 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8823 XCheckRefreshWindows(display,windows);
8824 if (apply_info.raised)
8825 return(MagickFalse);
8826 /*
8827 Save user preferences to the client configuration file.
8828 */
8829 resource_info->backdrop=
8830 preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
8831 resource_info->confirm_exit=
8832 preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
8833 resource_info->confirm_edit=
8834 preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
8835 resource_info->gamma_correct=
8836 preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
8837 resource_info->display_warnings=
8838 preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
8839 resource_info->quantize_info->dither=
8840 preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse;
8841 resource_info->colormap=SharedColormap;
8842 if (preferences_info[6].raised)
8843 resource_info->colormap=PrivateColormap;
8844 resource_info->use_pixmap=
8845 preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
8846 XUserPreferences(resource_info);
8847 return(MagickTrue);
8848}
8849
8850/*
8851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8852% %
8853% %
8854% %
8855% X P r o g r e s s M o n i t o r W i d g e t %
8856% %
8857% %
8858% %
8859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8860%
8861% XProgressMonitorWidget() displays the progress a task is making in
8862% completing a task. A span of zero toggles the active status. An inactive
8863% state disables the progress monitor.
8864%
8865% The format of the XProgressMonitorWidget method is:
8866%
8867% void XProgressMonitorWidget(Display *display,XWindows *windows,
8868% const char *task,const MagickOffsetType offset,
8869% const MagickSizeType span)
8870%
8871% A description of each parameter follows:
8872%
8873% o display: Specifies a connection to an X server; returned from
8874% XOpenDisplay.
8875%
8876% o window: Specifies a pointer to a XWindows structure.
8877%
8878% o task: Identifies the task in progress.
8879%
8880% o offset: Specifies the offset position within the span which represents
8881% how much progress has been made in completing a task.
8882%
8883% o span: Specifies the span relative to completing a task.
8884%
8885*/
cristybcbda3f2011-09-03 13:01:22 +00008886MagickPrivate void XProgressMonitorWidget(Display *display,XWindows *windows,
cristy3ed852e2009-09-05 21:47:34 +00008887 const char *task,const MagickOffsetType offset,const MagickSizeType span)
8888{
8889 unsigned int
8890 width;
8891
8892 XEvent
8893 event;
8894
8895 assert(display != (Display *) NULL);
8896 assert(windows != (XWindows *) NULL);
8897 assert(task != (const char *) NULL);
8898 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
8899 if (span == 0)
8900 return;
8901 /*
8902 Update image windows if there is a pending expose event.
8903 */
8904 while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
8905 (void) XCommandWidget(display,windows,(const char **) NULL,&event);
8906 while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
8907 XRefreshWindow(display,&windows->image,&event);
8908 while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
8909 if (monitor_info.text != (char *) NULL)
8910 XInfoWidget(display,windows,monitor_info.text);
8911 /*
8912 Draw progress monitor bar to represent percent completion of a task.
8913 */
8914 if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
8915 XInfoWidget(display,windows,task);
8916 width=(unsigned int) (((offset+1)*(windows->info.width-
8917 (2*monitor_info.x)))/span);
8918 if (width < monitor_info.width)
8919 {
8920 monitor_info.raised=MagickTrue;
8921 XDrawWidgetText(display,&windows->info,&monitor_info);
8922 monitor_info.raised=MagickFalse;
8923 }
8924 monitor_info.width=width;
8925 XDrawWidgetText(display,&windows->info,&monitor_info);
8926 (void) XFlush(display);
8927}
8928
8929/*
8930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8931% %
8932% %
8933% %
8934% X T e x t V i e w W i d g e t %
8935% %
8936% %
8937% %
8938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8939%
8940% XTextViewWidget() displays text in a Text View widget.
8941%
8942% The format of the XTextViewWidget method is:
8943%
8944% void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
8945% XWindows *windows,const MagickBooleanType mono,const char *title,
8946% const char **textlist)
8947%
8948% A description of each parameter follows:
8949%
8950% o display: Specifies a connection to an X server; returned from
8951% XOpenDisplay.
8952%
8953% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8954%
8955% o window: Specifies a pointer to a XWindows structure.
8956%
8957% o mono: Use mono-spaced font when displaying text.
8958%
8959% o title: This character string is displayed at the top of the widget
8960% window.
8961%
8962% o textlist: This string list is displayed within the Text View widget.
8963%
8964*/
cristybcbda3f2011-09-03 13:01:22 +00008965MagickPrivate void XTextViewWidget(Display *display,
cristy3ed852e2009-09-05 21:47:34 +00008966 const XResourceInfo *resource_info,XWindows *windows,
8967 const MagickBooleanType mono,const char *title,const char **textlist)
8968{
8969#define DismissButtonText "Dismiss"
8970
8971 char
8972 primary_selection[MaxTextExtent];
8973
8974 register int
8975 i;
8976
8977 static MagickStatusType
8978 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
8979
8980 Status
8981 status;
8982
8983 unsigned int
8984 height,
8985 lines,
8986 text_width,
8987 visible_lines,
8988 width;
8989
cristybb503372010-05-27 20:51:26 +00008990 size_t
cristy3ed852e2009-09-05 21:47:34 +00008991 delay,
8992 state;
8993
8994 XEvent
8995 event;
8996
8997 XFontStruct
8998 *font_info,
8999 *text_info;
9000
9001 XTextProperty
9002 window_name;
9003
9004 XWidgetInfo
9005 dismiss_info,
9006 expose_info,
9007 list_info,
9008 north_info,
9009 scroll_info,
9010 selection_info,
9011 slider_info,
9012 south_info;
9013
9014 XWindowChanges
9015 window_changes;
9016
9017 /*
9018 Convert text string to a text list.
9019 */
9020 assert(display != (Display *) NULL);
9021 assert(resource_info != (XResourceInfo *) NULL);
9022 assert(windows != (XWindows *) NULL);
9023 assert(title != (const char *) NULL);
9024 assert(textlist != (const char **) NULL);
9025 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
9026 XSetCursorState(display,windows,MagickTrue);
9027 XCheckRefreshWindows(display,windows);
9028 if (textlist == (const char **) NULL)
9029 {
9030 XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
9031 return;
9032 }
9033 /*
9034 Determine Text View widget attributes.
9035 */
9036 font_info=windows->widget.font_info;
9037 text_info=(XFontStruct *) NULL;
9038 if (mono != MagickFalse)
9039 text_info=XBestFont(display,resource_info,MagickTrue);
9040 if (text_info == (XFontStruct *) NULL)
9041 text_info=windows->widget.font_info;
9042 text_width=0;
9043 for (i=0; textlist[i] != (char *) NULL; i++)
9044 if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
9045 text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
9046 MagickMin(Extent(textlist[i]),160));
9047 lines=(unsigned int) i;
9048 width=WidgetTextWidth(font_info,DismissButtonText);
9049 width+=QuantumMargin;
9050 height=(unsigned int) (text_info->ascent+text_info->descent);
9051 /*
9052 Position Text View widget.
9053 */
9054 windows->widget.width=(unsigned int) (MagickMin((int) text_width,
9055 (int) MaxTextWidth)+5*QuantumMargin);
9056 windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
9057 if (windows->widget.width < windows->widget.min_width)
9058 windows->widget.width=windows->widget.min_width;
9059 windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
9060 height+((13*height) >> 1)+((9*QuantumMargin) >> 1));
9061 windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9*
9062 QuantumMargin) >> 1));
9063 if (windows->widget.height < windows->widget.min_height)
9064 windows->widget.height=windows->widget.min_height;
9065 XConstrainWindowPosition(display,&windows->widget);
9066 /*
9067 Map Text View widget.
9068 */
9069 (void) CopyMagickString(windows->widget.name,title,MaxTextExtent);
9070 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
9071 if (status != False)
9072 {
9073 XSetWMName(display,windows->widget.id,&window_name);
9074 XSetWMIconName(display,windows->widget.id,&window_name);
9075 (void) XFree((void *) window_name.value);
9076 }
9077 window_changes.width=(int) windows->widget.width;
9078 window_changes.height=(int) windows->widget.height;
9079 window_changes.x=windows->widget.x;
9080 window_changes.y=windows->widget.y;
9081 (void) XReconfigureWMWindow(display,windows->widget.id,
9082 windows->widget.screen,(unsigned int) mask,&window_changes);
9083 (void) XMapRaised(display,windows->widget.id);
9084 windows->widget.mapped=MagickFalse;
9085 /*
9086 Respond to X events.
9087 */
9088 XGetWidgetInfo((char *) NULL,&slider_info);
9089 XGetWidgetInfo((char *) NULL,&north_info);
9090 XGetWidgetInfo((char *) NULL,&south_info);
9091 XGetWidgetInfo((char *) NULL,&expose_info);
9092 visible_lines=0;
9093 delay=SuspendTime << 2;
9094 height=(unsigned int) (font_info->ascent+font_info->descent);
9095 state=UpdateConfigurationState;
9096 do
9097 {
9098 if (state & UpdateConfigurationState)
9099 {
9100 int
9101 id;
9102
9103 /*
9104 Initialize button information.
9105 */
9106 XGetWidgetInfo(DismissButtonText,&dismiss_info);
9107 dismiss_info.width=width;
9108 dismiss_info.height=(unsigned int) ((3*height) >> 1);
9109 dismiss_info.x=(int) windows->widget.width-dismiss_info.width-
9110 QuantumMargin-2;
9111 dismiss_info.y=(int) windows->widget.height-dismiss_info.height-
9112 QuantumMargin;
9113 /*
9114 Initialize scroll information.
9115 */
9116 XGetWidgetInfo((char *) NULL,&scroll_info);
9117 scroll_info.bevel_width--;
9118 scroll_info.width=height;
9119 scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
9120 1));
9121 scroll_info.x=(int) windows->widget.width-QuantumMargin-
9122 scroll_info.width;
9123 scroll_info.y=(3*QuantumMargin) >> 1;
9124 scroll_info.raised=MagickFalse;
9125 scroll_info.trough=MagickTrue;
9126 north_info=scroll_info;
9127 north_info.raised=MagickTrue;
9128 north_info.width-=(north_info.bevel_width << 1);
9129 north_info.height=north_info.width-1;
9130 north_info.x+=north_info.bevel_width;
9131 north_info.y+=north_info.bevel_width;
9132 south_info=north_info;
9133 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
9134 south_info.height;
9135 id=slider_info.id;
9136 slider_info=north_info;
9137 slider_info.id=id;
9138 slider_info.width-=2;
9139 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
9140 slider_info.bevel_width+2;
9141 slider_info.height=scroll_info.height-((slider_info.min_y-
9142 scroll_info.y+1) << 1)+4;
9143 visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+
9144 ((text_info->ascent+text_info->descent) >> 3));
9145 if (lines > visible_lines)
9146 slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
9147 lines;
9148 slider_info.max_y=south_info.y-south_info.bevel_width-
9149 slider_info.bevel_width-2;
9150 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
9151 slider_info.y=slider_info.min_y;
9152 expose_info=scroll_info;
9153 expose_info.y=slider_info.y;
9154 /*
9155 Initialize list information.
9156 */
9157 XGetWidgetInfo((char *) NULL,&list_info);
9158 list_info.raised=MagickFalse;
9159 list_info.bevel_width--;
9160 list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1);
9161 list_info.height=scroll_info.height;
9162 list_info.x=QuantumMargin;
9163 list_info.y=scroll_info.y;
9164 /*
9165 Initialize selection information.
9166 */
9167 XGetWidgetInfo((char *) NULL,&selection_info);
9168 selection_info.center=MagickFalse;
9169 selection_info.width=list_info.width;
9170 selection_info.height=(unsigned int)
9171 (9*(text_info->ascent+text_info->descent)) >> 3;
9172 selection_info.x=list_info.x;
9173 state&=(~UpdateConfigurationState);
9174 }
9175 if (state & RedrawWidgetState)
9176 {
9177 /*
9178 Redraw Text View window.
9179 */
9180 XDrawBeveledMatte(display,&windows->widget,&list_info);
9181 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
9182 XDrawTriangleNorth(display,&windows->widget,&north_info);
9183 XDrawBeveledButton(display,&windows->widget,&slider_info);
9184 XDrawTriangleSouth(display,&windows->widget,&south_info);
9185 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9186 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
9187 selection_info.id=(~0);
9188 state|=RedrawListState;
9189 state&=(~RedrawWidgetState);
9190 }
9191 if (state & RedrawListState)
9192 {
9193 /*
9194 Determine slider id and position.
9195 */
9196 if (slider_info.id >= (int) (lines-visible_lines))
9197 slider_info.id=(int) lines-visible_lines;
9198 if ((slider_info.id < 0) || (lines <= visible_lines))
9199 slider_info.id=0;
9200 slider_info.y=slider_info.min_y;
9201 if (lines != 0)
9202 slider_info.y+=
9203 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
9204 if (slider_info.id != selection_info.id)
9205 {
9206 /*
9207 Redraw scroll bar and text.
9208 */
9209 windows->widget.font_info=text_info;
9210 (void) XSetFont(display,windows->widget.annotate_context,
9211 text_info->fid);
9212 (void) XSetFont(display,windows->widget.highlight_context,
9213 text_info->fid);
9214 selection_info.id=slider_info.id;
9215 selection_info.y=list_info.y+(height >> 3)+2;
9216 for (i=0; i < (int) visible_lines; i++)
9217 {
9218 selection_info.raised=
9219 (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
9220 selection_info.text=(char *) NULL;
9221 if ((slider_info.id+i) < (int) lines)
9222 selection_info.text=(char *) textlist[slider_info.id+i];
9223 XDrawWidgetText(display,&windows->widget,&selection_info);
9224 selection_info.y+=(int) selection_info.height;
9225 }
9226 windows->widget.font_info=font_info;
9227 (void) XSetFont(display,windows->widget.annotate_context,
9228 font_info->fid);
9229 (void) XSetFont(display,windows->widget.highlight_context,
9230 font_info->fid);
9231 /*
9232 Update slider.
9233 */
9234 if (slider_info.y > expose_info.y)
9235 {
9236 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
9237 expose_info.y=slider_info.y-expose_info.height-
9238 slider_info.bevel_width-1;
9239 }
9240 else
9241 {
9242 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
9243 expose_info.y=slider_info.y+slider_info.height+
9244 slider_info.bevel_width+1;
9245 }
9246 XDrawTriangleNorth(display,&windows->widget,&north_info);
9247 XDrawMatte(display,&windows->widget,&expose_info);
9248 XDrawBeveledButton(display,&windows->widget,&slider_info);
9249 XDrawTriangleSouth(display,&windows->widget,&south_info);
9250 expose_info.y=slider_info.y;
9251 }
9252 state&=(~RedrawListState);
9253 }
9254 /*
9255 Wait for next event.
9256 */
9257 if (north_info.raised && south_info.raised)
9258 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
9259 else
9260 {
9261 /*
9262 Brief delay before advancing scroll bar.
9263 */
9264 XDelay(display,delay);
9265 delay=SuspendTime;
9266 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
9267 if (north_info.raised == MagickFalse)
9268 if (slider_info.id > 0)
9269 {
9270 /*
9271 Move slider up.
9272 */
9273 slider_info.id--;
9274 state|=RedrawListState;
9275 }
9276 if (south_info.raised == MagickFalse)
9277 if (slider_info.id < (int) lines)
9278 {
9279 /*
9280 Move slider down.
9281 */
9282 slider_info.id++;
9283 state|=RedrawListState;
9284 }
9285 if (event.type != ButtonRelease)
9286 continue;
9287 }
9288 switch (event.type)
9289 {
9290 case ButtonPress:
9291 {
9292 if (MatteIsActive(slider_info,event.xbutton))
9293 {
9294 /*
9295 Track slider.
9296 */
9297 slider_info.active=MagickTrue;
9298 break;
9299 }
9300 if (MatteIsActive(north_info,event.xbutton))
9301 if (slider_info.id > 0)
9302 {
9303 /*
9304 Move slider up.
9305 */
9306 north_info.raised=MagickFalse;
9307 slider_info.id--;
9308 state|=RedrawListState;
9309 break;
9310 }
9311 if (MatteIsActive(south_info,event.xbutton))
9312 if (slider_info.id < (int) lines)
9313 {
9314 /*
9315 Move slider down.
9316 */
9317 south_info.raised=MagickFalse;
9318 slider_info.id++;
9319 state|=RedrawListState;
9320 break;
9321 }
9322 if (MatteIsActive(scroll_info,event.xbutton))
9323 {
9324 /*
9325 Move slider.
9326 */
9327 if (event.xbutton.y < slider_info.y)
9328 slider_info.id-=(visible_lines-1);
9329 else
9330 slider_info.id+=(visible_lines-1);
9331 state|=RedrawListState;
9332 break;
9333 }
9334 if (MatteIsActive(dismiss_info,event.xbutton))
9335 {
9336 /*
9337 User pressed Dismiss button.
9338 */
9339 dismiss_info.raised=MagickFalse;
9340 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9341 break;
9342 }
9343 if (MatteIsActive(list_info,event.xbutton))
9344 {
9345 int
9346 id;
9347
9348 static Time
9349 click_time;
9350
9351 /*
9352 User pressed list matte.
9353 */
9354 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
9355 selection_info.height;
9356 if (id >= (int) lines)
9357 break;
9358 if (id != list_info.id)
9359 {
9360 list_info.id=id;
9361 click_time=event.xbutton.time;
9362 break;
9363 }
9364 list_info.id=id;
9365 if (event.xbutton.time >= (click_time+DoubleClick))
9366 {
9367 click_time=event.xbutton.time;
9368 break;
9369 }
9370 click_time=event.xbutton.time;
9371 /*
9372 Become the XA_PRIMARY selection owner.
9373 */
9374 (void) CopyMagickString(primary_selection,textlist[list_info.id],
9375 MaxTextExtent);
9376 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
9377 event.xbutton.time);
9378 if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
9379 break;
9380 selection_info.id=(~0);
9381 list_info.id=id;
9382 state|=RedrawListState;
9383 break;
9384 }
9385 break;
9386 }
9387 case ButtonRelease:
9388 {
9389 if (windows->widget.mapped == MagickFalse)
9390 break;
9391 if (north_info.raised == MagickFalse)
9392 {
9393 /*
9394 User released up button.
9395 */
9396 delay=SuspendTime << 2;
9397 north_info.raised=MagickTrue;
9398 XDrawTriangleNorth(display,&windows->widget,&north_info);
9399 }
9400 if (south_info.raised == MagickFalse)
9401 {
9402 /*
9403 User released down button.
9404 */
9405 delay=SuspendTime << 2;
9406 south_info.raised=MagickTrue;
9407 XDrawTriangleSouth(display,&windows->widget,&south_info);
9408 }
9409 if (slider_info.active)
9410 {
9411 /*
9412 Stop tracking slider.
9413 */
9414 slider_info.active=MagickFalse;
9415 break;
9416 }
9417 if (dismiss_info.raised == MagickFalse)
9418 {
9419 if (event.xbutton.window == windows->widget.id)
9420 if (MatteIsActive(dismiss_info,event.xbutton))
9421 state|=ExitState;
9422 dismiss_info.raised=MagickTrue;
9423 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9424 }
9425 break;
9426 }
9427 case ClientMessage:
9428 {
9429 /*
9430 If client window delete message, exit.
9431 */
9432 if (event.xclient.message_type != windows->wm_protocols)
9433 break;
9434 if (*event.xclient.data.l == (int) windows->wm_take_focus)
9435 {
9436 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
9437 (Time) event.xclient.data.l[1]);
9438 break;
9439 }
9440 if (*event.xclient.data.l != (int) windows->wm_delete_window)
9441 break;
9442 if (event.xclient.window == windows->widget.id)
9443 {
9444 state|=ExitState;
9445 break;
9446 }
9447 break;
9448 }
9449 case ConfigureNotify:
9450 {
9451 /*
9452 Update widget configuration.
9453 */
9454 if (event.xconfigure.window != windows->widget.id)
9455 break;
9456 if ((event.xconfigure.width == (int) windows->widget.width) &&
9457 (event.xconfigure.height == (int) windows->widget.height))
9458 break;
9459 windows->widget.width=(unsigned int)
9460 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
9461 windows->widget.height=(unsigned int)
9462 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
9463 state|=UpdateConfigurationState;
9464 break;
9465 }
9466 case EnterNotify:
9467 {
9468 if (event.xcrossing.window != windows->widget.id)
9469 break;
9470 state&=(~InactiveWidgetState);
9471 break;
9472 }
9473 case Expose:
9474 {
9475 if (event.xexpose.window != windows->widget.id)
9476 break;
9477 if (event.xexpose.count != 0)
9478 break;
9479 state|=RedrawWidgetState;
9480 break;
9481 }
9482 case KeyPress:
9483 {
9484 static char
9485 command[MaxTextExtent];
9486
9487 static int
9488 length;
9489
9490 static KeySym
9491 key_symbol;
9492
9493 /*
9494 Respond to a user key press.
9495 */
9496 if (event.xkey.window != windows->widget.id)
9497 break;
9498 length=XLookupString((XKeyEvent *) &event.xkey,command,
9499 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9500 *(command+length)='\0';
9501 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
9502 {
9503 dismiss_info.raised=MagickFalse;
9504 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9505 state|=ExitState;
9506 break;
9507 }
9508 if (AreaIsActive(scroll_info,event.xkey))
9509 {
9510 /*
9511 Move slider.
9512 */
9513 switch ((int) key_symbol)
9514 {
9515 case XK_Home:
9516 case XK_KP_Home:
9517 {
9518 slider_info.id=0;
9519 break;
9520 }
9521 case XK_Up:
9522 case XK_KP_Up:
9523 {
9524 slider_info.id--;
9525 break;
9526 }
9527 case XK_Down:
9528 case XK_KP_Down:
9529 {
9530 slider_info.id++;
9531 break;
9532 }
9533 case XK_Prior:
9534 case XK_KP_Prior:
9535 {
9536 slider_info.id-=visible_lines;
9537 break;
9538 }
9539 case XK_Next:
9540 case XK_KP_Next:
9541 {
9542 slider_info.id+=visible_lines;
9543 break;
9544 }
9545 case XK_End:
9546 case XK_KP_End:
9547 {
9548 slider_info.id=(int) lines;
9549 break;
9550 }
9551 }
9552 state|=RedrawListState;
9553 break;
9554 }
9555 break;
9556 }
9557 case KeyRelease:
9558 break;
9559 case LeaveNotify:
9560 {
9561 if (event.xcrossing.window != windows->widget.id)
9562 break;
9563 state|=InactiveWidgetState;
9564 break;
9565 }
9566 case MapNotify:
9567 {
9568 mask&=(~CWX);
9569 mask&=(~CWY);
9570 break;
9571 }
9572 case MotionNotify:
9573 {
9574 /*
9575 Discard pending button motion events.
9576 */
9577 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
9578 if (slider_info.active)
9579 {
9580 /*
9581 Move slider matte.
9582 */
9583 slider_info.y=event.xmotion.y-
9584 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
9585 if (slider_info.y < slider_info.min_y)
9586 slider_info.y=slider_info.min_y;
9587 if (slider_info.y > slider_info.max_y)
9588 slider_info.y=slider_info.max_y;
9589 slider_info.id=0;
9590 if (slider_info.y != slider_info.min_y)
9591 slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/
9592 (slider_info.max_y-slider_info.min_y+1);
9593 state|=RedrawListState;
9594 break;
9595 }
9596 if (state & InactiveWidgetState)
9597 break;
9598 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
9599 {
9600 /*
9601 Dismiss button status changed.
9602 */
9603 dismiss_info.raised=
9604 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
9605 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9606 break;
9607 }
9608 break;
9609 }
9610 case SelectionClear:
9611 {
9612 list_info.id=(~0);
9613 selection_info.id=(~0);
9614 state|=RedrawListState;
9615 break;
9616 }
9617 case SelectionRequest:
9618 {
9619 XSelectionEvent
9620 notify;
9621
9622 XSelectionRequestEvent
9623 *request;
9624
9625 if (list_info.id == (~0))
9626 break;
9627 /*
9628 Set primary selection.
9629 */
9630 request=(&(event.xselectionrequest));
9631 (void) XChangeProperty(request->display,request->requestor,
9632 request->property,request->target,8,PropModeReplace,
9633 (unsigned char *) primary_selection,Extent(primary_selection));
9634 notify.type=SelectionNotify;
9635 notify.send_event=MagickTrue;
9636 notify.display=request->display;
9637 notify.requestor=request->requestor;
9638 notify.selection=request->selection;
9639 notify.target=request->target;
9640 notify.time=request->time;
9641 if (request->property == None)
9642 notify.property=request->target;
9643 else
9644 notify.property=request->property;
9645 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
9646 (XEvent *) &notify);
9647 }
9648 default:
9649 break;
9650 }
9651 } while ((state & ExitState) == 0);
9652 if (text_info != windows->widget.font_info)
9653 (void) XFreeFont(display,text_info);
9654 XSetCursorState(display,windows,MagickFalse);
9655 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
9656 XCheckRefreshWindows(display,windows);
9657}
9658#endif