; $Id: cw_led.pro,v 1.4 2005/06/09 18:42:47 rdimeo Exp $ ; + ; NAME: ; CW_LED ; ; PURPOSE: ; Compound widget that provides an LED-type light display ; as a status indicator. ; ; CALLING SEQUENCE: ; id = CW_LED(PARENT, LABEL = LABEL, $ ; UNAME = uname, $ ; VALUE = value, $ ; UVALUE = uvalue, $ ; BG_COLOR = bg_color, $ ; RED = RED, $ ; GREEN = GREEN, $ ; BLUE = BLUE, $ ; YELLOW = YELLOW, $ ; ROW = row, $ ; XOFFSET = xoffset, $ ; YOFFSET = yoffset, $ ; OBJ_REF = obj_ref ) ; ; Note that the value of the widget, i.e. the current light setting, ; can be obtained using WIDGET_CONTROL: ; WIDGET_CONTROL,id,get_value = led_setting ; The resulting variable named led_setting here would be a byte ; value of 1 or 0 depending on the setting. ; ; The value of the widget can be modified using WIDGET_CONTROL ; as follows: ; WIDGET_CONTROL,id,set_value = new_led_setting ; where new_led_setting is a byte value like led_setting. ; ; PARAMETERS: (Required) ; PARENT: widget ID of the parent widget ; ; KEYWORDS: (Optional) ; BG_COLOR: RGB triplet specifying the color of the background of ; the LED. The default is the color of the widget background. ; XOFFSET: The horizontal offset of the widget in units in pixels ; relative to its parent. ; YOFFSET: The vertical offset of the widget in units in pixels ; relative to its parent. ; UVALUE: A user value to assign to the LED CW. This value ; can be of any type. ; LABEL: Label (string) for the LED. ; UNAME: Set this keyword to a string that can be used to identify ; the widget in your code. You can associate a name with ; each widget in a specific hierarchy, and then use that ; name to query the widget hierarchy and get the correct ; widget ID ; VALUE: Byte value that indicates if a particular LED is "on" ; value = 1B or "off", value = 0B ; RED: Set this keyword to create a red LED. ; BLUE: Set this keyword to create a blue LED. ; GREEN: Set this keyword to create a green LED. ; YELLOW: Set this keyword to create a yellow LED. ; PURPLE: Set this keyword to create a purple LED. ; ROW: If set then LEDs will be arranged in a single row ; OBJ_REF: Reference to the compound widget object to provide more ; flexibility to the programmer than a conventional ; compound widget. ; ; COMMON BLOCKS: ; None ; ; REQUIRED PROGRAMS: ; None ; ; REQUIREMENTS: ; IDL 6.0 and higher (due to the use of ARRAY_INDICES) ; ; EXAMPLE: ; An example implementation is contained at the end of this source code ; listing and is titled CW_LED_EXAMPLE. It illustrates how you can incorporate ; this compound widget into an application and toggle the LEDs ; on and off. ; ; AUTHOR: ; Robert M. Dimeo, Ph.D. ; NIST Center for Neutron Research ; 100 Bureau Drive ; Gaithersburg, MD 20899 ; Phone: (301) 975-8135 ; E-mail: robert.dimeo@nist.gov ; http://www.ncnr.nist.gov/staff/dimeo ; ; MODIFICATION HISTORY: ; Written by RMD 05/24/05 ; Improved appearance of the LED by adding a nicer border that ; gives more of a 3D look -- RMD 06/07/05 ; ; LICENSE: ; The software in this file is written by an employee of ; National Institute of Standards and Technology ; as part of the DAVE software project. ; ; The DAVE software package is not subject to copyright ; protection and is in the public domain. It should be ; considered as an experimental neutron scattering data ; reduction, visualization, and analysis system. As such, ; the authors assume no responsibility whatsoever for its ; use, and make no guarantees, expressed or implied, ; about its quality, reliability, or any other ; characteristic. The use of certain trade names or commercial ; products does not imply any endorsement of a particular ; product, nor does it imply that the named product is ; necessarily the best product for the stated purpose. ; We would appreciate acknowledgment if the DAVE software ; is used or if the code in this file is included in another ; product. ; - ; ************************************************ ; pro cw_led::cleanup ptr_free,self.on_ptr,self.off_ptr,self.storage wdelete,self.winpix end ; ************************************************ ; function cw_led::on device,get_decomposed = dc device,decomposed = 1 wset,self.winpix tv,*self.on_ptr,/true wset,self.winvis device,copy = [0,0,self.led_size,self.led_size,0,0,self.winpix] device,decomposed = dc return,1B end ; ************************************************ ; function cw_led::off device,get_decomposed = dc device,decomposed = 1 wset,self.winpix tv,*self.off_ptr,/true wset,self.winvis device,copy = [0,0,self.led_size,self.led_size,0,0,self.winpix] device,decomposed = dc return,1B end ; ************************************************ ; function cw_led::toggle_state ; Toggle the state... if self.state eq 0B then self.state = 1B else self.state = 0B ; ...and then turn the light off or on, depending on the state if self.state then ret = self->on() else ret = self->off() return,1B end ; ************************************************ ; pro cw_led::set_property, value = value, $ label = label, $ winpix = winpix, $ winvis = winvis if n_elements(value) ne 0 then begin self.state = value if self.state then ret = self->on() else ret = self->off() endif if n_elements(label) ne 0 then begin self.label_txt = label widget_control,self.label_id,set_value = self.label_txt endif if n_elements(winpix) ne 0 then self.winpix = winpix if n_elements(winvis) ne 0 then self.winvis = winvis end ; ************************************************ ; pro cw_led::get_property, tlb = tlb, $ winpix = winpix, $ winvis = winvis, $ win_id = win_id, $ label = label, $ value = value, $ led_size = led_size win_id = self.win_id led_size = led_size value = self.state label = self.label_txt tlb = self.tlb winpix = self.winpix winvis = self.winvis end ; ************************************************ ; function cw_led_get_value,id stash = widget_info(id,/child) widget_control,stash,get_uvalue = the_object the_object->get_property,value = value return,value end ; ************************************************ ; pro cw_led_set_value,id,val stash = widget_info(id,/child) widget_control,stash,get_uvalue = the_object the_object->set_property,value = val ; ...and then turn the light off or on, depending on the state if byte(val) then ret = the_object->on() else ret = the_object->off() end ; ************************************************ ; function cw_led_event,event return,event end ; ************************************************ ; pro cw_led_notify_realize,id stash = widget_info(id,/parent) ;stash = widget_info(widget_info(id,/parent),/child) widget_control,stash,get_uvalue = the_object the_object->get_property,led_size = led_size, $ win_id = win_id,value = state widget_control,win_id,get_value = winvis window,/free,/pixmap,xsize = led_size,ysize = led_size winpix = !d.window the_object->set_property,winpix = winpix,winvis = winvis ; Set the initial state of the button if state then ret = the_object->on() else ret = the_object->off() ; Set the cursor to the standard arrow (on Windows) so that ; the user doesn't know that he/she's using a draw widget here ; (where it would turn into a cross-hairs). device,/cursor_original end ; ************************************************ ; pro cw_led_kill_notify,id widget_control,id,get_uvalue = the_object obj_destroy,the_object end ; ************************************************ ; function cw_led::build_widgets tlb = widget_base(self.parent,uvalue = *self.storage, $ uname = self.uname,event_func = 'CW_LED_EVENT', $ pro_set_value = 'cw_led_set_value', $ xoffset = self.xoffset,yoffset = self.yoffset, $ func_get_value = 'cw_led_get_value',/base_align_center ) if ~self.row then begin base = widget_base(tlb,/col,uvalue = self, $ kill_notify = 'CW_LED_KILL_NOTIFY',xpad = 0,ypad = 0 ) endif else begin base = widget_base(tlb,/row,uvalue = self, $ kill_notify = 'CW_LED_KILL_NOTIFY',xpad = 0,ypad = 0 ) endelse self.tlb = tlb if self.label_txt ne '' then begin self.label_id = widget_label(base,value = self.label_txt, $ /dynamic_resize ) endif else begin self.label_id = 0L endelse self.win_id = widget_draw(base,xsize = self.led_size, $ ysize = self.led_size, $ notify_realize = 'CW_LED_NOTIFY_REALIZE', $ /align_center ) return,1B end ; ************************************************ ; function cw_led::init_leds base = widget_base() sys_colors = widget_info(base,/system_colors) color = self.bg_color ;color = sys_colors.face_3d light_3d = sys_colors.light_3d shadow_3d = sys_colors.shadow_3d light_edge_3d = sys_colors.light_edge_3d dark_shadow_3d = sys_colors.dark_shadow_3d widget_control,base,/destroy ; Use true color device,decomposed = 1 xsize = (ysize = self.led_size) b1 = bytarr(3,xsize,ysize) for i = 0,2 do b1[i,*,*] = color[i] xc = (xsize-1)/2. & yc = (ysize-1)/2. r = 0.7*xc xm = rebin(indgen(xsize),xsize,ysize,/sample) ym = rebin(transpose(indgen(ysize)),xsize,ysize,/sample) diff = (xm-xc)^2+(ym-yc)^2 - r^2 filled = where(diff le 0.0,count,complement = unfilled) xspot = 1.0*r & yspot = 1.8*r rspot = 0.2*r white = ((xm-xspot)^2+(ym-yspot)^2)-rspot^2 where_white = where(white le 0.0,count) white_ind = array_indices(bytarr(xsize,ysize),where_white) angle = !radeg * atan(ym-yc,xm-xc) border = (((xm-xc)^2+(ym-yc)^2) le (1.0*xc)^2) and $ (((xm-xc)^2+(ym-yc)^2) ge r^2) r1 = 0.85*xc border1_cond = (((xm-xc)^2+(ym-yc)^2) le xc^2) and $ (((xm-xc)^2+(ym-yc)^2) ge r1^2) border1 = where(border1_cond) border2_cond = (((xm-xc)^2+(ym-yc)^2) le r1^2) and $ (((xm-xc)^2+(ym-yc)^2) ge r^2) border2 = where(border2_cond) border1_ind = array_indices(bytarr(xsize,ysize),border1) border2_ind = array_indices(bytarr(xsize,ysize),border2) sb1 = size(border1_ind) & sb2 = size(border2_ind) ; Now create the color change around the border xx = xm-xc & yy = ym-yc & h = sqrt(xx^2+yy^2) theta = asin(yy/h) nth = n_elements(theta) this_angle = -45.0 border1_color = bytscl(sin(1.*theta)) border2_color = 255B-border1_color border1_image = border1_color+bytarr(xsize,ysize) border1_image = rot(border1_image,this_angle,/cubic) border2_image = border2_color+bytarr(xsize,ysize) border2_image = rot(border2_image,this_angle,/cubic) ;angle_cond = (angle le 45.0) and (angle ge -135.0) angle_cond = (angle le 10.0) and (angle ge -120.0) border_hi = angle_cond and border border_hi_indices = where(border_hi) border_lo = ~angle_cond and border border_lo_indices = where(border_lo) border_lo_ind = array_indices(bytarr(xsize,ysize),border_lo_indices) border_hi_ind = array_indices(bytarr(xsize,ysize),border_hi_indices) sb_hi = size(border_hi_ind) sb_lo = size(border_lo_ind) ; Create a blurred "half-moon" from which we'll extract the border ; and put "behind" the LED. This will provide a visual indication ; of depth. ; ; R = radius of the LED ; XC = "half-size" of the entire LED image array ; r1 = 0.9*xc rcspot = 0.15*r close_white = (xm-xspot)^2+(ym-yspot)^2-rcspot^2 where_close_white = where(close_white le 0.0,count) close_white_indices = array_indices(bytarr(xsize,ysize),where_close_white) b2 = b1 b3 = b1 findices = array_indices(bytarr(xsize,ysize),filled) sf = size(findices) sw = size(white_ind) case self.color of 'red': $ begin index1 = 0 & onval1 = 240B & offval1 = 70B index2 = 1 & onval2 = 0B & offval2 = 0B index3 = 2 & onval3 = 0B & offval3 = 0B end 'green': $ begin index1 = 1 & onval1 = 240B & offval1 = 70B index2 = 0 & onval2 = 0B & offval2 = 0B index3 = 2 & onval3 = 0B & offval3 = 0B end 'blue': $ begin index1 = 2 & onval1 = 255B & offval1 = 130B index2 = 0 & onval2 = 0B & offval2 = 0B index3 = 1 & onval3 = 0B & offval3 = 0B end 'yellow': $ begin index1 = 0 & onval1 = 248B & offval1 = 184B index2 = 1 & onval2 = 221B & offval2 = 134B index3 = 2 & onval3 = 0B & offval3 = 11B end 'purple': $ begin index1 = 0 & onval1 = 160B & offval1 = 80B index2 = 1 & onval2 = 32B & offval2 = 0B index3 = 2 & onval3 = 240B & offval3 = 80B end endcase for j = 0,sf[2]-1 do begin b2[index1,findices[0,j],findices[1,j]] = onval1 b2[index2,findices[0,j],findices[1,j]] = onval2 b2[index3,findices[0,j],findices[1,j]] = onval3 b3[index1,findices[0,j],findices[1,j]] = offval1 b3[index2,findices[0,j],findices[1,j]] = offval2 b3[index3,findices[0,j],findices[1,j]] = offval3 endfor scw = size(close_white_indices) ; Add the white spot for j = 0,sw[2]-1 do $ for i = 0,2 do $ b2[i,white_ind[0,j],white_ind[1,j]] = 255B for j = 0,scw[2]-1 do $ for i = 0,2 do $ b3[i,close_white_indices[0,j],close_white_indices[1,j]] = 255B ; Now blur the LED images width = 5 for i = 0,2 do begin b2[i,*,*] = smooth(b2[i,*,*],/edge_truncate,width) b3[i,*,*] = smooth(b3[i,*,*],/edge_truncate,width) endfor ; Add the high border to the lights for j = 0,sb1[2]-1 do begin for i = 0,2 do begin b2[i,border1_ind[0,j],border1_ind[1,j]] = border1_image[border1_ind[0,j],border1_ind[1,j]] b3[i,border1_ind[0,j],border1_ind[1,j]] = border1_image[border1_ind[0,j],border1_ind[1,j]] endfor endfor for j = 0,sb2[2]-1 do begin for i = 0,2 do begin b2[i,border2_ind[0,j],border2_ind[1,j]] = border2_image[border2_ind[0,j],border2_ind[1,j]] b3[i,border2_ind[0,j],border2_ind[1,j]] = border2_image[border2_ind[0,j],border2_ind[1,j]] endfor endfor ; Add the widget colored border unfilled = (((xm-xc)^2+(ym-yc)^2) ge xc^2) where_unfilled = where(unfilled) unfill_ind = array_indices(bytarr(xsize,ysize),where_unfilled) suf = size(unfill_ind) ufindices = array_indices(bytarr(xsize,ysize),unfill_ind) su = size(ufindices) for j = 0,su[2]-1 do begin for i = 0,2 do begin b2[i,ufindices[0,j],ufindices[1,j]] = color[i] b3[i,ufindices[0,j],ufindices[1,j]] = color[i] endfor endfor *self.on_ptr = b2 *self.off_ptr = b3 return,1B end ; ************************************************ ; function cw_led::init, parent, $ red = red, $ green = green, $ blue = blue, $ yellow = yellow, $ purple = purple, $ row = row, $ uname = uname, $ value = value, $ uvalue = uvalue, $ led_size = led_size, $ bg_color = bg_color, $ xoffset = xoffset, $ yoffset = yoffset, $ label = label if n_params() eq 0 then return,0B if n_elements(bg_color) eq 0 then begin base = widget_base() bg_color = (widget_info(base,/system_colors)).face_3d widget_control,base,/destroy endif self.bg_color = bg_color if n_elements(xoffset) eq 0 then xoffset = 0L if n_elements(yoffset) eq 0 then yoffset = 0L self.xoffset = xoffset & self.yoffset = yoffset if n_elements(led_size) eq 0 then led_size = 25 self.led_size = led_size if n_elements(value) eq 0 then value = 1B self.state = value self.parent = parent if n_elements(label) eq 0 then label = '' self.label_txt = label self.row = keyword_set(row) ; default is for a column layout if keyword_set(red) then color = 'red' if keyword_set(green) then color = 'green' if keyword_set(blue) then color = 'blue' if keyword_set(yellow) then color = 'yellow' if keyword_set(purple) then color = 'purple' if ~keyword_set(red) and $ ~keyword_set(green) and $ ~keyword_set(blue) and $ ~keyword_set(purple) and $ ~keyword_set(yellow) $ then color = 'green' self.color = color if n_elements(uname) eq 0 then uname = '' self.uname = uname if n_elements(uvalue) eq 0 then uvalue = '' self.storage = ptr_new(uvalue) self.on_ptr = ptr_new(/allocate_heap) self.off_ptr = ptr_new(/allocate_heap) ret = self->init_leds() return,1B end ; ************************************************ ; pro cw_led__define void = { cw_led, $ parent:0L, $ bg_color:bytarr(3), $ uname:'', $ storage:ptr_new(), $ led_size:0L, $ xoffset:0L, $ yoffset:0L, $ label_id:0L, $ win_id:0L, $ winpix:0L, $ winvis:0L, $ tlb:0L, $ color:'', $ label_txt:'', $ row:0B, $ state:0B, $ on_ptr:ptr_new(), $ off_ptr:ptr_new() } end ; ************************************************ ; function cw_led, parent, $ _Extra = extra, $ obj_ref = obj_ref obj_ref = obj_new('cw_led',parent,_Extra = extra) ret = obj_ref->build_widgets() obj_ref->get_property,tlb = tlb return,tlb end ; ************************************************ ; ; ************************************************ ; pro cw_led_example_event,event case widget_info(event.id,/uname) of 'QUIT': widget_control,event.top,/destroy 'TOGGLE': $ begin for i = 0,4 do begin uname = 'MY_LED'+strtrim(string(i+1),2) led_id = widget_info(event.top,find_by_uname = uname) widget_control,led_id,get_value = old_value if old_value eq 1 then new_value = 0 else new_value = 1 widget_control,led_id,set_value = new_value if new_value eq 1 then button_label = 'Lights off' else $ button_label = 'Lights on' widget_control,event.id,set_value = button_label endfor end else: endcase end ; ************************************************ ; pro cw_led_example title = 'Example usage of CW_LED' tlb = widget_base(/col,/tlb_frame_attr,/base_align_center,title = title) row = widget_base(tlb,/row) ls = 30 void = cw_led(row,value = 0,label = 'Label 1',/blue,uname = 'MY_LED1', $ LED_SIZE = ls) void = cw_led(row,value = 0,label = 'Label 2',/red,uname = 'MY_LED2', $ LED_SIZE = ls) void = cw_led(row,value = 0,label = 'Label 3',/green,uname = 'MY_LED3', $ LED_SIZE = ls) void = cw_led(row,value = 0,label = 'Label 4',/yellow,uname = 'MY_LED4', $ LED_SIZE = ls) void = cw_led(row,value = 0,label = 'Label 5',/purple,uname = 'MY_LED5', $ LED_SIZE = ls) void = widget_button(tlb,value = 'Lights on',uname = "TOGGLE",/dynamic_resize) void = widget_button(tlb,value = 'Quit',uname = "QUIT") widget_control,tlb,/realize xmanager,'cw_led_example',tlb,/no_block end