; $Id: annotate.pro,v 1.22 1999/05/28 16:37:22 ali Exp $ ; ; Copyright (c) 1993-1999, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ; ; Parameter definitions: ; For all objects: ; 0 p0_x ; 1 p0_y ; 2 p1_x ; 3 p1_y ; 4 color index ; 5 thickness ; 6 linestyle ; 7 size ; 8 fill style (0=none, 1 = solid, 2 = lines ; 9 fill space ; 10 fill angle ; 11 npoints / nchars ; 12 alignment ; 13 font ; 14 orientation ; 15 head size ; 17 line/arrow/solid_arrow ; 18 eccen ; 19 object type ; 20 interpolation ; ; Modes: ; 0 Text ; 1 Lines/Arrows ; 2 Polylines/Polygons, Drag ; 3 Circles ; 4 Squares pro xmgr_fake, top, window ; simulate the xmanager routine for a non-widgetized environment. ; deliver events from the ann widget as well as motion and button ; events from the selected idl window. compile_opt hidden buttons = 0 ix0 = -1 iy0 = -1 while 1 do begin ev = widget_event(top, BAD_ID = bad, /NOWAIT) ;Widget event? if bad ne 0L then return ;Gone? Done. if ev.id ne 0L then annotate_event, ev $ ;Dispatch it. else begin ;Check for mouse if !d.window ne window then wset, window CURSOR, ix, iy, /DEV, /NOWAIT if (ix < iy) ge 0 then begin ;In window? j = !err ;New buttons i = j xor buttons ;changed buttons if i ne 0 then $ ;Button change... ANN_DRAW_EVENT, { ANN_FAKE_EVENT, $ x:ix, y:iy, press: i and j, release: i and buttons }, top $ else if ((ix ne ix0) or (iy ne iy0)) then $ ANN_DRAW_EVENT, { ANN_FAKE_EVENT, $ x:ix, y:iy, press: 0L, release: 0L }, top ix0 = ix iy0 = iy buttons = j endif ;ix, iy >= 0 endelse ;no widget event endwhile end function b_button, a ;Return a 1 bit deep bitmap given a byte image. ;width of image MUST be a multiple of 8. compile_opt hidden s = size(a) b = bytarr(s[1]/8, s[2]) if (s[1] and 7) ne 0 then $ message, 'B_BUTTON: image width must be a multiple of 8.' subs = lindgen(n_elements(b)) * 8 for ibit = 0,7 do b = b or byte(2^ibit) * (a[subs+ibit] ne 0b) return, reverse(b,2) end FUNCTION ann_closest, xy, n, pos ;return index of closest point compile_opt hidden d = (xy[0,0:n-1]-pos[0])^2 + (xy[1,0:n-1]-pos[1])^2 junk = min(d, i) return, i end FUNCTION ann_closest_obj, st compile_opt hidden WIDGET_CONTROL, st.objlist, GET_UVALUE=l ;Object list dmin = 1e6 pos = st.pos psize = n_elements(st.p) ;Elements/object nrows = n_elements(l)/psize if n_elements(l) le 1 then return, 0 for i=0L, nrows-1 do begin ;Each object p = l[*,i] ;Ith object k = i n = long(p[11]) case p[19] of ;Which object? 0: BEGIN ;A mess... x = p[2] ;Text width dx = cos(p[14]* !dtor) * x dy = sin(p[14]* !dtor) * x q = [p[0] + dx * (0.5-p[12]), p[1] + dy * (0.5-p[12])] i = i + (n + psize - 1)/psize ;Next object ENDCASE 1: q = [p[0]+p[2], p[1]+p[3]]/2. ;Lines 2: BEGIN ;Polygon j = psize * (i+1) xy = reform(l[j: j+2*n-1], 2, n) ;Extract points xmin=min(xy[0,*], max=xmax) ymin=min(xy[1,*], max=ymax) q = [xmin+xmax, ymin+ymax]/2. i = i + (2*n+psize-1)/psize ;Next element ENDCASE 3: q = p[[2,3]] ;Circle 4: q = [p[0]+p[2], p[1]+p[3]]/2. ;box else: q = pos + 10 ;Unknown obj, dist = big ENDCASE d = total((pos - q)^2) ;Distance... if d lt dmin then begin dmin = d & imin = k & endif ENDFOR if dmin lt 0.04 then return, imin else return, -1 END ;Ann_closest_obj PRO ANN_GET_NUM_EVENT, ev compile_opt hidden on_ioerror, bad_again widget_control, ev.id, get_value=v widget_control, ev.top, get_uvalue=u val = float(v[0]) if val lt u.minv or val gt u.maxv then goto, bad_again WIDGET_CONTROL, u.id, SET_VALUE=v[0] ;Save the correct value WIDGET_CONTROL, ev.top, /DESTROY ;Done return bad_again: WIDGET_CONTROL, ev.id, SET_VALUE='' return END pro CW_CONF_EVENT, ev ;On any event, save the value and kill it compile_opt hidden WIDGET_CONTROL, ev.id, GET_UVALUE=i ;Button index WIDGET_CONTROL, ev.top, GET_UVALUE=temp ;Temp storage location WIDGET_CONTROL, temp, SET_UVALUE=i ;save choice WIDGET_CONTROL, ev.top, /DESTROY ;Kill it return END FUNCTION CW_CONFIRM, message, choices ; Make a Modal widget with the given message as text, and with buttons ; corresponding to the choices. Return the index of the button pressed. ; compile_opt hidden temp = WIDGET_BASE() a = WIDGET_BASE(title='Confirmation',/COLUMN, UVALUE=temp, $ GROUP_LEADER=temp, /MODAL) for i=0, N_ELEMENTS(message)-1 DO junk = widget_label(a, value=message[i]) b = WIDGET_BASE(a, /ROW) for i=0,n_elements(choices)-1 do $ junk = WIDGET_BUTTON(b, VALUE=choices[i], /NO_REL, UVALUE=i) WIDGET_CONTROL, a, /REALIZE XMANAGER, 'Confirmation', a, EVENT_HANDLER='CW_CONF_EVENT' WIDGET_CONTROL, temp, GET_UVALUE=u, /DESTROY return, u end FUNCTION ann_get_num, str, id, minv, maxv ; Get & check a numeric value from a text widget. If illegal format, ; use a modal widget to get a correct value. compile_opt hidden on_ioerror, bad ;1st level call v = float(str[0]) if v lt minv or v gt maxv then goto, bad return, v ;OK bad: temp = WIDGET_BASE() t = widget_base(title='Invalid Number', /column, $ GROUP_LEADER=temp, /MODAL) WIDGET_CONTROL, t, set_uvalue = { id:id, minv: minv, maxv: maxv} ;Save params b = WIDGET_LABEL(t, value= 'An invalid number was entered') b = WIDGET_LABEL(t, value = 'Range = '+string(minv)+' to '+string(maxv)) b = WIDGET_LABEL(t, value= 'Please enter the correct value') j = WIDGET_TEXT(t, /frame, xsize=10, ysize=1, /EDIT) WIDGET_CONTROL, t, /REAL xmanager, 'Invalid Number', t, EVENT_HANDLER = 'ann_get_num_event' WIDGET_CONTROL, id, GET_VALUE=v ;The correct value WIDGET_CONTROL, temp, /DESTROY return, float(v[0]) end PRO ann_reset_mode, st, mode, submode, NOCLEAN = noclean ;Clean out the current object, reset mode compile_opt hidden if n_elements(mode) le 0 then mode = st.mode ;Save old mode if n_elements(submode) le 0 then submode = 0 newmode = st.mode ne mode if newmode then begin m = st.mode_bases WIDGET_CONTROL, m[n_elements(m)-1], MAP=0 ;Options base WIDGET_CONTROL, m[st.mode], MAP=0 ;Unmap old WIDGET_CONTROL, st.mode_buttons[mode], SET_BUTTON=1 if mode ge 2 then begin ;Set polyfill controls? p = st.p WIDGET_CONTROL, st.spline_id, SET_VALUE=p[20] WIDGET_CONTROL, st.poly_style[mode], SET_VALUE=p[8] WIDGET_CONTROL, st.poly_angle[mode], SET_VALUE=p[10] WIDGET_CONTROL, st.poly_spacing[mode], SET_VALUE=p[9] endif st.mode = mode WIDGET_CONTROL, m[mode], MAP=1 wset, st.draw_win ;Redraw the view window device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[1]] endif if keyword_set(noclean) eq 0 then begin ;Remove current object st.p[11] = 0 endif st.open = 0 st.minor_mode = submode st.p[19] = st.mode WIDGET_CONTROL, st.minor_mode_id, SET_VALUE=submode end PRO ann_add_object, st ;Add current object to list compile_opt hidden wset, st.backing[1] ;Make it permanent p = st.p ann_draw_object, st, p ;Draw obj in backing store wset, st.draw_win device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[1]] ;To draw window psize = n_elements(p) if p[19] eq 0 then begin ;text? n = strlen(st.txt) ;# of chars, Save in an array if n eq 0 then return ;Nothing to save p[11] = n a = bytarr(psize, (n+psize-1)/psize) ; Addtl bytes a[0] = byte(st.txt) p = [[p],[float(a)]] endif else if p[19] eq 2 then begin ;Polygon? n = long(p[11])*2 ;# of pnts required a = fltarr(psize, (n+psize-1)/psize) ;Array into which to insert WIDGET_CONTROL, st.xy, GET_UVALUE=xy, /NO_COPY a[0] = xy[0:n-1] ;Insert it p = [[p], [a]] endif WIDGET_CONTROL, st.objlist, GET_UVALUE = l, /NO_COPY if n_elements(l) gt 1 then p = [[l], [p]] ;Add to end of list WIDGET_CONTROL, st.objlist, SET_UVALUE = p, /NO_COPY ;Add to list ann_reset_mode, st ;Reset mode end ;Ann_add_object pro ann_set_controls, st, p ;Set controls to corresp to object compile_opt hidden WIDGET_CONTROL, st.color_id, SET_VALUE=p[4] WIDGET_CONTROL, st.thick_id, SET_VALUE=p[5]*10. WIDGET_CONTROL, st.linestyle_id, SET_VALUE=p[6] case p[19] of 0: BEGIN ;Text WIDGET_CONTROL, st.txt_size_id, SET_VALUE=p[7]*10. WIDGET_CONTROL, st.txt_id, SET_VALUE=st.txt WIDGET_CONTROL, st.ori_id, SET_VALUE=(p[14] + 360) mod 360 WIDGET_CONTROL, st.txt_ali_id, SET_VALUE=p[12]*2 WIDGET_CONTROL, st.txt_font_id, SET_VALUE=p[13] ENDCASE 1: BEGIN ;Line/arrow WIDGET_CONTROL, st.line_arrow_id, SET_VALUE=p[17] WIDGET_CONTROL, st.head_size_id, SET_VALUE=p[15]*10. ENDCASE 2: BEGIN WIDGET_CONTROL, st.spline_id, SET_VALUE=p[20] do_poly: i = long(p[19]) WIDGET_CONTROL, st.poly_style[i], SET_VALUE=p[8] WIDGET_CONTROL, st.poly_angle[i], SET_VALUE=p[10] WIDGET_CONTROL, st.poly_spacing[i], SET_VALUE=p[9] ENDCASE 3: BEGIN ;Circle WIDGET_CONTROL, st.ecc_id, SET_VALUE=(p[18]-1.)*10. goto, do_poly ENDCASE 4: goto, do_poly ;Rectangle ENDCASE END pro ann_refresh_list, st, FROM_SCRATCH=redraw, WINDOW=window, MONO = mono ; FROM_SCRATCH = redraw from backing store(0) ; WINDOW = destination window ; MONO = color index to gray scale translation table compile_opt hidden if n_elements(mono) le 0 then mono = 0 if n_elements(window) eq 1 then WSET, window if keyword_set(redraw) then $ ;Redraw from scratch? device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[0]] WIDGET_CONTROL, st.objlist, GET_UVALUE=l, /NO_COPY if n_elements(l) le 1 then goto, done ;Nothing... s = size(l) psize = s[1] ;# of columns n = n_elements(l) / psize ;# of rows for i=0L, n-1 do begin ;Do each object.... p = l[*,i] ;The object m = 0 ;# of addtl elements k = (i+1) * psize ;Next row if p[19] eq 0 then begin ;Text m = long(p[11]) ann_draw_object, { txt: string(byte(l[k:k+m-1]))} , p, MONO = mono endif else if p[19] eq 2 then begin ;polygon? m = long(p[11])*2 xy = reform(l[k:k+m-1], 2, m/2) ann_draw_object, st, p, xy=xy, MONO= mono endif else ann_draw_object, st, p, MONO= mono i = i + (m+psize-1)/psize ;Next row endfor done: WIDGET_CONTROL, st.objlist, SET_UVALUE=l, /NO_COPY end function ann_load_obj, st, obj ;Load nth object from list. Remove ; the object from the list. return 0 if error, 1 if ok. ; reload st with object. compile_opt hidden WIDGET_CONTROL, st.objlist, GET_UVALUE = l, /NO_COPY if n_elements(l) le 1 then begin quit: WIDGET_CONTROL, st.objlist, SET_UVALUE=l, /NO_COPY return, 0 endif psize = n_elements(st.p) n = n_elements(l) / psize ;# of objects if obj lt 0 or obj ge n then goto, quit ;There? p = l[*,obj] k = (obj+1) * psize m = 0 mode = fix(p[19]) if mode eq 0 then begin ;Text? m = long(p[11]) st.txt = string(byte(l[k:k+m-1])) ;fetch the text endif else if mode eq 2 then begin ;Polygon? j = long(p[11]) m = j*2 ;# of elements xy = reform(l[k:k+m-1], 2, j) WIDGET_CONTROL, st.xy, SET_UVALUE=xy, /NO_COPY endif else m = 0 st.p = p ;Get the object... m = (m+psize-1)/psize ;# of addtl rows ; print, 'loaded',obj,', rows ',m,', n =',n if n eq (m+1) then l = 0 $ ;last object else BEGIN ;Remove this object v = replicate(1,n) v[obj:obj+m] = 0 ;Rows we remove l = l[*,where(v)] ENDELSE WIDGET_CONTROL, st.objlist, SET_UVALUE = l, /NO_COPY ;Restore list ann_refresh_list, st, window=st.backing[1], /FROM_SCRATCH ann_set_controls, st, p ;Reset the controls return, 1 end pro ann_xfer_file, st, file, SAVE=save, LOAD=load ; Transfer an annotate load/save file. compile_opt hidden WIDGET_CONTROL, st.objlist, GET_UVALUE=l, /NO_COPY ;Current object list psize = n_elements(st.p) n = n_elements(l) / psize magic = '414e4e00'XL if keyword_set(save) then begin ;Save?? if n eq 0 then begin i = CW_CONFIRM('There is nothing to save.', 'OK') WIDGET_CONTROL, st.objlist, SET_UVALUE=l, /NO_COPY return endif mwrfits,st,'annotate.fits' openw, unit, /GET_LUN, file, /XDR ;Make the file writeu, unit, magic, psize ;Magic number, # of columns p = float([ !d.x_size, !d.y_size, !d.x_ch_size, !d.y_ch_size ]) ;Params writeu, unit, p for i=0L, n-1 do begin ;Write each object p = l[*,i] ;The object m = 0 ;# of addtl elements k = (i+1) * psize ;Next row writeu, unit, p ;The array if p[19] eq 0 then begin ;Text? m = long(p[11]) ;Strlen writeu, unit, byte(l[k:k+m-1]) ;The characters endif else if p[19] eq 2 then begin ;Polygon? m = long(p[11])*2 writeu, unit, l[k:k+m-1] ;The points endif i = i + (m+psize-1)/psize endfor writeu, unit, replicate(-1.0, psize) free_lun, unit WIDGET_CONTROL, st.objlist, SET_UVALUE=l, /NO_COPY ;Restore endif else begin ;LOAD openr,unit, /GET_LUN, file, /XDR, ERROR=i ;Try to open it... if i lt 0 then begin ;No file.. i = CW_CONFIRM(['File not found or unreadable', file], 'OK') return endif i = 0L ;Read magic columns = 0L readu, unit, i, columns if i ne magic then begin i = CW_CONFIRM(['File is not an annotate data file.', file], 'OK') return endif params = fltarr(4) readu, unit, params while 1 do begin ;Read each record p = fltarr(columns) readu, unit, p ; print, p[19] if p[19] eq -1 then begin ;Done.... free_lun, unit WIDGET_CONTROL, st.objlist, SET_UVALUE = l, /NO_COPY ;save list ann_refresh_list, st, WINDOW=st.backing[1], /FROM_SCRATCH wset, st.draw_win device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[1]] return endif m = 0L if p[19] eq 0 then begin ;string m = long(p[11]) ;# of addtl elements a = bytarr(m) readu, unit, a p = [[p], [fltarr(psize, (m+psize-1)/psize)]] ;what we add p[psize] = a ;Insert chars.... endif else if p[19] eq 2 then begin ;polygon m = long(p[11])*2 ;# of addtl elements a = fltarr(m) readu, unit, a p = [[p], [fltarr(psize, (m+psize-1)/psize)]] ;what we add p[psize] = a endif ; Adjust size for possible expansion.... if columns lt psize then p = [p, fltarr(columns-psize)] $ else if psize lt columns then p = p[0:psize-1] if n_elements(l) gt 1 then l = [[temporary(l)], [p]] $ else l = p endwhile endelse end pro annotate_ps, st, draw_ps, include_image compile_opt hidden if (LMGR(/DEMO)) then begin tmp = DIALOG_MESSAGE( /ERROR, $ 'Postscript Output: Feature disabled for demo mode.') return endif tvlct, r,g,b, /get ;current color table old = !d.name ;Current device name file = PICKFILE(FILE='annotate.ps', /WRITE, FILTER='*.ps', /NOCONF) if include_image then begin if draw_ps then WSET, st.backing[0] $ ;Original image else WSET, st.backing[1] ;image + our annotations a = tvrd() endif width = st.ps_width ;Output width ch = [!d.x_ch_size, !d.y_ch_size] / float([!d.x_size, !d.y_size]) if st.ps_units then width = width / 2.54 ;From cm to inches height = width * !d.y_size / !d.x_size ;Height print, 'Color=',st.ps_color SET_PLOT,'PS' DEVICE, file=file, COLOR=st.ps_color if st.ps_orien then DEVICE, /LANDSCAPE $ else DEVICE, /PORTRAIT DEVICE, XSIZE = width, YSIZE=height, /INCHES ;Set size tvlct,r,g,b if st.ps_color eq 0 then $ ;To BW from RGB l = bytscl(r * .3 + .6 * g + .11 * b) if include_image then begin ;Include image with new file? if st.ps_color eq 0 then a = l[a] tv, a ;Output image endif if draw_ps then begin device, set_char = ch * !d.x_size ;Proportional char size (aspect = same) ann_refresh_list, st, MONO = l endif if include_image then device, /close set_plot, old ;done end pro annotate_event, ev compile_opt hidden WIDGET_CONTROL, ev.top, GET_UVALUE = st, /NO_COPY ;Our data structure WIDGET_CONTROL, ev.id, GET_UVALUE = u ;The object uvalue ldr = strmid(u, 0, 1) IF ldr eq 'M' THEN BEGIN ;New mode? ann_reset_mode, st, fix(strmid(u,1,2)), 0 goto, done ENDIF IF ldr eq '#' THEN BEGIN WIDGET_CONTROL, ev.id, GET_VALUE = v ldr = '@' ENDIF IF ldr eq '@' THEN BEGIN ;Execute string? i = EXECUTE(strmid(u,2,100)) ;Execute the string.... IF strmid(u, 1, 1) eq 'R' THEN BEGIN ;Redraw? redraw: if st.open then begin wset, st.draw_win handle = st.minor_mode eq 1 p = st.p ANN_DRAW_OBJECT, st, p, handle, REFRESH=st.backing[1] st.p = p st.handle = handle ENDIF ENDIF ;Redraw ENDIF ELSE IF u eq 'Help' THEN BEGIN ;ldr eq '@' xdisplayfile, filepath("annotate.txt", subdir=['help', 'widget']), $ ; xdisplayfile, 'annotate.txt', $ title = "Annotate Help", $ group = ev.top, $ width = 72, height = 24 ENDIF else if u eq 'Options' THEN BEGIN m = st.mode_bases WIDGET_CONTROL, m[st.mode], MAP=0 WIDGET_CONTROL, m[n_elements(m)-1], /MAP ENDIF else if u eq 'Dismiss' THEN BEGIN m = st.mode_bases WIDGET_CONTROL, m[n_elements(m)-1], MAP=0 WIDGET_CONTROL, m[st.mode], MAP=1 ENDIF ELSE IF u eq 'TOPROW' THEN BEGIN WIDGET_CONTROL, ev.top, /HOURGLASS isDemo = LMGR(/DEMO) case ev.value of 'Exit' : BEGIN WIDGET_CONTROL, ev.top, /DESTROY return ENDCASE 'Save' : BEGIN ann_xfer_file, st, st.file, /SAVE ENDCASE 'Load': BEGIN st.file = PICKFILE(FILE=st.file, /READ, /MUST_EXIST, FILTER='*.dat') ann_xfer_file, st, st.file, /LOAD ENDCASE 'TIFF': BEGIN if (isDemo) then begin tmp = DIALOG_MESSAGE( /ERROR, $ 'WRITE_TIFF: Feature disabled for demo mode.') endif else BEGIN file = PICKFILE(FILE='annotate.tif', /WRITE, FILTER='*.tif', /NOCONF) WSET, st.backing[1] tvlct, red, green, blue, /GET WRITE_TIFF, file, tvrd(/ORDER), 1, RED=red, GREEN=green, BLUE=blue endelse ENDCASE 'GIF': BEGIN if (isDemo) then begin tmp = DIALOG_MESSAGE( /ERROR, $ 'WRITE_GIF: Feature disabled for demo mode.') endif else BEGIN file = PICKFILE(FILE='annotate.gif', /WRITE, FILTER='*.gif', /NOCONF) WSET, st.backing[1] WRITE_GIF, file, tvrd(ORDER=0) endelse ENDCASE ; If demo mode, disable ps in annotate_ps 'PostScript': annotate_ps, st, 0, 1 ;Postscript bitmap 'Everything': annotate_ps, st, 1, 1 ;do it with PS commands 'Objects only': annotate_ps, st, 1, 0 'Clear': BEGIN WIDGET_CONTROL, st.objlist, SET_UVALUE=0 ;Clean up object list wset, st.backing[1] ;redraw all objects except this one device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[0]] wset, st.draw_win device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, st.backing[0]] ann_reset_mode, st, st.mode, 0 ENDCASE ENDCASE ENDIF ELSE IF u eq 'Save' THEN BEGIN if st.open THEN ann_add_object, st ENDIF ELSE help, /st, u, ev done: WIDGET_CONTROL, ev.top, SET_UVALUE = st, /NO_COPY end PRO ANN_MOVE_RESIZE, st, mode, first, last compile_opt hidden if st.open eq 0 then return handle = st.handle pos = st.pos p = st.p if first then begin ;Initial hit? np = ([2,2,4,4,4])[mode] ;# of points ;distances from handle points and midpoint h = handle[*,0:np-1] d = [[h], [total(h,2)/np]] - (pos # replicate(1.,np+1)) d = min(total(d^2, 1), i) ;Dist squared, get closest if i eq np then i = 5 ;always use 5 for last point if d lt 0.01 then begin ;Close enough? st.ihandle = i if mode eq 0 then begin ;Text mode? if p[7] eq 0.0 then p[7] = 1.0 ;Size st.temp[0] = p[7] / p[2] ;1./(Length of siz=1) endif else if mode eq 3 then begin ;Circle? Save params. c = p[2:3] st.temp = [p[0:1] - c, total((pos - c)^2)] ;dx,dy, len endif if i ne 5 then st.orig = handle[*,np-1-i] $ ;Anchor point else st.orig = pos endif else st.ihandle = -1 endif ;First ihandle = st.ihandle if ihandle lt 0 then return ;A hit? d = pos - st.orig ;Movement ; if d(0) eq 0.0 and d(1) eq 0.0 and first eq 0 then goto, no_move if ihandle eq 5 then begin ;Move? st.orig = pos ;Reset it if mode eq 2 then begin ;Polygons? if p[11] gt 1 THEN BEGIN ;Polygons WIDGET_CONTROL, st.xy, GET_UVALUE=xy, /NO_COPY xy = xy + (d # replicate(1, p[11])) ;Translate WIDGET_CONTROL, st.xy, SET_UVALUE=xy, /NO_COPY ENDIF endif else p[0] = p[0:3] + [d,d] ;Just move origin ENDIF ELSE BEGIN ;Sizing handle if (mode gt 1) then begin ;Need scale factor? s = handle[*,ihandle] - st.orig ;stretch factor if min(abs(s)) lt 0.001 then goto, no_move s = (pos - st.orig) / s ;Scale factor if min(abs(s)) lt 0.001 then goto, no_move endif case mode of 0: BEGIN ;Text r = sqrt(total(d^2)) ;Length of line if r lt 0.001 then goto, no_move p[14] = atan(d[1], d[0]) * !radeg ;New orientation if ihandle eq 0 then p[14] = p[14] + 180. p[7] = r * st.temp[0] ;New size k = long(3 * ihandle + 2 * p[12]) ;Subs from 0 to 5. p[0] = pos + ([0, -0.5, -1., -1, -0.5, 0])[k] * d ENDCASE 1: p[ihandle * 2] = pos ;Line, just move vertex 2: if p[11] gt 1 THEN BEGIN ;Polygon, Scale all verts WIDGET_CONTROL, st.xy, GET_UVALUE=xy, /NO_COPY xy0 = st.orig # replicate(1.0,p[11]) xy = (xy - xy0) * (s # replicate(1.0,p[11])) + xy0 WIDGET_CONTROL, st.xy, SET_UVALUE=xy, /NO_COPY ENDIF 3: BEGIN ;Circle c = p[2:3] ;Center r = sqrt(total((pos - c)^2)/st.temp[2]) ;Dist from ctr p[0] = st.temp[0:1] * r + c ENDCASE 4: BEGIN ;Rectangle x0 = [st.orig, st.orig] p[0] = (p[0:3] - x0) * s[[0,1,0,1]] + x0 ENDCASE ENDCASE ENDELSE no_move: ANN_DRAW_OBJECT, st, p, handle, REFRESH=st.backing[1] ;Refresh st.p = p st.handle = handle END ;ANN_MOVE_RESIZE PRO ANN_DRAW_EVENT, ev, ann_base ;Handle events from drawable compile_opt hidden if n_elements(ann_base) eq 0 then $ WIDGET_CONTROL, ev.id, GET_UVALUE = ann_base WIDGET_CONTROL, ann_base, GET_UVALUE=st, /NO_COPY mode = st.mode WSET, st.draw_win if ev.press eq 4 then begin ;Right button to close object if st.open then ann_add_object, st goto, skip_it endif else if ev.press eq 2 then begin if st.open eq 0 then goto, skip_it i = st.minor_mode eq 0 ;Switch modes st.minor_mode = i ;Reset minor mode WIDGET_CONTROL, st.minor_mode_id, SET_VALUE=i p = st.p ANN_DRAW_OBJECT, st, p, i, REFRESH=st.backing[1] st.handle = i goto, skip_it endif pos = [ev.x, ev.y] first = 0 drag = 0 last = 0 if st.buttons eq 0 then begin ;First time? if ev.press ne 1 then begin ;Move? if !x.s[1] ne 0 then pos = convert_coord(pos, /DEVICE, /TO_DATA) WIDGET_CONTROL, st.instruct, SET_VALUE=string(pos[0:1]) goto, skip_it endif else begin first = 1 WIDGET_CONTROL, st.instruct, SET_VALUE='Right button to close' st.buttons = 1 endelse endif else begin ;Not first if ev.release ne 1 then drag = 1 $ else begin last = 1 st.buttons = 0 endelse endelse g = st.granularity pos = round(pos/g)*g / [!d.x_size, !d.y_size] if drag and (st.pos[0] eq pos[0]) and (st.pos[1] eq pos[1]) then goto, skip_it st.pos = pos if st.minor_mode eq 1 then begin ;MOVE/RESIZE ANN_MOVE_RESIZE, st, mode, first, last goto, skip_it ENDIF ELSE if st.minor_mode eq 2 then begin ;Select if first then begin ann_reset_mode, st, st.mode, 2 k = ann_closest_obj(st) if k ge 0 then begin ;Found one? st.temp[0] = k if ann_load_obj(st, k) then begin ;Find it? p = st.p st.minor_mode = 1 ;Now in move/resize ann_reset_mode, st, p[19], 1, /NOCLEAN st.open = 1 h = 1 wset, st.draw_win ANN_DRAW_OBJECT, st, p, h, REFRESH=st.backing[1] st.handle = h ANN_MOVE_RESIZE, st, st.mode, first, last endif endif endif goto, skip_it ENDIF ;Minor = 2 p = st.p if st.open eq 0 then begin ;First time p[11] = 0 WIDGET_CONTROL, st.fill_mode_id, SET_VALUE=0 WIDGET_CONTROL, st.minor_mode_id, SET_VALUE=0 st.fill_mode = 0 st.minor_mode = 0 ENDIF st.open = 1 case mode of 0: BEGIN ;Text IF first THEN BEGIN WIDGET_CONTROL, st.txt_id, GET_VALUE=h st.txt = h[0] ENDIF no_name_label: if first then p[2] = pos p[0] = pos h = last ANN_DRAW_OBJECT, st, p, h, REFRESH=st.backing[1] if last then begin st.handle = h st.minor_mode = 1 ;Go to move resize mode WIDGET_CONTROL, st.minor_mode_id, SET_VALUE=1 endif ENDCASE 1: goto, no_name_label ;Dragging line or arrow 2: BEGIN ;Polygon/polyline n = long(p[11]) if n eq 0L THEN BEGIN ;Initialize line buffer? xy = FLTARR(2,256) ENDIF ELSE WIDGET_CONTROL, st.xy, GET_UVALUE=xy, /NO_COPY case st.fill_mode of ;What are we doing? 0: BEGIN ;Vector /drag mode if n_elements(xy) le n*2 then xy = [[xy], [FLTARR(2,n)]] ;Extend it addok = 1 ; avoid adding the same point repeatedly (which crashes the spline .pro) IF (n GE 1L) THEN BEGIN IF ((xy[0,n-1] EQ st.pos[0]) $ AND (xy[1,n-1] EQ st.pos[1])) THEN addok = 0 ENDIF IF (addok) THEN BEGIN xy[0,n] = st.pos ;Last point if st.buttons then p[11] = n+1 ;Dragging ENDIF ENDCASE ;Vector 1: BEGIN ;Edit mode if n eq 0 then goto, skip_it1 if first then begin if n_elements(xy) le n*2 then xy = [[xy], [FLTARR(2,n)]] j = ann_closest(xy, n, pos) xy[0,n] = j endif else j = xy[0,n] xy[0,j] = pos ENDCASE 2: BEGIN ;Delete if (n le 0) or (last eq 0) then goto, skip_it1 j = ann_closest(xy, n, pos) ;Point to delete p[11] = n-1 if n eq 1 then goto, skip_it if j eq 0 then xy = xy[*,1:*] $ else if j eq n-1 then xy = xy[*, 0:n-2] $ else xy = [[xy[*,0:j-1]], [xy[*, j+1:*]]] ENDCASE ;delete ENDCASE ;st.fill_mode WIDGET_CONTROL, st.xy, SET_UVALUE=xy, /NO_COPY ANN_DRAW_OBJECT, st, p, REFRESH=st.backing[1] ENDCASE ;2 3: goto, no_name_label ;Circle 4: goto, no_name_label ;Box ENDCASE skip_it: if n_elements(p) gt 1 then st.p = p WIDGET_CONTROL, ann_base, SET_UVALUE=st, /NO_COPY return skip_it1: WIDGET_CONTROL, st.xy, SET_UVALUE=xy, /NO_COPY goto, skip_it end pro ANN_DRAW_OBJECT, st, p, handle, REFRESH = refresh, XY=xy, MONO = mono compile_opt hidden c = long(p[4]) ;Color index if keyword_set(mono) then c = mono[c] ;Outputting Postscript for BW? if n_elements(refresh) gt 0 then $ ;Refresh? device, copy = [0,0, !d.x_size, !d.y_size, 0, 0, refresh] case p[19] of ;What type of object 0: BEGIN ;Text str = '!' + strtrim(fix(p[13])>3,2) + st.txt + '!3' xyouts, p[0], p[1], /NORM, str, $ COLOR = c, CHARSIZE = p[7], $ ALI = p[12], ORI=p[14], CHARTHICK = p[5], WIDTH=x p[2] = x ;Save width if keyword_set(handle) then begin dx = cos(p[14]* !dtor) * x dy = sin(p[14]* !dtor) * x handle = [[ p[0]-p[12] * dx, p[1]-p[12] * dy], $ [p[0] + (1.-p[12]) * dx, p[1] + (1.-p[12]) * dy]] n = 2 do_handle: PLOTS, handle, /NORM, PSYM=6 PLOTS, total(handle,2)/n, /NORM, PSYM=6 ;The center ENDIF ENDCASE 1: BEGIN if p[17] ne 0 THEN BEGIN ;Lines/Arrows if p[15] le 0.0 then p[15] = 1.0 ARROW, p[2], p[3], p[0], p[1], /NORM, $ COLOR = c, THICK = p[5], SOLID=p[17] eq 2, $ HSIZE = p[15] * !D.X_SIZE/20. ENDIF ELSE PLOTS, p[[2,0]], p[[3,1]], /NORM, COLOR=c, THICK=p[5], $ LINESTYLE=p[6] if keyword_set(handle) then begin n = 2 handle = [[p[0], p[1]], [p[2], p[3]]] goto, do_handle ENDIF ENDCASE 2: BEGIN ;Polygon n = p[11] do_fill: if n gt 1 THEN BEGIN if n_elements(xy) le 1 then WIDGET_CONTROL, st.xy, GET_UVALUE = xy if (p[19] eq 2) and (p[20] eq 1) and (n gt 2) then $ ;Splines? spline_p, reform(xy[0,0:n-1]), reform(xy[1,0:n-1]), $ x, y, INTERV= 0.01 $ else begin ;Not splines x = xy[0,0:n-1] y = xy[1,0:n-1] endelse if (p[8] ne 1) or (n eq 2) THEN BEGIN ;Outline it? plots, x, y, /NORM, COLOR = c, $ ;Draw outline THICK = p[5], LINESTYLE = p[6] if p[8] eq 2 THEN BEGIN ;line fill? plots, x[[n-1,0]], y[[n-1,0]], /NORM, COLOR = c, $ ;Close it THICK = p[5], LINESTYLE = p[6] if n ge 3 THEN POLYFILL, x, y, /NORM, COLOR = c, $ THICK = p[5], ORI = p[10], SPACING = p[9]/100. ENDIF ENDIF ELSE IF N GE 3 THEN $ ;Solid fill POLYFILL, x,y, /NORM, COLOR = c ENDIF ELSE IF (n EQ 1) THEN BEGIN ; If only one point, we may still need handles... if n_elements(xy) le 1 then WIDGET_CONTROL, st.xy, GET_UVALUE = xy x = xy[0,0] y = xy[1,0] ENDIF ; get the handle bounds... IF (keyword_set(handle) AND (n GE 1)) THEN BEGIN ;Draw resizing handles xmin=min(x, max=xmax) ymin=min(y, max=ymax) n = 4 handle = [[xmin, ymin], [xmin, ymax], [xmax,ymin],[xmax, ymax]] GOTO, do_handle ENDIF ENDCASE 3: BEGIN ;Circle/ Ellipse a = !d.x_size / float(!d.y_size) ;Aspect ratio dx = p[0] - p[2] dy = p[1] - p[3] r = sqrt(dx^2 + dy^2) if r eq 0.0 then return dx = dx/r dy = dy/r n = 128 t = findgen(n) * (( 2 * !pi)/ (n-1)) ;Angles.. ; The whole ball of wax xy = [[cos(t) * r], [sin(t) * r/p[18]]] # [[dx, -dy],[dy, dx]] xy = reform([p[2] + xy[*,0], p[3] + a*xy[*,1]], n,2,/OVER) xy = transpose(xy) goto, do_fill ENDCASE ;Circle 4: BEGIN ;Box xy = p[[[0,1],[0,3],[2,3],[2,1],[0,1]]] n = 5 goto, do_fill ENDCASE else: print,'Unknown object' ENDCASE end pro ann_make_draw_button, st ; Make mode buttons compile_opt hidden a = widget_base(st.base, /ROW, Exclusive=!version.os ne 'Win32') id = lonarr(n_elements(st.mode_buttons)) ;Id arrays wsize = 32 window, xsize=wsize, ysize=wsize, /pix, /free w2 = wsize/2 ;Handy constants w9 = 9*wsize/10 w1 = wsize/10 w3 = wsize/3 xyouts, w1, wsize/4, 'Abc', /dev, chars= wsize/(3.2* !d.x_ch_size) ;Text id[0] = WIDGET_BUTTON(a, /NO_REL, value= b_button(tvrd())) erase arrow, w1, w3, w9, w3, /device, hsize = 10 ;Arrows/ lines plots, [w1, w9], wsize - [w3, w3], lines=3, /DEV id[1] = WIDGET_BUTTON(a, /NO_REL, value= b_button(tvrd())) erase ;polyfill, [w1,w2,w1], [w1, w9, w9], /dev ;Polygons ;plots, [ 2, 4, 6, 8, 10, 12, 10, 8, 8]*wsize/16, $ ;Drag/Draw ; [ 1, 3, 7, 9, 9, 11, 16, 14, 6]*wsize/20, /dev ;id[2] = WIDGET_BUTTON(a, /NO_REL, value= b_button(tvrd())) ;erase ;n = 32 ;Circles ;t = findgen(n) *(2 * !pi / (n-1)) ;plots, wsize/3 * cos(t) + (w2), wsize/3 * sin(t) + w2, /dev ;id[3] = WIDGET_BUTTON(a, /NO_REL, value= b_button(tvrd())) ;erase ;plots, [w1,w1, w9, w9, w1], [w1, w9, w9, w1, w1], /dev ;Squares ;id[4] = WIDGET_BUTTON(a, /NO_REL, value= b_button(tvrd())) ;erase for i=0, n_elements(id)-4 do $ ;Set up uv = Mn WIDGET_CONTROL, id[i], SET_UVALUE='M'+strtrim(i,2) WIDGET_CONTROL, id[0], /SET_BUTTON ;Set initial choice wdelete st.mode_buttons = id end PRO ANNOTATE2, DRAWABLE = draw, WINDOW = window, LOAD_FILE=load_file, $ COLOR_INDICES=color_indices, TEK_COLORS = tek_colors ;+ ; NAME: ; ANNOTATE2 - Slightly revised version of ANNOTATE designed to ; work within TCTOOL. ; ; PURPOSE: ; This procedure is a general purpose drawing program/widget to ; annotate displays. Drawing objects include text, lines, arrows, ; polygons, rectangles, circles, and ellipses. ; ; This TCTOOL version is stripped down to just text, lines and arrows. ; ; CATEGORY: ; Widgets. Will also work with plain windows. ; ; CALLING SEQUENCE: ; ANNOTATE ; ; INPUTS: ; No required inputs. ; ; KEYWORD PARAMETERS: ; COLOR_INDICES: an array of color indices from which the user ; can choose colors. For example, to allow the user ; to choose 10 colors, spread evenly over the ; available indices, set the keyword as folows: ; COLOR_INDICES = INDGEN(10) * (!D.N_COLORS-1) / 9 ; DRAWABLE: the widget ID of the draw widget for the annotations. ; This is mutually exclusive with WINDOW. ; LOAD_FILE: the name of an annotation format file to load after ; initialization. ; TEK_COLORS: if set, the Tektronix color table is loaded ; starting at color index TEK_COLORS(0), with ; TEK_COLORS(1) color indices. The Tektronix color ; table contains up to 32 distinct colors suitable ; for graphics. ; WINDOW: the window index number of the window to receive the ; annotations. ; ; OUTPUTS: ; This procedure has no explicit outputs. Menu choices exist to ; write TIFF, GIF, or PostScript bitmap files. Encapsulated ; or standalone PostScript files may also be created. ; ; SIDE EFFECTS: ; Annotations are made in the designated window or draw widget. ; ; RESTRICTIONS: ; This is a simple drawing program. ; ; PROCEDURE: ; If neither TEK_COLORS or COLOR_INDICES are specified, the default ; is to load 10 colors, evenly distributed over those available. ; ; If neither WINDOW or DRAWABLE are specified, the current window ; is used. ; ; EXAMPLE: ; TVSCL, HANNING(300,200) ;Output an image in the current window ; ANNOTATE ;Annotate it ; ; MODIFICATION HISTORY: ; DMS, RSI, July, 1993. Original version. ;- nmodes = 5 sl_width = 128 st = { ANN_STATE, $ mode : 0, $ minor_mode_id: 0L, $ minor_mode: 0, $ p: fltarr(21), $ ;General params open : 0, $ ;NE 0 if an object is open base : 0L, $ current: 0L, $ ;Current object if saved on list objlist : 0L, $ ;object container xy: 0L, $ pos: fltarr(2), $ ;Current position orig: fltarr(2), $ ;Beginning of drag txt: 'Text',$ ;Current contents of text widget mode_buttons: lonarr(nmodes), $ mode_bases : lonarr(nmodes+1), $ draw_win : 0L, $ backing : lonarr(2), $ ;0 = original bitmap, 1 = with closed objects color_id: 0L, $ thick_id: 0L, $ txt_id: 0L, $ txt_size_id: 0L, $ txt_ali_id: 0L, $ txt_font_id: 0L, $ ori_id: 0L, $ linestyle_id : 0L, $ buttons: 0L, $ granularity : 1.0, $ instruct: 0L, $ line_arrow_id: 0L, $ head_size_id: 0L, $ fill_mode_id: 0L, $ fill_mode: 0, $ handle: fltarr(2,4), $ temp: fltarr(3), $ poly_style: lonarr(nmodes), $ poly_angle: lonarr(nmodes), $ poly_spacing: lonarr(nmodes), $ ecc_id: 0L, $ spline_id: 0L, $ file: 'annotate.dat', $ ihandle: 0, $ ps_encap: 0, $ ps_color: 0, $ ps_orien: 0, $ ps_width: 5.0, $ ps_units: 0 } st.p[18] = 1.0 ;Eccent ann_base = WIDGET_BASE(title='Annotate', /COLUMN) ;Our base st.base = ann_base win = !d.window ;Default window use_xmgr = 0 if n_elements(window) eq 1 then win = window $ else if n_elements(draw) eq 1 then begin widget_control, draw, get_value = win, EVENT_PRO = 'ANN_DRAW_EVENT', $ SET_UVALUE = ann_base use_xmgr = 1 endif if win lt 0 then message,'No draw window active' st.draw_win = win wset, win nx = !d.x_size ny = !d.y_size for i=0,1 do begin ;Get 2 backing pixmaps. window, /FREE, /PIXMAP, xs = nx, ys = ny device, copy = [0,0,nx, ny, 0, 0, win] ;Copy original window st.backing[i] = !d.window endfor st.objlist = WIDGET_BASE(ann_base, UVALUE = 0, $ ;Object list holder xsize = 2, ysize=2) st.xy = WIDGET_BASE(ann_base, UVALUE = 0, $ ;Polygon points holder xsize = 2, ysize=2) junk = WIDGET_BASE(ann_base, /ROW) tmp = CW_PDMENU(junk, /RETURN_NAME, UVALUE='TOPROW', [ $ {CW_PDMENU_S, flags: 1, name: 'File'}, $ {CW_PDMENU_S, flags: 0, name: 'Load'}, $ {CW_PDMENU_S, flags: 0, name: 'Save'}, $ {CW_PDMENU_S, flags: 1, name: 'Write PostScript'}, $ {CW_PDMENU_S, flags: 0, name: 'Everything'}, $ {CW_PDMENU_S, flags: 2, name: 'Objects only'}, $ {CW_PDMENU_S, flags: 1, name: 'Export Bitmap'}, $ {CW_PDMENU_S, flags: 0, name: 'GIF'}, $ {CW_PDMENU_S, flags: 0, name: 'PostScript'}, $ {CW_PDMENU_S, flags: 2, name: 'TIFF'}, $ {CW_PDMENU_S, flags: 0, name: 'Clear'}, $ {CW_PDMENU_S, flags: 2, name: 'Exit'}]) tmp = WIDGET_BUTTON(junk, value='Help', UVALUE='Help', /NO_REL) tmp = WIDGET_BUTTON(junk, value='Options', UVALUE='Options', /NO_REL) junk = WIDGET_BASE(ann_base, /ROW) tmp = WIDGET_BUTTON(junk, VALUE='Save', UVALUE='Save', /NO_REL) st.minor_mode_id = CW_BGROUP(junk, /EXCLUSIVE, /ROW, /NO_REL, $ LABEL_LEFT = 'Mode:', $ ['Draw', 'Edit','Select'], $ UVALUE='@Rst.minor_mode = ev.value', SET_VALUE=0) ann_make_draw_button, st scolor = 0 ncolors = 10 if n_elements(tek_colors) ge 1 then begin scolor = tek_colors[0] if n_elements(tek_colors) ge 2 then ncolors = tek_colors[1] else ncolors=8 color_indices = indgen(ncolors) + scolor endif else if n_elements(color_indices) gt 0 then begin ncolors = n_elements(color_indices) endif else begin color_indices = (!d.n_colors-1) * lindgen(ncolors) / (ncolors-1) endelse st.color_id = CW_CLR_INDEX(ann_base, LABEL = 'Color:', XSIZE=160, $ NCOLORS = ncolors, START_COLOR = scolor, $ COLOR_VALUES=color_indices, uvalue = '@Rst.p[4] = ev.value') st.p[4] = color_indices[ncolors-1] ;Init color junk = WIDGET_BASE(ann_base, /ROW) st.linestyle_id = CW_BSELECTOR(junk, LABEL_TOP = 'Linestyle:', $ ['Solid', 'Dots', 'Dashes', 'Dash-Dot', 'Dash-3 Dots', $ 'Long Dash'], uvalue = '@Rst.p(6) = ev.value') st.thick_id = WIDGET_SLIDER(junk, XSIZE = sl_width, MIN=0, $ MAX=200, TITLE = 'Thickness', /DRAG, $ UVALUE='@Rst.p(5) = ev.value/10.') st.instruct = WIDGET_TEXT(ann_base, value = ' ', xsize=32, ysize=1, /FRAME) tmp_base = WIDGET_BASE(ann_base, /FRAME) for i=0, nmodes do BEGIN base = WIDGET_BASE(tmp_base, /COLUMN) st.mode_bases[i] = base WIDGET_CONTROL, base, map = i eq 0 ENDFOR ; ; Text widget top = st.mode_bases[0] junk = WIDGET_BASE(top, /ROW) junk1 = WIDGET_LABEL(junk, Value = 'Text: ') st.txt_id = WIDGET_TEXT(junk, xs = 32, ys = 1, /frame, /edit, $ uvalue = '#Rst.txt=v[0]', value=st.txt) junk = WIDGET_BASE(top, /ROW) st.txt_size_id = WIDGET_SLIDER(junk, TITLE='Size', Value=0, XSIZE = sl_width, $ MAX=100, MIN=0, /DRAG, UVALUE = '@Rst.p[7] = ev.value/10.') st.ori_id = WIDGET_SLIDER(junk, TITLE='Orientation', Value = 0, $ MAX = 360, min = 0, /DRAG, UVALUE = '@Rst.p[14] = ev.value', $ XSIZE = sl_width) st.txt_ali_id = CW_BGROUP(top, LABEL_LEFT='Alignment:', /EXCLUSIVE, /ROW, $ ['Left', 'Center', 'Right' ], SET_VALUE=0, /NO_REL, $ UVALUE='@Rst.p[12] = ev.value/2.') fonts = ['Simplex Roman ', 'Simplex Greek', 'Duplex Roman', $ 'Complex Roman', 'Complex Greek', 'Complex Italic', $ 'Math & Special', 'Special', 'Gothic', 'Script', 'Complex Script', $ 'Gothic Italian', 'Gothic German', 'Cyrillic', 'Triplex Roman', $ 'Triplex Italic'] junk = WIDGET_BASE(top, /ROW) junk1 = WIDGET_LABEL(junk, VALUE = 'Font:') st.txt_font_id = CW_BSELECTOR(junk, fonts, $ uvalue = '@Rst.p[13] = ev.value + 3') ; Arrow Widget top = st.mode_bases[1] junk = WIDGET_BASE(top, /ROW) st.line_arrow_id = CW_BGROUP(junk, /EXCLUSIVE, /ROW, /NO_REL, $ ['Line','Arrow', 'Solid Arrow'], $ UVALUE='@Rst.p[17]=ev.value', SET_VALUE=0, LABEL_LEFT='Mode:') st.head_size_id = WIDGET_SLIDER(top, TITLE='Head Size', VALUE = 0, $ XSIZE=sl_width, MAX=100, /DRAG, UVALUE='@Rst.p[15] = ev.value/10.') ; Polygon Widget top = st.mode_bases[2] st.fill_mode_id = CW_BGROUP(top, /EXCLUSIVE, /ROW, LABEL_LEFT = 'Mode:', $ ['Draw', 'Edit', 'Delete'], /NO_REL, $ UVALUE='@Rst.fill_mode = ev.value', SET_VALUE=0) ; Circle widget top = st.mode_bases[3] st.ecc_id = WIDGET_SLIDER(top, TITLE='Eccentricity', VALU=0, /DRAG, $ XSIZE=sl_width, MIN=0, MAX=100, UVALUE='@Rst.p[18]=ev.value/10.+1') ; Square Widget has nothing unique for i=2, nmodes-1 do begin ;Make polyfill controls for the bases top = st.mode_bases[i] st.poly_style[i] = CW_BGROUP(top, /EXCLUSIVE, /ROW, $ LABEL_LEFT = 'Fill: ', /NO_REL, $ ['None', 'Solid', 'Lines'], $ UVALUE='@Rst.p[8]=ev.value', SET_VALUE=0) if i eq 2 then $ st.spline_id = CW_BGROUP(top, /EXCLUSIVE, /ROW, /NO_REL, $ LABEL_LEFT='Interpolation:', ['None', 'Spline'], $ UVALUE='@Rst.p[20]=ev.value', SET_VALUE=0) junk = WIDGET_BASE(top, /ROW) st.poly_angle[i] = WIDGET_SLIDER(junk, TITLE='Line Angle', VALU=0, /DRAG, $ MIN=0, MAX=180, UVALUE='@Rst.p[10]=ev.value', XSIZE=sl_width) st.poly_spacing[i] = WIDGET_SLIDER(junk, TITLE='Line Spacing', $ VALU=0, /DRAG, MIN=0, MAX=50, UVALUE='@Rst.p[9]=ev.value', $ XSIZE=sl_width) endfor ;******************************************* ; Options Widget top = st.mode_bases[nmodes] junk = WIDGET_BASE(top, /ROW) junk1 = WIDGET_LABEL(junk, value = 'Grid granularity:') junk1 = WIDGET_TEXT(junk, /EDIT, /FRAME, xsize=4, ysize=1, value='1', $ UVALUE = '# st.granularity=ann_get_num(v(0), ev.id, 1, 128)') junk = WIDGET_BASE(top, /COLUMN, /FRAME) junk1 = WIDGET_LABEL(junk, VALUE= 'PostScript Options') junk1 = WIDGET_BASE(junk, /ROW) junk2 = CW_BGROUP(junk1, /EXCLUSIVE, /ROW, /NO_REL, $ ['Std', 'Encapsulated'], $ UVALUE='@ st.ps_encap=ev.value', SET_VALUE=0) junk2 = CW_BGROUP(junk1, /EXCLUSIVE, /ROW, /NO_REL, $ ['Mono', 'Color'], $ UVALUE='@ st.ps_color=ev.value', SET_VALUE=0) junk1 = CW_BGROUP(junk, /EXCLUSIVE, /ROW, /NO_REL, $ ['Portrait', 'Landscape'], $ UVALUE='@ st.ps_orien=ev.value', SET_VALUE=0) junk1 = WIDGET_BASE(junk, /ROW) junk2 = WIDGET_LABEL(junk1, VALUE='Width:') junk2 = WIDGET_TEXT(junk1, /EDIT, /FRAME, xsize=5, ysize=1, value='5.0', $ UVALUE='# st.ps_width=ann_get_num(v(0), ev.id, .1, 200)') junk2 = CW_BGROUP(junk1, /EXCLUSIVE, /ROW, /NO_REL, $ ['In', 'Cm'], UVALUE='@ st.ps_units=ev.value', SET_VALUE=0) junk = WIDGET_BUTTON(top, VALUE='Dismiss', UVALUE='Dismiss') wset, win wshow, win if n_elements(tek_colors) ge 1 then tek_color, scolor, ncolors widget_control, ann_base, /REAL WIDGET_CONTROL, st.color_id, SET_VALUE = color_indices[ncolors-1] ;Set color if keyword_set(load_file) then $ ;Load a file? ann_xfer_file, st, load_file, /LOAD WIDGET_CONTROL, ann_base, SET_UVALUE = st, /NO_COPY if use_xmgr then xmanager, 'annotate', ann_base $ else xmgr_fake, ann_base, win end