; $Id: cw_text_display.pro,v 1.6 2005/06/07 17:45:59 rdimeo Exp $ ; + ; NAME: ; CW_TEXT_DISPLAY ; ; PURPOSE: ; Compound widget that can display text using colored fonts. ; This is not a replacement for WIDGET_TEXT because it is ; not editable. It is just for display purposes only. ; ; CALLING SEQUENCE: ; ID = CW_DISPLAY_TEXT( PARENT, $ ; OBJ_REF = obj_ref, $ ; UNAME = uname, $ ; UVALUE = uvalue, $ ; XSIZE = xsize, $ ; TEXT = text, $ ; COLOR = color, $ ; YSIZE = ysize ) ; ; RETURN VALUE: ; Widget ID of the compound widget. ; ; PARAMETERS: (required) ; ; PARENT: widget ID of the parent of this compound widget ; ; KEYWORDS: (optional) ; ; 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. ; ; UVALUE: A user value to assign to the CW. This value can be ; of any type. ; XSIZE: Horizontal size of the draw widget (in pixels) ; YSIZE: Vertical size of the draw widget (in pixels) ; TEXT: String array containing the initial setting for the ; text display. ; COLOR: String array of the same size as TEXT that contains ; the identity of the colors of each of the elements in TEXT. ; Valid colors are those accepted by FSC_COLOR (David Fanning). ; OBJ_REF: Reference to the object which allows more control over ; the compound widget than WIDGET_CONTROL. ; ; SIDE EFFECTS: ; -This widget generates no events. ; ; COMMON BLOCKS: ; None ; ; REQUIRED PROGRAMS: ; FSC_COLOR.PRO (From David Fanning's web site) ; ; REQUIRED RESOURCES: ; NONE ; ; REQUIREMENTS: ; 24-Bit color required ; ; EXAMPLE USAGE: (appended to end of this file) ; Compile this file then ; IDL> TEXT_DISPLAY_TEST ; ; AUTHOR: ; Robert M. Dimeo, Ph.D. ; NIST Center for Neutron Research ; 100 Bureau Drive ; Mail Stop 8562 ; Gaithersburg, MD 20899 ; Phone: (301) 975-8135 ; E-mail: robert.dimeo@nist.gov ; http://www.ncnr.nist.gov/staff/dimeo ; ; MODIFICATION HISTORY: ; Written 6/03/05 ; Corrected some problems with the ordering of text in text ; arrays and also the colors -- RMD 06/06/05 ; Rewrote the ENLARGE method when I discovered that I did *not* ; have to destroy and re-create the entire draw widget all over ; again. -- RMD 06/06/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 rmd_text_display::cleanup ptr_free,self.text_ptr,self.storage,self.color_ptr end ; ************************************************************ ; pro rmd_text_display::get_property, tlb = tlb, $ uvalue = uvalue, $ value = value, $ xsize = xsize, $ ysize = ysize, $ winbase = winbase, $ color = color winbase = self.winbase tlb = self.tlb if n_elements(*self.text_ptr) eq 0 then value = '' else $ value = *self.text_ptr if n_elements(*self.color_ptr) eq 0 then color = '' else $ color = *self.color_ptr xsize = self.xsize ysize = self.ysize uvalue = *self.storage end ; ************************************************************ ; pro rmd_text_display::set_property, win = win, $ winvis = winvis, $ value = value if n_elements(win) ne 0 then self.win = win if n_elements(winvis) ne 0 then self.winvis = winvis if n_elements(value) ne 0 then *self.text_ptr = value end ; ************************************************************ ; function rmd_text_display::eventhandler,event ; Handle the *internal* events if event.id eq self.win then begin ; Handle viewport change events (i.e. scroll bar changes) if event.type eq 3 then begin n = n_elements(*self.text_ptr) if n eq 0 then return,0B wset,self.winvis tv,255B+bytarr(3,self.x_scroll_size,self.y_scroll_size),/true dy = float(!d.y_ch_size) ypos = 2.0*dy+1.5*dy*findgen(n) orig_font = !p.font !p.font = 0 for i = 0,n-1 do begin xyouts,5-event.x,ypos[i]-event.y,(*self.text_ptr)[i], $ /device,color = fsc_color((*self.color_ptr)[i]) endfor !p.font = orig_font return,0B endif endif return,0B end ; ************************************************************ ; function rmd_text_display::append_text,text ; Are there more than one element in text? max_len = 128 n = n_elements(text) if n eq 0 then begin ; Is this line too long? length = strlen(text) if length gt max_len then begin ; Split up the text value into a new text array ; whose elements do not exceed MAX_LEN nchar = 1 + length/max_len text_out = strarr(nchar) for i = 0,nchar-1 do begin init = i*max_len text_out[i] = strmid(text,init,max_len) endfor endif else begin text_out = text endelse endif else begin for j = 0,n-1 do begin ; Is this line too long? length = strlen(text[j]) if length gt max_len then begin ; Split up the text value into a new text array ; whose elements do not exceed MAX_LEN nchar = 1 + length/max_len output = strarr(nchar) for i = 0,nchar-1 do begin init = i*max_len output[i] = strmid(text[j],init,max_len) endfor endif else begin output = text[j] endelse if n_elements(text_out) eq 0 then begin text_out = output endif else begin text_out = [output,text_out] endelse endfor endelse text = reverse(text_out) if n_elements(*self.text_ptr) eq 0 then begin *self.text_ptr = text endif else begin *self.text_ptr = [text,*self.text_ptr] endelse return,1B end ; ************************************************************ ; function rmd_text_display::set_color,color if n_elements(color) gt 1 then color = reverse(color) if n_elements(*self.color_ptr) eq 0 then $ *self.color_ptr = color $ else $ *self.color_ptr = [color,*self.color_ptr] return,1B end ; ************************************************************ ; function rmd_text_display::enlarge n = n_elements(*self.text_ptr) if (n+1) lt float(self.ysize)/(1.5*!d.y_ch_size) then y_enlarge = 0B else y_enlarge = 1B if y_enlarge then self.ysize = self.ysize + 50.*!d.y_ch_size max_string = max(strlen(*self.text_ptr),imax) strmax = (*self.text_ptr)[imax] wset,self.winvis xyouts,0.,0.,strmax,width = this_width,charsize = -1 win_geom = widget_info(self.win,/geometry) this_width = this_width*(float(!d.x_size)/win_geom.draw_xsize) xlen = win_geom.draw_xsize*this_width x_enlarge = (xlen+5*!d.x_ch_size) gt self.xsize if x_enlarge then self.xsize = xlen+10*!d.x_ch_size if (x_enlarge or y_enlarge) then begin widget_control,self.win, draw_xsize = self.xsize, $ draw_ysize = self.ysize widget_control,self.win,set_draw_view = [0,0] wset,self.winvis tv,255B+bytarr(3,self.xsize,self.ysize),/true endif return,1B end ; ************************************************************ ; function rmd_text_display_get,id stash = widget_info(id,/child) widget_control,stash,get_uvalue = the_object the_object->get_property,value = value return,reverse(value) end ; ************************************************************ ; function rmd_text_display::clear_text ptr_free,*self.text_ptr self.text_ptr = ptr_new(/allocate_heap) wset,self.winvis tv,255B+bytarr(3,self.xsize,self.ysize),/true return,1B end ; ************************************************************ ; function rmd_text_display::update_text,value ; Append the latest value of the text to the current text ; array. ret = self->append_text(value) ; Determine if we need to enlarge the display window ret = self->enlarge() ; Display the text in the window n = n_elements(*self.text_ptr) if n eq 0 then return,0B wset,self.winvis tv,255B+bytarr(3,self.xsize,self.ysize),/true if n gt n_elements(*self.color_ptr) then begin nremaining = n - n_elements(*self.color_ptr) ret = self->set_color(replicate('black',nremaining)) endif dy = float(!d.y_ch_size) ypos = 2*dy+1.5*dy*indgen(n) orig_font = !p.font !p.font = 0 for i = 0,n-1 do begin xyouts,5.0,ypos[i],(*self.text_ptr)[i],/device, $ color = fsc_color((*self.color_ptr)[i]) endfor !p.font = orig_font return,1B end ; ************************************************************ ; pro rmd_text_display_set,id,value stash = widget_info(id,/child) widget_control,stash,get_uvalue = the_object n = n_elements(value) for i = 0,n-1 do begin result = strsplit(value[i],string(10B),/extract) if n_elements(output) eq 0 then begin output = result endif else begin output = [output,result] endelse endfor if n_elements(output) gt 1 then output = reverse(output) ret = the_object->update_text(output) end ; ************************************************************ ; pro rmd_text_display_kill,id widget_control,id,get_uvalue = the_object obj_destroy,the_object end ; ************************************************************ ; function rmd_text_display_event,event stash = widget_info(event.id,/parent) widget_control,stash,get_uvalue = the_object the_event = the_object->eventhandler(event) return,the_event end ; ************************************************************ ; pro rmd_text_display_notify_realize,id device,decomposed = 1 stash = widget_info(id,/parent) widget_control,stash,get_uvalue = the_object widget_control,id,get_value = winvis the_object->set_property,winvis = winvis the_object->get_property,xsize = xsize,ysize = ysize, $ winbase = winbase wset,winvis tv,255B+bytarr(3,xsize,ysize),/true widget_control,id,set_draw_view = [0,0] device,/cursor_original ;widget_control,winbase,map = 1B end ; ************************************************************ ; function rmd_text_display::build_widget tlb = widget_base(self.parent,uvalue = *self.storage, $ uname = self.uname, $ pro_set_value = 'rmd_text_display_set', $ func_get_value = 'rmd_text_display_get' ) self.tlb = tlb self.winbase = widget_base(self.tlb,uvalue = self, $ kill_notify = 'rmd_text_display_kill' ) self.win = widget_draw(self.winbase,xsize = self.xsize, $ /app_scroll, $ /keyboard_events, $ notify_realize = 'rmd_text_display_notify_realize', $ event_func = 'rmd_text_display_event', $ retain = 2, $ ysize = self.ysize, $ x_scroll_size = self.x_scroll_size, $ y_scroll_size = self.y_scroll_size ) return,1B end ; ************************************************************ ; function rmd_text_display::init, parent, $ xsize = xsize, $ ysize = ysize, $ uvalue = uvalue, $ uname = uname, $ text = text, $ color = color if n_params() eq 0 then return,0B self.parent = parent self.text_ptr = ptr_new(/allocate_heap) if n_elements(text) ne 0 then *self.text_ptr = text self.x_scroll_size = (n_elements(xsize) ne 0) ? xsize:400 self.y_scroll_size = (n_elements(ysize) ne 0) ? ysize:200 self.xsize = 80.*!d.x_ch_size self.ysize = self.y_scroll_size+10 self.color_ptr = (n_elements(color) ne 0) ? ptr_new(color):ptr_new(/allocate_heap) self.storage = (n_elements(uvalue) ne 0) ? ptr_new(uvalue):ptr_new('') self.uname = (n_elements(uname) ne 0) ? uname:'' return,1B end ; ************************************************************ ; pro rmd_text_display__define void = { rmd_text_display, $ parent:0L, $ tlb:0L, $ win:0L, $ winvis:0L, $ xsize:0L, $ ysize:0L, $ x_scroll_size:0L, $ y_scroll_size:0L, $ winbase:0L, $ uname:'', $ color_ptr:ptr_new(), $ storage:ptr_new(), $ text_ptr:ptr_new() } end ; ************************************************************ ; function cw_text_display, parent, $ obj_ref = obj_ref, $ _Extra = extra obj_ref = obj_new('rmd_text_display', parent, $ _Extra = extra ) ret = obj_ref->build_widget() obj_ref->get_property, tlb = tlb return,tlb end ; ************************************************************ ; ; ***************** EXAMPLE IMPLEMENTATION ******************* ; ; ************************************************************ ; pro text_display_test_event,event case widget_info(event.id,/uname) of 'QUIT': widget_control,event.top,/destroy 'DISPLAY': $ begin cmd_id = widget_info(event.top,find_by_uname = 'CMD') print,event.value widget_control,cmd_id,set_value = event.value end 'CMD': $ begin ; If not a carriage return then get out cr = 10B up = 9B if event.type ne 0 then return if byte(event.ch) eq cr then begin ; widget_control,event.top,get_uvalue = state,/no_copy ; state.colors = shift(state.colors,-1) id = widget_info(event.top,find_by_uname = 'DISPLAY') widget_control,id,get_uvalue = o ; ret = o->set_color(state.colors[0]) ; Get the new value widget_control,event.id,get_value = value widget_control,id,set_value = value widget_control,event.id,set_value = '' ; widget_control,event.top,set_uvalue = state,/no_copy endif if byte(event.ch) eq up then begin display = widget_info(event.top,find_by_uname = 'DISPLAY') widget_control,display,get_value = text_array endif end else: endcase end ; ************************************************************ ; pro text_display_test tlb = widget_base(/col,/tlb_frame_attr,mbar = bar) filemenu = widget_button(bar,value = 'File',/menu) void = widget_button(filemenu,value = 'Quit',uname = 'QUIT') id = cw_text_display(tlb,xsize = 400,ysize = 400, $ obj_ref = o,uname = 'DISPLAY') void = widget_text(tlb,/editable,value = '',uname = 'CMD', $ /all_events) widget_control,tlb,/realize colors = ['red','green','blue','violet red','brown','tomato','purple'] text = ['This is an example implementation','of CW_TEXT_DISPLAY.',''] text = [text,'This compound widget is used for the display of'] text = [text,'text, possibly echoed from a command line.'] text = [text,'','The text can be displayed in different colors.',''] text = [text,'Programmatically the colors can be selected by'] text = [text,'using the SET_COLOR method with the object reference'] text = [text,'for this compound widget.'] text = [text,'','This widget is scrollable allowing more text than can '] n = n_elements(text) text[n-1] = text[n-1]+'fit in the window to be viewed.' n = n_elements(text) these_colors = replicate('black',n) these_colors[6] = 'red' these_colors[8:10] = 'blue' these_colors[12] = 'purple' ;state = {colors:colors} widget_control,tlb,set_uvalue = state,/no_copy widget_control,id,set_uvalue = o for i = 0,n-1 do ret = o->set_color(these_colors[i]) widget_control,id,set_value = text,set_uvalue = o new_text = ['This is my new','message for you!'] ret = o->set_color(['blue','red']) widget_control,id,set_value = new_text text = strjoin(replicate('G',145)) widget_control,id,set_value = text xmanager,'text_display_test',tlb,/no_block end