; $Id: cw_colorsel.pro,v 1.16 2001/01/15 22:28:01 scottm Exp $ ; ; Copyright (c) 1992-2001, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ;+ ; NAME: ; CW_COLORSEL ; ; PURPOSE: ; CW_COLORSEL is a compound widget that displays all the colors ; in the current colormap and allows the user to select the color ; indices via the mouse or with sliders. ; ; CATEGORY: ; Compund widgets. ; ; CALLING SEQUENCE: ; widget = CW_COLORSEL(Parent) ; ; INPUTS: ; Parent: The ID of the parent widget. ; ; KEYWORD PARAMETERS: ; FRAME: If set, a frame is drawn around the widget. ; UVALUE: The user value for the widget. ; UNAME: The user value for the widget. ; XOFFSET: The X offset position ; YOFFSET: The Y offset position ; ; OUTPUTS: ; The ID of the created widget is returned. ; ; SIDE EFFECTS: ; This widget generates event structures containing a field named ; VALUE, which contains the colormap index selected by the user. ; ; PROCEDURE: ; The COLORSEL widget displays all the colors in the current ; colormap in a 16x16 (320x320 pixels) grid. To select a color ; index, the user moves the mouse pointer over the desired ; color square and presses any mouse button. Alternatively, the ; color index can be selected by moving one of the three sliders ; provided around the grid. ; ; WIDGET_CONTROL, SET_VALUE=index can be used to set the current ; color index. ; ; WIDGET_CONTROL, SET_VALUE=-1 informs the widget to initialize ; itself and redraw. It should be called when any of the ; following happen: ; - The widget needs redrawing. ; - The brightest or darkest color has changed. ; ; WIDGET_CONTROL, GET_VALUE=var can be used to retrieve the ; current color index. ; ; MODIFICATION HISTORY: ; March 30, 1992, AB ; Removed the relevant code from XPALETTE.PRO and modified ; it to create this reusable widget cluster. ; September 4, 1992, SR ; Fixed a bug where the value of the xslider was calculated ; as negative and WIDGET_CONTROL, SET_VALUE failed. ; 7 April 1993, AB, Removed state caching. ; October 20, 1993, KDB ; Changed return value in function CSEL_GET_VALUE ; from state.cur_idx to ret ; 23 May 1994, AB ; Added NOTIFY_REALIZE routine to eliminate the need ; to call "WIDGET_CONTROL, SET_VALUE=-1" when the widget ; is realized. ; 29 Nov 2000, DD ; Force all visuals to honor indexed colors; temporarily set ; DEVICE, DECOMPOSED=0 as needed. Also, maintain a backing ; store for the display of the color ramp. ;- pro CSEL_SETSLIDERS, state, type, cur_x, cur_y, idx ; Set the three position sliders according to the supplied values. ; Move the mark to the new location. ; entry: ; type - Controls operation of procedure. Can have the following ; values: ; 0 - Set all three sliders from IDX. state.x and state.y ; are updated. ; 1 - Set Row and Column sliders from IDX. Update ; state.x and state_y. ; 2 - Set Column and Index sliders from CUR_X and CUR_Y. ; 3 - Set Row and Index sliders from CUR_X and CUR_Y. compile_opt hidden change_x = 0 change_y = 0 change_idx = 0 nc = !D.table_size if (type lt 2) then begin ; From IDX if (idx ge nc) then idx = nc -1 if (type eq 0) then change_idx = 1 ; Update slider to match ; Calculate current Y and see if slider value needs changing tmp = idx / 16 if (idx ne cur_y) then begin cur_y = tmp change_y = 1 endif ; Calculate current X and see if slider value needs changing tmp = idx - (cur_y * 16) if (tmp GE 0) AND (tmp ne cur_x) then begin cur_x = tmp change_x = 1 endif endif else begin ; From CUR_X and CUR_Y if (type eq 2) then begin tmp = cur_x while (((cur_y * 16) + tmp) ge nc) do tmp = tmp - 1 if (tmp ne cur_x) then begin cur_x = tmp change_x = 1 endif endif else begin tmp = cur_y while (((tmp * 16) + cur_x) ge nc) do tmp = tmp - 1 if (tmp ne cur_y) then begin cur_y = tmp change_y = 1 endif endelse IDX = (cur_y * 16B) + cur_x change_idx = 1 endelse if (change_x) then WIDGET_CONTROL, set_value=cur_x, state.column if (change_y) then WIDGET_CONTROL, set_value=cur_y, state.row if (change_idx) then WIDGET_CONTROL, set_value=idx, state.by_index state.x = cur_x state.y = cur_y CSEL_MVMARK, state, idx end function CSEL_NEW_COLORS, state compile_opt hidden ; Choose the best foreground and background colors for the current ; color maps. Returns 1 if the colors changed, 0 otherwise. res = 0 luminance = ct_luminance(dark=dark_col, bright=bright_col) if (bright_col ne state.bright_idx) then begin state.bright_idx = bright_col res = 1 endif if (dark_col ne state.dark_idx) then begin state.dark_idx = dark_col res = 1 endif if (res ne 0) then begin marker = bytarr(20, 20) + state.dark_idx marker[2, 2] = bytarr(16, 16) + state.bright_idx marker[4, 4] = bytarr(12, 12) + state.dark_idx marker[6, 6] = bytarr(8, 8) + state.bright_idx marker[8, 8] = bytarr(4, 4) + state.dark_idx state.marker = marker marker = bytarr(20, 20) + state.dark_idx marker[1:18, 2:17] = bytarr(18, 16) + state.bright_idx state.unreach = marker endif return, res end pro CSEL_MVMARK, state, to_index ; Move the marker and update the current color square. compile_opt hidden cur_idx = state.cur_idx new_pos = to_index ne cur_idx ; Restore current square save_win = !D.WINDOW DEVICE, GET_DECOMPOSED=save_decomp DEVICE, DECOMPOSED=0 wset, state.spectrum_win if (new_pos) then begin tv, bytarr(20, 20) + byte(cur_idx), cur_idx state.cur_idx = (cur_idx = to_index) endif tv, state.marker, cur_idx wset, save_win DEVICE, DECOMPOSED=save_decomp end function CSEL_EVENT, ev compile_opt hidden ; Recover the state of this compound widget parent = ev.handler stash = WIDGET_INFO(parent, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY case (ev.id) of state.by_index: begin set_slide_idx: CSEL_SETSLIDERS, state, 1, state.x, state.y, ev.value end state.column: begin CSEL_SETSLIDERS, state, 2, byte(ev.value), state.y, tmp end state.row : begin CSEL_SETSLIDERS, state, 3, state.x, byte(ev.value), tmp end state.spectrum: begin if (ev.press ne 0) then begin tmp = ((319 - ev.y) / 20 ) * 16 + (ev.x / 20) CSEL_SETSLIDERS, state, 0, state.x, state.y, tmp endif else begin WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, 0 ; Swallow key release events endelse end endcase value=state.cur_idx WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, {COLORSEL_EVENT, ID: parent, TOP:ev.top, HANDLER:0L, VALUE: value } end pro CSEL_REALIZE, id compile_opt hidden ;Retrieve the state information. stash = WIDGET_INFO(id, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY ; Initialize everything ; What is the spectrum window id? WIDGET_CONTROL, state.spectrum, get_value=tmp state.spectrum_win=tmp junk = CSEL_NEW_COLORS(state) ; Draw spectrum widgets save_win = !D.WINDOW DEVICE, GET_DECOMPOSED=save_decomp DEVICE, DECOMPOSED=0 wset, state.spectrum_win tmp=bytarr(20,20) for i = 0, !d.table_size-1 do begin tv, tmp, i tmp = tmp + 1B endfor ; Draw the unreachable squares tmp = state.unreach for i = !d.table_size, 255 do tv, tmp, i WSET, save_win DEVICE, DECOMPOSED=save_decomp ; Highlight the current position using the marker CSEL_MVMARK, state, state.cur_idx WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY end pro CSEL_SET_VALUE, id, value compile_opt hidden if (value eq -1) then begin CSEL_REALIZE, id endif else begin ;Retrieve the state information. stash = WIDGET_INFO(id, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY CSEL_SETSLIDERS, state, 0, 0, 0, value WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY endelse end function CSEL_GET_VALUE, id compile_opt hidden ;Retrieve the state information. stash = WIDGET_INFO(id, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY ret = state.cur_idx WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, ret end function CW_COLORSEL, parent, FRAME = frame, UVALUE = uval, $ XOFFSET=xoff, YOFFSET=yoff, UNAME=uname state = { by_index:0L, $ ; By index slider widget row:0L, $ ; Row slider widget column:0L, $ ; Column slider widget spectrum:0L, $ ; Spectrum widget first_child:0L, $ ; ID of first child of base. x:0L, y:0L, $ ; Current X and Y of marker in spectrum cur_idx:0, $ ; Current index marker:bytarr(20,20,/nozero), $ ; Byte array used as marker unreach:bytarr(20,20,/nozero), $ ; Image for unreachable colors spectrum_win:0, $ ; Spectrum draw window index bright_idx:-1, dark_idx:-1} ; Dark and bright colors for marker on_error,2 ;Return to caller if an error occurs IF NOT (KEYWORD_SET(frame)) THEN frame = 0 IF NOT (KEYWORD_SET(uval)) THEN uval = 0 IF NOT (KEYWORD_SET(uname)) THEN uname = 'CW_COLORSEL_UNAME' IF NOT (KEYWORD_SET(xoff)) THEN xoff = 0 IF NOT (KEYWORD_SET(yoff)) THEN yoff = 0 version = WIDGET_INFO(/VERSION) newer_motif = (version.style eq 'Motif') and (version.release ne '1.0') ; Create widgets base = WIDGET_BASE(parent, frame=frame, uvalue=uval, uname=uname, $ EVENT_FUNC='CSEL_EVENT', FUNC_GET_VALUE='CSEL_GET_VALUE', $ PRO_SET_VALUE='CSEL_SET_VALUE', NOTIFY_REALIZE='CSEL_REALIZE', $ XOFFSET=xoff, YOFFSET=yoff) if (newer_motif) then begin state.row = WIDGET_SLIDER(base, min=15, max=0, xoff = 325, $ yoff= 75, /vert, val=0, title='Row', ysize=320, $ uname=uname+'_ROW') endif else begin state.row = WIDGET_SLIDER(base, min=15, max=0, xoff = 325, $ yoff= 75, /vert, val=0, title='Row', ysize=320, xsize=75, $ uname=uname+'_ROW') endelse state.column = WIDGET_SLIDER(base, max=15, title='Column', $ xsize=320, yoff=400, uname=uname+'_COLUMN') state.spectrum=WIDGET_DRAW(base, xsize=320, ysize=320, /frame, /button, $ yoff=75, retain=2, uname=uname+'_SPECTRUM') state.by_index = WIDGET_SLIDER(base, max=!d.table_size-1, $ title = 'By Index', xsize=320,uname=uname+'_INDEX') state.cur_idx = 0 state.x = 0 state.y = 0 ; Stash the state WIDGET_CONTROL, WIDGET_INFO(base, /CHILD), SET_UVALUE=state, /NO_COPY return, base end