; $Id: cw_rgbslider.pro,v 1.26 2004/02/27 23:06:40 douge Exp $ ; ; Copyright (c) 1992-2004, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ;+ ; NAME: ; CW_RGBSLIDER ; ; PURPOSE: ; CW_RGBSLIDER is a compund widget that provides three sliders for ; adjusting color values. The RGB, CMY, HSV, and HLS color systems ; can all be used. No matter which color system is in use, ; the resulting color is always supplied in RGB, which is the ; base system for IDL. ; ; CATEGORY: ; Compound widgets. ; ; CALLING SEQUENCE: ; Widget = CW_RGBSLIDER(Parent) ; ; INPUTS: ; Parent: The ID of the parent widget. ; ; KEYWORD PARAMETERS: ; COLOR_INDEX: If set, display a small rectangle with the ; selected color, using the given index. ; The color is updated as the values are changed. ; CMY: If set, the initial color system used is CMY. ; DRAG: Set to zero if events should only be generated when ; the mouse button is released. If this keyword is set, ; events will be generated continuously when the sliders ; are adjusted. Note: On slow systems, /DRAG performance ; can be inadequate. The default is DRAG=0. ; FRAME: If set, a frame will be drawn around the widget. The ; default is FRAME=0 (no frame drawn). ; GRAPHICS_LEVEL: Set to 2 to use RGB graphics. ; Set to 1 for Direct graphics (default). ; If set to 2 a small rectangle with the RGB passed ; in through the VALUE keyword is displayed. ; This color swatch is updated as the color value is changed. ; HSV: If set, the initial color system used is HSV. ; HLS: If set, the initial color system used is HLS. ; LENGTH: The length of the sliders. The default = 256. ; RGB: If set, the initial color system used is RGB. ; This is the default. ; UVALUE: The user value for the widget. ; UNAME: The user name for the widget. ; VALUE: The RGB value for the color swatch. ; VERTICAL: If set, the sliders will be oriented vertically. ; The default is VERTICAL=0 (horizontal sliders). ; ; OUTPUTS: ; The ID of the created widget is returned. ; ; SIDE EFFECTS: ; This widget generates event structures containing a three fields ; named 'R', 'G', and 'B' containing the Red, Green, and Blue ; components of the selected color. ; ; Specifying the COLOR_INDEX keyword or the GRAPHIC_LEVEL keyword ; set to 2 have the side effect of displaying a draw widget ; with the represented color. Note that these are, in general, ; mutually exclusive. If you are using the Object graphics ; system, it's recommended that you set the GRAPHICS_LEVEL ; keyword to two (COLOR_INDEX keyword is ignored in this case) ; and pass in the initial RGB value through ; the VALUE keyword. If you are using Direct graphics (and ; want to display the color swatch) it's recommended to ; set the COLOR_INDEX keyword to the initial color index, ; set GRAPHICS_LEVEL keyword to one (default), and pass in the ; initial RGB value through the VALUE keyword. ; ; PROCEDURE: ; The CW_RGBSLIDER widget has the following controls: ; ; Color System Selection: A droplist which allows the user ; to change between the supported color systems. ; ; Color adjustment sliders: Allow the user to select a new color ; value. ; ; By adjusting these controls, the user selects color values which ; are reported via the widget event mechanism. ; ; MODIFICATION HISTORY: ; April 1, 1992, AB ; Based on the RGB code from XPALETTE.PRO, but extended to ; support color systems other than RGB. ; 7 April 1993, AB, Removed state caching. ; 10 May 1994, DMS, Added Color_index param to display color. ; Feb. 1999, WSO, Added VALUE and GRAPHICS_LEVEL features. ; Aug. 2000, DLD, Provided improved support for display on devices ; using decomposed color. ;- ; ----------------------------------------------------------------------------- pro CW_RGB_CHNG_CS, state, base_idx ; Change the current color system. ; State is the state structure to use ; base_idx is the index into state.select_b of the base to change to. COMPILE_OPT hidden case (base_idx) of 0: begin ; RGB WIDGET_CONTROL, state.r_sl, set_value=state.r_v WIDGET_CONTROL, state.g_sl, set_value=state.g_v WIDGET_CONTROL, state.b_sl, set_value=state.b_v end 1: begin ; CMY WIDGET_CONTROL, state.c_sl, set_value=255-state.r_v WIDGET_CONTROL, state.m_sl, set_value=255-state.g_v WIDGET_CONTROL, state.y_sl, set_value=255-state.b_v end 2: begin ; HSV COLOR_CONVERT, state.r_v, state.g_v, state.b_v, a, b, c, /RGB_HSV WIDGET_CONTROL, state.hsv_h_sl, set_value=(state.h_v = a) WIDGET_CONTROL, state.hsv_s_sl, set_value=(state.f1_v = b) WIDGET_CONTROL, state.hsv_v_sl, set_value=(state.f2_v = c) end 3: begin ; HLS COLOR_CONVERT, state.r_v, state.g_v, state.b_v, a, b, c, /RGB_HLS WIDGET_CONTROL, state.hls_h_sl, set_value=(state.h_v = a) WIDGET_CONTROL, state.hls_l_sl, set_value=(state.f1_v = b) WIDGET_CONTROL, state.hls_s_sl, set_value=(state.f2_v = c) end endcase ; Change the displayed slider base WIDGET_CONTROL, map=0, state.select_b[state.curr_b_idx] WIDGET_CONTROL, map=1, state.select_b[base_idx] state.curr_b_idx = base_idx end ; ----------------------------------------------------------------------------- ; PRO CW_RGB_SET_DRAW, state COMPILE_OPT hidden if state.color_window lt 0 then begin ;Initialize? if state.graphicsLevel eq 2 then begin WIDGET_CONTROL, state.color_draw, GET_VALUE=oWindow if (OBJ_VALID(oWindow)) then $ oWindow->Erase, COLOR=[state.r_v, state.g_v, state.b_v] endif else begin TVLCT, state.r_v, state.g_v, state.b_v, state.color_index if (state.color_draw gt 0) then begin WIDGET_CONTROL, state.color_draw, GET_VALUE=i swin = !d.window WSET, i state.color_window = i DEVICE, GET_DECOMPOSED=decomp if (decomp eq 0) then begin ERASE, state.color_index ;Set to our value endif else begin ERASE, ISHFT(ULONG(state.b_v),16) + $ ISHFT(ULONG(state.g_v),8) + $ ULONG(state.r_v) endelse WSET, swin endif endelse endif else begin if state.graphicsLevel eq 2 then begin WIDGET_CONTROL, state.color_draw, GET_VALUE=oWindow oWindow->Erase, COLOR=[state.r_v, state.g_v, state.b_v] endif else begin TVLCT, state.r_v, state.g_v, state.b_v, state.color_index colormapApplies = COLORMAP_APPLICABLE(redrawRequired) DEVICE, GET_DECOMPOSED=decomp IF ((redrawRequired ne 0) or (decomp ne 0)) then begin swin = !d.window WSET, state.color_window if (decomp eq 0) then begin ERASE, state.color_index ;Set to our value endif else begin ERASE, ISHFT(ULONG(state.b_v),16) + $ ISHFT(ULONG(state.g_v),8) + $ ULONG(state.r_v) endelse WSET, swin endif endelse endelse end ; ----------------------------------------------------------------------------- ; Called at widget realization time to set the color of the draw widget ; PRO CW_RGB_INIT, base COMPILE_OPT hidden ; Recover the state of this compound widget stash = WIDGET_INFO(base, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state CW_RGB_SET_VAL, base, [state.r_v, state.g_v, state.b_v] end ; ----------------------------------------------------------------------------- ; function CW_RGB_EVENT, ev COMPILE_OPT hidden ; Recover the state of this compound widget base = ev.handler stash = WIDGET_INFO(base, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY case (ev.id) of state.select_s : begin if (state.curr_b_idx ne (ev.index)) then $ CW_RGB_CHNG_CS,state,ev.index WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, 0 ; Swallow the event end state.r_sl: state.r_v = ev.value state.g_sl: state.g_v = ev.value state.b_sl: state.b_v = ev.value state.c_sl: state.r_v = 255 - ev.value state.m_sl: state.g_v = 255 - ev.value state.y_sl: state.b_v = 255 - ev.value state.hsv_h_sl: begin state.h_v = ev.value goto, calc_new_hsv end state.hsv_s_sl: begin state.f1_v = ev.value goto, calc_new_hsv end state.hsv_v_sl: begin state.f2_v = ev.value calc_new_hsv: COLOR_CONVERT, state.h_v, state.f1_v, state.f2_v, a, b, c, /HSV_RGB state.r_v = a state.g_v = b state.b_v = c end state.hls_h_sl: begin state.h_v = ev.value goto, calc_new_hls end state.hls_l_sl: begin state.f1_v = ev.value goto, calc_new_hls end state.hls_s_sl: begin state.f2_v = ev.value calc_new_hls: COLOR_CONVERT, state.h_v, state.f1_v, state.f2_v, a, b, c, /HLS_RGB state.r_v = a state.g_v = b state.b_v = c end state.color_draw : endcase if ((state.color_index ge 0) or (state.graphicsLevel eq 2)) then $ CW_RGB_SET_DRAW, state ; Return an RGB event ret = { RGB_EVENT, ID: base, TOP:ev.top, HANDLER:0L, $ R:state.r_v, G:state.g_v, B:state.b_v } WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, ret end ; ----------------------------------------------------------------------------- ; pro CW_RGB_SET_VAL, id, value COMPILE_OPT hidden ; Recover the state of this compound widget stash = WIDGET_INFO(id, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY state.r_v = value[0] state.g_v = value[1] state.b_v = value[2] case (state.curr_b_idx) of 0: begin ; RGB WIDGET_CONTROL, state.r_sl, set_value=state.r_v WIDGET_CONTROL, state.g_sl, set_value=state.g_v WIDGET_CONTROL, state.b_sl, set_value=state.b_v end 1: begin ; CMY WIDGET_CONTROL, state.c_sl, set_value=255-state.r_v WIDGET_CONTROL, state.m_sl, set_value=255-state.g_v WIDGET_CONTROL, state.y_sl, set_value=255-state.b_v end 2: begin ; HSV COLOR_CONVERT, state.r_v, state.g_v, state.b_v, a, b, c, /RGB_HSV WIDGET_CONTROL, state.hsv_h_sl, set_value=(state.h_v = a) WIDGET_CONTROL, state.hsv_s_sl, set_value=(state.f1_v = b) WIDGET_CONTROL, state.hsv_v_sl, set_value=(state.f2_v = c) end 3: begin ; HLS COLOR_CONVERT, state.r_v, state.g_v, state.b_v, a, b, c, /RGB_HLS WIDGET_CONTROL, state.hls_h_sl, set_value=(state.h_v = a) WIDGET_CONTROL, state.hls_l_sl, set_value=(state.f1_v = b) WIDGET_CONTROL, state.hls_s_sl, set_value=(state.f2_v = c) end endcase if ((state.color_index ge 0) or (state.graphicsLevel eq 2)) then $ CW_RGB_SET_DRAW, state WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY end ; ----------------------------------------------------------------------------- ; function CW_RGB_GET_VAL, id COMPILE_OPT hidden ; Recover the state of this compound widget stash = WIDGET_INFO(id, /CHILD) WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY ret = [ state.r_v, state.g_v, state.b_v ] WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY return, ret end ; ----------------------------------------------------------------------------- ; function CW_RGBSLIDER, parent, vertical=vertical, frame=frame, $ drag=drag, uvalue=uvalue, rgb=map_rgb, cmy=map_cmy, $ hsv=map_hsv, hls=map_hls, LENGTH = length, $ COLOR_INDEX=color_index, GRAPHICS_LEVEL=graphicsLevel, $ VALUE=initialColor, UNAME=uname, TAB_MODE=tab_mode IF NOT (KEYWORD_SET(drag)) THEN drag=0 IF NOT (KEYWORD_SET(frame)) THEN frame=0 IF NOT (KEYWORD_SET(vertical)) THEN vertical=0 IF NOT (KEYWORD_SET(uvalue)) THEN uvalue=0 IF NOT (KEYWORD_SET(uname)) THEN uname='CW_RGBSLIDER_UNAME' IF NOT (KEYWORD_SET(length)) THEN length=256 IF N_ELEMENTS(Color_index) le 0 then color_index=-1 IF N_ELEMENTS(graphicsLevel) le 0 then graphicsLevel=1 IF N_ELEMENTS(initialColor) gt 0 then begin if N_ELEMENTS(initialColor) ne 3 then $ MESSAGE,'VALUE must have three elements: [red, green, blue].' endif else $ initialColor=[0B,0B,0B] map_rgb = KEYWORD_SET(map_rgb) map_cmy = KEYWORD_SET(map_cmy) map_hsv = KEYWORD_SET(map_hsv) map_hls = KEYWORD_SET(map_hls) ; Make sure only one color system is selected. junk = map_rgb + map_cmy + map_hsv + map_hls if (junk eq 0) then map_rgb = 1 ; RGB is the default if (junk gt 1) then $ message, 'The RGB, CMY, HSV, and HLS keywords are mutually exclusive.' ; The variables in the state struct have suffixes that identify their class ; _b - The various slider bases ; _s - The pulldown menu selection buttons ; _sl - The sliders ; _v - Current values in various systems state = { CW_RGBSLIDER_STATE, $ ; Current RGB for all C.S. r_v:initialColor[0], g_v:initialColor[1], b_v:initialColor[2], $ h_v:0.0, f1_v:0.0, f2_v:0.0, $ ; Curr. for HLS and HSV r_sl:0L, g_sl:0L, b_sl:0L, $ ; RGB sliders c_sl:0L, m_sl:0L, y_sl:0L, $ ; CMY sliders hsv_h_sl:0L, hsv_s_sl:0L, hsv_v_sl:0L, $ ; HSV sliders hls_h_sl:0L, hls_l_sl:0L, hls_s_sl:0L, $ ; HLS sliders select_s:0L, select_b:lonarr(4), curr_b_idx:0L, $ ;Slider bases first_child:0L, $ ; Where the state is kept color_index: long(color_index), $ color_window: -1L, $ graphicsLevel: graphicsLevel, $ color_draw: 0L } on_error,2 ;Return to caller if an error occurs base = WIDGET_BASE(parent, /COLUMN, FRAME=frame, EVENT_FUNC='CW_RGB_EVENT',$ FUNC_GET_VALUE='CW_RGB_GET_VAL', PRO_SET_VALUE='CW_RGB_SET_VAL', $ NOTIFY_REALIZE='CW_RGB_INIT', $ UVALUE=uvalue, UNAME=uname) if ( N_ELEMENTS(tab_mode) ne 0 ) then $ WIDGET_CONTROL, base, TAB_MODE=tab_mode base1 = WIDGET_BASE(base, /ROW) exposeEvents = (graphicsLevel eq 2) retain = (graphicsLevel eq 2) ? 0 : 2 if ((color_index ge 0) or (graphicsLevel eq 2)) then $ state.color_draw = WIDGET_DRAW(base1, xsize=24, ysize=24, $ RETAIN=retain, GRAPHICS_LEVEL=graphicsLevel, $ EXPOSE_EVENTS=exposeEvents, $ UNAME=uname+'_COLOR_DRAW') state.select_s = WIDGET_DROPLIST(base1, VALUE=['RGB (Red/Green/Blue)', $ 'CMY (Cyan/Magenta/Yellow)', 'HSV (Hue/Saturation/Value)', $ 'HLS (Hue/Lightness/Saturation)'], TITLE='Color System:', $ UNAME=uname+'_SELECT') selbase = WIDGET_BASE(base) fslide_fmt = '(F4.2)' if (vertical eq 0) then begin tmp = WIDGET_BASE(selbase, /COLUMN, /MAP) state.r_sl = WIDGET_SLIDER(tmp, max=255, title='Red', $ drag=drag, xsize=length,UNAME=uname+'_R') state.g_sl = WIDGET_SLIDER(tmp, max=255, title='Green', $ drag=drag, xsize=length,UNAME=uname+'_G') state.b_sl = WIDGET_SLIDER(tmp, max=255, title='Blue', $ drag=drag, xsize=length,UNAME=uname+'_B') state.select_b[0] = tmp tmp = WIDGET_BASE(selbase, /COLUMN, MAP=0) state.c_sl = WIDGET_SLIDER(tmp, max=255, title='Cyan', $ drag=drag, xsize=length,UNAME=uname+'_C') state.m_sl = WIDGET_SLIDER(tmp, max=255, title='Magenta', $ drag=drag, xsize=length,UNAME=uname+'_M') state.y_sl = WIDGET_SLIDER(tmp, max=255, title='Yellow', $ drag=drag, xsize=length,UNAME=uname+'_Y') state.select_b[1] = tmp tmp = WIDGET_BASE(selbase, /COLUMN, MAP=0) state.hsv_h_sl = WIDGET_SLIDER(tmp, max=360, title='Hue', $ drag=drag, xsize=length,UNAME=uname+'_HSV_H') state.hsv_s_sl = CW_FSLIDER(tmp, max=1.0, title='Saturation', $ drag=drag, xsize=length, format=fslide_fmt, $ UNAME=uname+'_HSV_S') state.hsv_v_sl = CW_FSLIDER(tmp, max=1.0, title='Value', $ drag=drag, xsize=length, format=fslide_fmt, $ UNAME=uname+'_HSV_V') state.select_b[2] = tmp tmp = WIDGET_BASE(selbase, /COLUMN, MAP=0) state.hls_h_sl = WIDGET_SLIDER(tmp, max=360, title='Hue', $ drag=drag, xsize=length,UNAME=uname+'_HLS_H') state.hls_l_sl = CW_FSLIDER(tmp, max=1.0, title='Lightness', $ drag=drag, xsize=length, format=fslide_fmt, $ UNAME=uname+'_HLS_L') state.hls_s_sl = CW_FSLIDER(tmp, max=1.0, title='Saturation', $ drag=drag, xsize=length, format=fslide_fmt, $ UNAME=uname+'_HLS_S') state.select_b[3] = tmp endif else begin ; Vertical sliders tmp = WIDGET_BASE(selbase, /ROW, /MAP) state.r_sl = WIDGET_SLIDER(tmp, max=255, title='R',drag=drag, $ ysize=length, /vertical,UNAME=uname+'_R') state.g_sl = WIDGET_SLIDER(tmp, max=255, title='G', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_G') state.b_sl = WIDGET_SLIDER(tmp, max=255, title='B', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_B') state.select_b[0] = tmp tmp = WIDGET_BASE(selbase, /ROW, MAP=0) state.c_sl = WIDGET_SLIDER(tmp, max=255, title='C', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_C') state.m_sl = WIDGET_SLIDER(tmp, max=255, title='M', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_M') state.y_sl = WIDGET_SLIDER(tmp, max=255, title='Y', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_Y') state.select_b[1] = tmp tmp = WIDGET_BASE(selbase, /ROW, MAP=0) state.hsv_h_sl = WIDGET_SLIDER(tmp, max=360, title='H', $ drag=drag, ysize=length, /vertical,UNAME=uname+'_HSV_H') state.hsv_s_sl = CW_FSLIDER(tmp, max=1.0, title='S', $ drag=drag, ysize=length, /vertical, $ format=fslide_fmt,UNAME=uname+'_HSV_S') state.hsv_v_sl = CW_FSLIDER(tmp, max=1.0, title='V', $ drag=drag, ysize=length, /vertical, $ format=fslide_fmt,UNAME=uname+'_HSV_V') state.select_b[2] = tmp tmp = WIDGET_BASE(selbase, /ROW, MAP=0) state.hls_h_sl = WIDGET_SLIDER(tmp, max=360, title='H', $ drag=drag, ysize=length, /vertical, $ UNAME=uname+'_HLS_H') state.hls_l_sl = CW_FSLIDER(tmp, max=1.0, title='L',drag=drag,$ ysize=length, /vertical, format=fslide_fmt, $ UNAME=uname+'_HLS_L') state.hls_s_sl = CW_FSLIDER(tmp, max=1.0, title='S',drag=drag,$ ysize=length, /vertical, format=fslide_fmt, $ UNAME=uname+'_HLS_S') state.select_b[3] = tmp endelse ; If the initial color system is not RGB, switch it now before it's realized if (map_rgb) then CW_RGB_CHNG_CS, state, 0 if (map_cmy) then begin CW_RGB_CHNG_CS, state, 1 widget_control, state.select_s, SET_DROPLIST_SELECT=1 endif if (map_hsv) then begin CW_RGB_CHNG_CS, state, 2 widget_control, state.select_s, SET_DROPLIST_SELECT=2 endif if (map_hls) then begin CW_RGB_CHNG_CS, state, 3 widget_control, state.select_s, SET_DROPLIST_SELECT=3 endif ; Stash the state WIDGET_CONTROL, WIDGET_INFO(base, /CHILD), SET_UVALUE=state, /NO_COPY return, base end ; -----------------------------------------------------------------------------