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