File: RtdImagePick2.tcl

package info (click to toggle)
skycat 3.1.2%2Bstarlink1~b%2Bdfsg-7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 12,312 kB
  • sloc: cpp: 41,950; tcl: 22,499; ansic: 10,288; sh: 1,034; makefile: 46; lisp: 23
file content (918 lines) | stat: -rw-r--r-- 29,801 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
#*************************************************************************
# E.S.O. - VLT project/ ESO Archive
#
# "@(#) $Id: RtdImagePick2.tcl,v 1.1.1.1 2009/03/31 14:11:52 cguirao Exp $"
#
# RtdImagePick2.tcl - Pick object with a given sample size
#
# See the man page for a complete description.
#
# who       when      what
# --------  --------  ----------------------------------------------
# pbiereic  01/07/01  created

# RtdImagePick2 is used to pick an object with a given sample size which 
# can be changed interactively with a slider.
# Two pick modes are implemented: pick object and pick cursor (that's why
# it is called RtdImagePick2).
# Pick object uses a centroiding algorithm for finding the object center
# and displays the statistics likewise RtdImagePick does.
# Pick cursor simply displays the picked x, y coordinates.
#
# The itk option -pickedCmd is evaluated whenever an object was picked.
# It returns a tcl list with the following values:
#
#   { x y ra dec equinox fwhmX fwhmY angle peak background } { nsamples }
#
# The command option -newSizeCmd is evaluated whenever the sample
# size is changed. It returns the number of samples.
#
# The command option -newImageCmd is evaluated whenever a new image (i.e. an image with
# a different type or size) is loaded and also when it is cleared.
#
# RtdImagePick2 uses the second zoom provided by RTD via class RtdImagePickView.
#
# It can co-exist with RtdImagePick, i.e. it checks the X cursor font to
# determine if the click in the canvas is assigned to this widget.
#
# RtdImagePick2 listens to image events which are either a new image or
# real-time image events. When the option -postImageEvent is true then
# the statistics is updated with every new image event (which may slow down
# the display rate).
#
# Applications (like tcscam) can inherit this class and add their own widgets.
# With method 'add_my_button' one can add a control button.
# The main frame components are public (i.e. the component name will not
# change). They are:
#
#  $itk_component(infof)    - info frame
#  $itk_component(zoomf)    - zoom frame
#  $itk_component(sliderf)  - slider frame
#  $itk_component(choicef)  - choice frame
#  $itk_component(buttonf)  - button frame
#
# The frames (and all other widgets) are packed with the blt::table geometry
# manager. The 'pack' geometry manager should not be used (see LIMITATIONS
# on man page of table(BLT 2.4).
#
# There are options like -with_info, -with_choice which are set to 1 by default
# to show all frames (see options). They can be set to 0 and the application
# can re-arrange the frames (via blt::table) as required.
#
# NOTES
# - In contrast to RtdImagePick, RtdImagePick2 does not use tkwait which may
#   cause problem for an inheriting class due to nested calls to tkwait.
package require Tclutil

itk::usual RtdImagePick2 { }

itcl::class rtd::RtdImagePick2 {
    inherit util::TopLevelWidget

    constructor { args } {
	eval itk_initialize $args
    }

    destructor {
	catch { close }
    }

    # init is called by the TopLevelWidget after the itk options
    # have been evaluated.

    protected method init { } {
	wm protocol $w_ WM_DELETE_WINDOW [code $this close]
	wm title    $w_ "Pick Object"

	config -samplesize 40  ; # sample size at start

	if { [cget -with_menu] } {
	    make_menu ; # Make the menu
	}
	make_layout ; # Make the window layout

	$itk_component(smaller) config -command [code $this inc_zoom -1]
	$itk_component(larger)  config -command [code $this inc_zoom 1]

	# set canvas and widget bindings
	$canvas_ bind all     <ButtonRelease-1> "+[code $this picked_object]"
	$canvas_ bind $image_ <Enter>           "+[code $this config_cursor]"

	bind enter$w_ <Enter> "+[code $this this_entered 1]"
	bind leave$w_ <Leave> "+[code $this this_entered 0]"
        bindtags $w_ "enter$w_ leave$w_"
	
	wm resizable $w_ 0 0  ; # resizing is possible but makes layout worse
    }

    # Make the menu. Add menubar and menus

    protected method make_menu { } {
	add_menubar
	set m [add_menubutton File]
	add_menuitem $m command "Close" \
		{Close this window} \
		-command [code $this close]

	set m [add_menubutton View]
	add_menuitem $m checkbutton "Update after image events" \
		{Update statistics after every new real-time image event} \
		-variable $w_.postImageEvent -onvalue 1 -offvalue 0 \
		-command [code $this setPostImageEvent]

	global ::$w_.postImageEvent
	set $w_.postImageEvent [cget -postImageEvent]

	set magMenu_ $m.mag
	add_menuitem $m cascade "Magnification" \
		{Set the magnification factor of the zoom} \
		-menu [menu $magMenu_]

	for {set i 2} {$i < 31} {incr i} {
	    $m.mag add radiobutton -label " ${i}x" \
		    -command [code $this scaleZoom $i] \
		    -variable $magMenu_
	}
    }

    # Make the window layout

    protected method make_layout { } {
	if { [cget -with_menu] } {
	    set w $w_.mainf
	    # use same geometry manager as for the menubar
	    pack [frame $w] -expand 1 -fill both
	} else {
	    set w $w_
	}
	if { "[cget -panel_orient]" == "horizontal" } {
	    add_mframe $w infof   make_info     [cget -with_info] raised  0,0 "-fill both"
	    add_mframe $w zoomf   make_zoom     1 raised  0,1 "-fill both"
	    add_mframe $w sliderf make_sldframe [cget -with_slider]  raised  1,0 "-fill both"
	    add_mframe $w choicef make_choice   [cget -with_choice] raised  1,1 "-fill both"
	    add_mframe $w buttonf make_buttons  [cget -with_buttons] groove  2,0 \
		    "-columnspan 2 -fill x"
	} else {
	    add_mframe $w infof   make_info     [cget -with_info] raised  2,0 "-fill both"
	    add_mframe $w zoomf   make_zoom     1 raised  0,0 "-fill both"
	    add_mframe $w sliderf make_sldframe [cget -with_slider] raised  3,0 "-fill both"
	    add_mframe $w choicef make_choice   [cget -with_choice] raised  1,0 "-fill both"
	    add_mframe $w buttonf make_buttons  [cget -with_buttons] groove  4,0 "-fill x"
	}
    }

    # Add a frame to the main blt table of this mega widget.
    # Add frame component, execute the method which create the widgets
    # within the component and add the component to the blt table.

    protected method add_mframe { w compo methd map relief idx opts } {
	itk_component add $compo {
	    frame $w.$compo -borderwidth 2 -relief $relief
	}
	eval $methd $itk_component($compo)
	if { $map } {
	    eval blt::table $w $itk_component($compo) $idx $opts
	}
    }

    # Add short help text for a component

    protected method add_shelp { compo text } {
	add_short_help $itk_component($compo) $text
    }

    # Add a LabelValue widget to a blt table

    protected method add_label { w compo text idx { font labelfont } } {
	set wdg $w.$compo
	itk_component add $compo {
	    util::LabelValue $wdg \
		    -text        $text \
		    -labelfont   $itk_option(-$font) \
		    -labelwidth  $itk_option(-labelwidth) \
		    -valuewidth  $itk_option(-valuewidth) \
		    -relief      groove \
		    -anchor      e
	}
	catch {
	    [$wdg component entry] config -justify right -highlightthickness 0
	    [$wdg component label] config -pady 0
	}
	blt::table $w $wdg $idx -fill x -anchor e
    }

    # Create the widgets for displaying the statistics

    protected method make_info { w } {
	set idx -1
	add_label $w  x      "Image X:"          [incr idx],0
	add_label $w  y      "Image Y:"          [incr idx],0
	add_label $w  ra     "a:"                [incr idx],0  wcsfont
	add_label $w  dec    "d:"                [incr idx],0  wcsfont
	add_label $w  equin  "Equinox:"          [incr idx],0
	add_label $w  peak   "Peak above bg:"    [incr idx],0
	add_label $w  back   "Background level:" [incr idx],0
	add_label $w  fwhm   "FWHM X:Y:"         [incr idx],0
	add_label $w  angle  "Angle of X axis:"  [incr idx],0
	add_label $w  nsize  "Pixels in x,y:"    [incr idx],0

	add_shelp x      "X image pixel coordinate (or X detector chip coord if known)"
	add_shelp y      "Y Image pixel coordinate (or Y detector chip coord if known)"
	add_shelp ra     "World Coordinates RA value"
	add_shelp dec    "World Coordinates DEC value"
	add_shelp equin  "World Coordinates equinox (default: J2000)"
	add_shelp peak   "Object: peak value of object above background"
	add_shelp back   "Background: mean background level"
	add_shelp fwhm   "FWHM: full width half maximum in X and Y"
	add_shelp angle  "Angle: angle of major axis, degrees, along X = 0"
	add_shelp nsize  "Number of pixels: along x and y-axis "
    }

    # Create a zoom window used to display the part of the
    # image to be examined.

    protected method make_zoom { w } {
	itk_component add zoomView {
	    rtd::RtdImagePickView $w.zoomView \
		    -target_image  $itk_option(-target_image) \
		    -factor        $itk_option(-zoomFact) \
		    -command       [code $this zoomScaledCb]
	}
	blt::table $w $itk_component(zoomView) 0,0
    }

    # Add a button and add to blt table

    protected method add_button { w compo text idx command } {
	itk_component add $compo {
	    button $w.$compo -text $text -command $command
	}
	blt::table $w $itk_component($compo) $idx -fill x
    }

    # Add an application specific button

    public method add_my_button { idx compo text command shelp } {
	set w $itk_component(buttonf)

	if { "[cget -panel_orient]" == "horizontal" } {
	    # add button and redo packing
	    set names [blt::table search $w -pattern *]
	    add_button $w $compo $text 0,$idx $command
	    
	    set names [linsert $names $idx $itk_component($compo)]
	    set i -1
	    foreach name $names {
		blt::table $w $name 0,[incr i] -fill x
	    }
	} else {
	    add_button $w $compo $text 1,$idx $command
	}
	add_shelp $compo $shelp
	return $itk_component($compo)
    }

    # Add control buttons

    protected method make_buttons { w } {
	set idx -1

	add_button $w pick   "Pick Object" 0,[incr idx]  [code $this pick_object]
	add_button $w cancel "Cancel"      0,[incr idx]  [code $this cancel 1]
	add_button $w close  "Close"       0,[incr idx]  [code $this close]

	add_shelp pick \
		{Pick Object: {bitmap b1} = select object in image and display \
		center and other statistics}
	add_shelp cancel {Cancel: cancel the current pick operation}
	add_shelp close  {Close: close the pick window}
    }

    # Create the slider widget

    protected method make_slider { w } {

	itk_component add slider {
	    util::LabelEntryScale $w.slider \
		    -show_arrows   1 -increment 1 -valuewidth 4 \
		    -text          "Sample size (in image pixels):"  \
		    -orient        vertical \
		    -length        $itk_option(-maxSsize)  \
		    -value         [cget -samplesize] \
		    -from          $itk_option(-minSsize)  \
		    -to            $itk_option(-maxSsize) \
		    -validate      numeric  \
		    -scaleWidth    10
	}
	add_shelp slider \
		{Slider: set the size of the image area to examine (in image pixels)}

	# configure slider widget and change the layout
	set sldWdg $itk_component(slider)
	$sldWdg config -command [code $this update_rect] \
		-entrycommand [code $this update_rect]
	[$sldWdg component label] config -justify left

	blt::table $sldWdg \
		[$sldWdg component label]      0,0 -anchor w -fill x \
		[$sldWdg component entry]      0,1 -anchor e \
		[$sldWdg component scaleframe] 1,0 -fill x -columnspan 2 -padx 1m
    }

    # add slider widget

    protected method make_sldframe { w } {
	make_slider $w
	blt::table $w $itk_component(slider) 0,0 -anchor w -fill x
    }

    # Create pick control frame

    protected method make_choice { w } {
	# pick mode choice
	set rbChoice $w.rbChoice
	itk_component add rbChoice {
	    util::LabelChoice $rbChoice \
		    -text       "Select pick mode" \
		    -orient     vertical \
		    -choice     {"Pick Object" "Pick Cursor"} \
		    -variable   $w_.pickMode \
		    -value      "Pick Object" \
		    -anchor     c \
		    -command    [code $this set_pickmode]
	}

	# cross marker checkbutton and zoom buttons
	set zoomctrlf $w.zoomctrlf
	itk_component add zoomctrlf { frame $zoomctrlf }
	
	# button to show cross markers
	set var $w_.pickMark
	global ::$var
	itk_component add pickMark {
	    checkbutton $zoomctrlf.pickMark -text "X" -variable $var \
		    -command [code $this toggleMarker $var]
	}
	set $var $itk_option(-showMarker)
	add_shelp pickMark {Show/hide cross marker when object was picked}

	# Zoom buttons
	itk_component add larger {
	    button $zoomctrlf.larger -bitmap magnify -command [code $this inc_zoom 1]   
	}
	itk_component add smaller {
	    button $zoomctrlf.smaller -bitmap shrink -command [code $this inc_zoom -1]  
	}
	add_shelp larger  {Zoom larger:  {bitmap b1} = increase magnification of zoom image}
	add_shelp smaller {Zoom smaller: {bitmap b1} = decrease magnification of zoom image}

	# label for scale factor
	itk_component add scalelab {
	    label $zoomctrlf.label -text "" -width 3 -font $itk_option(-labelfont) 
	}

	blt::table $zoomctrlf \
		$itk_component(pickMark)  0,0  -fill y -anchor w -columnspan 3 \
		$itk_component(larger)    1,0  -fill x \
		$itk_component(smaller)   1,1  -fill x \
		$itk_component(scalelab)  1,2  -fill x

	blt::table $w \
		$itk_component(rbChoice)  0,0 -fill both \
		$itk_component(zoomctrlf) 0,1 -fill both
    }

    # activate / de-activate the widget. 

    protected method activate { bool } {
	if { $bool == $activated_ || ( $bool != 0 && [$image_ isclear] ) } { return }
	
	set im $itk_option(-target_image)
	if { $bool } {
	    # use the "new image" callback for initialization
	    newImageCb

	    # expand zoom window to fill the zoom frame (minus the borderwidth)
	    set bd 6
	    set width  [expr {[winfo width  $itk_component(zoomf)] - $bd}]
	    set height [expr {[winfo height $itk_component(zoomf)] - $bd}]
	    $itk_component(zoomView) change_size $width $height

	    # activate the zoom view widget
	    $itk_component(zoomView) activate 1

	    # install callbacks for new images and image events
	    set cmd [$im cget -newimagecmd]
	    set newImgCmd_ " ; [code $this newImageCb]"
	    $im config -newimagecmd "$cmd$newImgCmd_"
	    
	    set cmd [$im cget -cameraPostCmd]
	    set postCmd_   " ; [code $this updateImageCb]"
	    $im config -cameraPostCmd "$cmd$postCmd_"
	} else {
	    # de-activate the zoom view widget
	    $itk_component(zoomView) activate 0

	    # remove callbacks for new images and image events
	    set cmd [$im cget -newimagecmd]
	    regsub $newImgCmd_ $cmd "" cmd
	    $im config -newimagecmd $cmd

	    set cmd [$im cget -cameraPostCmd]
	    regsub $postCmd_ $cmd "" cmd
	    $im config -cameraPostCmd $cmd
	}
	set activated_ $bool
    }

    # newImageCb is called whenever a new image (i.e. an image with
    # a different type or size) is loaded and also when it is cleared.

    protected method newImageCb { args } {
	if { [$image_ isclear] } {
	    cancel
	    if { "$itk_option(-newImageCmd)" != ""} {
		eval $itk_option(-newImageCmd)
	    }
	    return
	}
	updateMarker 0

	# check that the last picked coords are within the range
	# of the new image. If not, use the center coords.
	set width  [$image_ width]
	set height [$image_ height]

	# check if there was one pick
	if {"$pickx_" == ""} {
	    $image_ convert coords \
		[expr {$width / 2.0}] [expr {$height / 2.0}] image \
		    pickx_ picky_ chip
	}
	$image_ convert coords $pickx_ $picky_ chip x y image

	# check if center coords are in bounds
	if { $x > $width || $y > $height } {
	    $image_ convert coords $x $y image pickx_ picky_ chip
	    set_values {}
	}
	$itk_component(zoomView) moveTo $pickx_ $picky_

	# check sample size
	set size [cget -samplesize]
	set maxsize [min $width $height]
	if { $size > $maxsize } {
	    set size $maxsize
	    config -samplesize $size
	}
	$itk_component(slider) config -value $size
	$itk_component(zoomView) config -ssize $size

	if { "$itk_option(-newImageCmd)" != ""} {
	    eval $itk_option(-newImageCmd)
	}
    }

    # updateImageCb is called after an image event

    protected method updateImageCb { args } {
	catch {
	    # check if the statistics of the actual image can be updated
	    if { ! [cget -postImageEvent] || $picking_ || ! $activated_ || \
		    $pickMode_ == 1 || [ $image_ isclear ] } {
		return
	    }
	    if { [lempty $pickx_] } { return }
	    set result [$itk_component(zoomView) statistics $pickx_ $picky_]
	    $itk_component(zoomView) moveTo $pickx_ $picky_
	    set_values $result 1
	}
    }

    # setup new center coords and sample size for method pick_object

    public method setup_pick { xref yref sampleSize } {
	update_rect $sampleSize
	set_values "$xref $yref"
	set pickx_ $xref
	set picky_ $yref
	$itk_component(zoomView) moveTo $xref $yref
    }

    # pick an object in the image and get the statistics on
    # the area. Currently the args list is not used.

    public method pick_object { args } {
	if { $picking_ || [$image_ isclear] } { return }

	# update and raise is needed for method activate
	raise $w_
	update idletasks
	updateMarker 0

	# prepare for <ButtonRelease-1> event which calls method picked_object
	activate 1 ; # activate zoom
	picking  1 ; # change mode to "picking"
    }

    # picked_object is called when the user has clicked in the image 
    # to select an object or star for the "pick_object" method. 

    protected method picked_object { } {
	# return if the mouse click is not for us
	set cs [lindex "$cs_pick_ $cs_click_" $pickMode_]
	if { ! $picking_ || "$cs" != "[$canvas_ cget -cursor]" } { return }

	# get chip coordinates at cursor position set by the rtdimage code
	global ::$image_
	lassign "[set ${image_}(X)] [set ${image_}(Y)]" x y

	picking 0 ; # stop the zoom

	if { [$image_ isclear] } { return }

	# set result according to the current pick mode
	if { $pickMode_ == 0 } {
	    # get statistics
	    $itk_option(-target_image) busy {
		set result [$itk_component(zoomView) statistics $x $y]
	    }
	} else {
	    # set result to the displayed x,y coords
	    set result "$x $y"
	}
	lassign $result xc yc
	set pickx_ $xc
	set picky_ $yc

	# move to new center of image
	$itk_component(zoomView) moveTo $xc $yc
	raise $w_
	set_values $result

	if { "$itk_option(-pickedCmd)" != "" } {
	    eval $itk_option(-pickedCmd) {"[list $result [cget -samplesize]]"}
	}
    }

    # close this window

    protected method close { } {
	cancel 1   ; # cleanup
	activate 0 ; # de-activate the zoom and events
	wm withdraw $w_
    }

    # set pick mode

    protected method set_pickmode { args } {
	global ::$w_.pickMode
	if { "[set $w_.pickMode]" == "Pick Object" } {
	    set pickMode_ 0
	} else {
	    set pickMode_ 1
	}
	$itk_component(pick) config -text \
		[lindex [$itk_component(rbChoice) cget -choice] $pickMode_]
	config_cursor
    }

    # cancel pick operation

    public method cancel { { eval_cmd 0 } } {
	if { $eval_cmd } {
	    updateMarker 0
	    if { "$itk_option(-cancelCmd)" != ""} {
		eval $itk_option(-cancelCmd)
	    }
	}
	picking 0
    }

    # Show image at last picked coords when mouse ptr. enters this widget.
    # Otherwise: switch zoom on when picking is active, else off.

    public method this_entered { bool } {
	if { ! $bool && $picking_ } {
	    $itk_component(zoomView) zoom 1
	} else {
	    $itk_component(zoomView) zoom 0
	    if { [lempty $pickx_] } { return }
	    $itk_component(zoomView) moveTo $pickx_ $picky_
	}
    }

    # change cursor when mouse pointer enters or leaves the image.
    # This is only done when the default cursor is displayed.

    protected method config_cursor { } {
	set cursor [$canvas_ cget -cursor]
	set cs [lindex "$cs_pick_ $cs_click_" $pickMode_]
	if { $picking_ } {
	    if { "$cursor" == "" || "$cursor" == "$cs_pick_" || \
		    "$cursor" == "$cs_click_"} {
		$canvas_ configure -cursor $cs
		$w_ configure -cursor $cs
	    }
	} else {
	    if { "$cursor" == "$cs_pick_" || "$cursor" == "$cs_click_"} {
		$canvas_ configure -cursor {}
		$w_ configure -cursor {}
	    }
	}
    }

    # set state picking / zooming and configure the widgets

    protected method picking { bool } {
	if { $bool == $picking_ } { return }

	if { $bool } {
	    $itk_component(zoomView) zoom 1
	    $itk_component(pick) config -state disabled
	} else {
	    $itk_component(zoomView) zoom 0
	    $itk_component(pick) config -state normal
	}
	set picking_ $bool
	config_cursor
    }

    # set the values of the labels from the list (results of "pick_object" call).
    # If list is empty the labels are cleared.

    protected method set_values { list { imgEvt 0 } } {
	set list_ ""
	foreach wdg [winfo children $itk_component(infof)] {
	    catch { $wdg config -value "" }
	}
	if { [lempty $list] } {
	    return
	}
	set pickOk 1
	lassign $list x y ra dec equin fwhmX fwhmY angle peak back

	$itk_component(x)     config -value  [format_val $x]
	$itk_component(y)     config -value  [format_val $y]
	$itk_component(nsize) config -value  [format_val [cget -samplesize]]

	if { $pickMode_ == 0 } {
	    if {"$fwhmX" == "" || $fwhmX > 0 && $fwhmY > 0} {
		$itk_component(ra)    config -value  $ra
		$itk_component(dec)   config -value  $dec
		$itk_component(equin) config -value  $equin
		$itk_component(peak)  config -value  [format_val $peak]
		$itk_component(back)  config -value  [format_val $back]
		$itk_component(angle) config -value  [format_val $angle]
		$itk_component(fwhm)  config -value "[format_val $fwhmX] : [format_val $fwhmY]"
		set fgcol black
	    } else {
		# "Can't do" was displayed by the first astronomical image processing
		# system in the world, named IHAP.
		if { ! $imgEvt } {
		    $itk_component(fwhm)  config -value "Can't do"
		}
		$itk_component(angle) config -value ""
		set fgcol red
		set pickOk 0
	    }
	    [$itk_component(fwhm) component entry] config -foreground $fgcol
	}
	lappend list_ $list "$pickMode_ $pickOk"
	updateMarker
    }

    # update the size of the square in the zoom canvas from the slider widget.
    # "size" is the size of the sample image in image pixels

    public method update_rect { {size 0} }  {
	# check requested size
	if {$size < $itk_option(-minSsize) || \
		$size > $itk_option(-maxSsize) || \
		$size > [min [$image_ width] [$image_ height]]} {
	    $itk_component(slider) select  ; # just select - no warning message
	    return
	}
	config -samplesize $size
	$itk_component(zoomView) config -ssize $size
	$itk_component(zoomView) update_rect
	$itk_component(slider) config -value $size

	if { "$itk_option(-newSizeCmd)" != "" } {
	    eval $itk_option(-newSizeCmd) $size
	}
    }

    # increment or decrement the zoom factor

    protected method inc_zoom { inc } {
	$itk_component(zoomView) inc_zoom $inc
	updateMarker
    }

    # display the scale factor of the zoom widget

    protected method zoomScaledCb { args } {
	set f [$itk_component(zoomView) get_scale]
	$itk_component(scalelab) config -text "${f}x"
    }

    # scale the zoom widget

    protected method scaleZoom { scale } {
	$itk_component(zoomView) set_scale $scale
	zoomScaledCb
	updateMarker
    }

    # format a floating point value (which may also be empty)

    protected method format_val { val } {
	if {"$val" == ""} {
	    return
	}
	return [format {%.1f} $val]
    }

    # configure the -postImageEvent option

    protected method setPostImageEvent { args } {
	global ::$w_.postImageEvent
	config -postImageEvent [set $w_.postImageEvent]
    }

    # toggle the visibility of the blinking marker

    protected method toggleMarker { var } {
	global ::$var
	config -showMarker [set $var]
	updateMarker
    }

    # show/hide blinking marker when object was picked. In pick
    # cursor mode a simple cross is displayed and in pick object
    # mode the cross marking the fwhm values.

    protected method updateMarker { {show -1} } {
	if { [lempty $list_] && $show != 0 } { return }

	set zoomIm [$itk_component(zoomView) get_image]
	set zoomCv [$itk_component(zoomView) get_canvas]

	if { $show == -1 } {
	    set show [cget -showMarker]
	}
	lassign [lindex $list_ 0] x y ra dec equinox fwhmX fwhmY angle peak background
	lassign [lindex $list_ 1] pickMode pickOk

	if { $show && $pickOk } {
	    $image_ convert coords $x $y chip x y image
	    if { $pickMode == 0 } {
		mark_spot $x $y $zoomIm $zoomCv  $angle $fwhmX $fwhmY
		mark_spot $x $y $image_ $canvas_ $angle $fwhmX $fwhmY 1
	    } else {
		$image_ convert coords 5 5 image nx ny image
		mark_spot $x $y $zoomIm $zoomCv  0 $nx $ny
		mark_spot $x $y $image_ $canvas_ 0 $nx $ny 1
	    }
	} else {
	    catch {$zoomCv  delete mark$zoomIm}
	    catch {$canvas_ delete mark$image_}
	}
    }

    # mark the x,y image coordinate point in the canvas with
    # a cross with the width, height (image pixels) and angle (deg).

    protected method mark_spot {xc yc image canvas angle w h {blink 0}} {
	set tags "mark$image objects"
	catch { $canvas delete mark$image }

	if { $xc > [$image width] || $yc > [$image height] || \
		 $xc < 1 || $yc < 1 || [catch {expr {$angle / 2.0}}] } { 
	    return
	}

	# convert angle to radian
	set rad [expr {$angle / 57.2958}]

	# deltas for X and Y axis
	set dxX [expr {cos($rad) * $w/2.0}]
	set dyX [expr {sin($rad) * $w/2.0}]
	set dxY [expr {cos($rad) * $h/2.0}]
	set dyY [expr {sin($rad) * $h/2.0}]

	# compute end points for X-axis and convert points to canvas coordinates
	$image convert coords [expr {$xc + $dxX}] [expr {$yc + $dyX}] image x1X y1X canvas
	$image convert coords [expr {$xc - $dxX}] [expr {$yc - $dyX}] image x2X y2X canvas

	# the Y-axis is rotated "by hand" so that it appears perpendicular to the X-axis
	$image convert coords [expr {$xc + $dyY}] [expr {$yc - $dxY}] image x1Y y1Y canvas
	$image convert coords [expr {$xc - $dyY}] [expr {$yc + $dxY}] image x2Y y2Y canvas

	# draw X and Y axis lines with an outer thick black line
	# and inner thin white line
	foreach width {3 1} bg {black white} {
	    set opts "-fill $bg -width $width -tags {$tags $bg}"
	    eval $canvas create line $x1X $y1X $x2X $y2X $opts
	    eval $canvas create line $x1Y $y1Y $x2Y $y2Y $opts
	}
	if { $blink } {
	    blink_mark $canvas $tags
	}
    }

    # blink a cross in the main image, showing the marker created
    # by method mark_spot

    protected method blink_mark { canvas tags { color 0 } } {
	catch {after cancel $afterId_}
	set tag [lindex $tags 0]
	if { "[$canvas gettags $tag]" == "" } { return }

	set cols "black white"
	if { $color } {
	    set cols "white black"
	}
	$canvas itemconfigure white -fill [lindex $cols 0]
	$canvas itemconfigure black -fill [lindex $cols 1]
	set afterId_ [after 700 [code $this blink_mark $canvas $tag [expr {! $color}]]]
    }

    # -- options --

    # target (main) RtdImage itcl widget
    itk_option define -target_image target_image Target_image { } {
        set image_  [[cget -target_image] get_image]
        set canvas_ [[cget -target_image] get_canvas]
    }
    # actual sample size
    itk_option define -samplesize sampleSize SampleSize {}

    # min. and max. values for slider
    itk_option define -minSsize minSsize MinSsize 5
    itk_option define -maxSsize maxSsize MaxSsize 100

    # command to evaluate when a an object was picked
    itk_option define -pickedCmd pickedCmd PickedCmd {}

    # command to evaluate when the sample size changed
    itk_option define -newSizeCmd newSizeCmd NewSizeCmd {}

    # command to evaluate after a new image
    itk_option define -newImageCmd newImageCmd NewImageCmd {}

    # command to evaluate when the pick was canceled
    itk_option define -cancelCmd cancelCmd CancelCmd {}

    # cursors to use
    itk_option define -pick_cursor pick_cursor Pick_cursor {target} {
	set cs_pick_ [cget -pick_cursor]
    }
    itk_option define -click_cursor click_cursor Click_cursor {plus} {
	set cs_click_ [cget -click_cursor]
    }
    
    # update statistics after every image event, bool
    itk_option define -postImageEvent postImageEvent PostImageEvent 1

    # default: show marker (blinking cross) when object was picked, bool
    itk_option define -showMarker showMarker ShowMarker 1

    # default zoom factor
    itk_option define -zoomFact zoomFact ZoomFact 4

    # "show" options: menubar, slider, info, ...
    itk_option define -with_menu with_menu With_menu 0
    itk_option define -with_slider with_slider With_slider 1
    itk_option define -with_info with_info With_info 1
    itk_option define -with_choice with_choice With_choice 1
    itk_option define -with_buttons with_buttons With_buttons 1

    # Specify the orientation of image and panel, one of {vertical horizontal}
    itk_option define -panel_orient panel_orient Panel_orient {horizontal}

    # fonts, widths, etc.
    itk_option define -labelfont  labelFont  LabelFont TkDefaultFont
    itk_option define -valuefont  valueFont  ValueFont TkDefaultFont
    itk_option define -wcsfont    wcsFont    WcsFont   {Symbol -14}
    itk_option define -labelwidth labelWidth LabelWidth 15
    itk_option define -valuewidth valueWidth ValueWidth 11

    # -- protected vars --
    
    protected variable image_        ;# internal target image
    protected variable canvas_       ;# target canvas
    protected variable picking_   0  ;# user is picking object, bool
    protected variable pickMode_  0  ;# pick mode (0=object, 1=cursor)
    protected variable afterId_      ;# id for blink after job
    protected variable list_      {} ;# result of last pick operation
    protected variable activated_ 0  ;# widget activated, bool
    protected variable newImgCmd_    ;# our callback for a new image cmd
    protected variable postCmd_      ;# our callback for a post image cmd
    protected variable magMenu_      ;# widget name of magnification menu
    protected variable cs_pick_      ;# cursor used for picking object
    protected variable cs_click_     ;# cursor used for clicking object
    protected variable pickx_     {} ;# last picked x coord
    protected variable picky_     {} ;# last picked y coord
}