;+
; This helper routine can be called after a CW_COLOREDLABEL widget
; is created to modify properties of the label other than the
; string value.  (The string value is modified via a call to
; WIDGET_CONTROL, SET_VALUE = Text on the compound widget.)
;
; @Param
;   ID {in}{required}{type=long}
;       Set this parameter to the ID of the CW_COLOREDLABEL
;       compound widget whose properties are to be changed.
;
; @Keyword
;   Dynamic_Resize {in} {optional}{type=boolean}
;       Set this keyword to a non-zero value to indiate that
;       if WIDGET_CONTROL, SET_VALUE is subsequently called
;       on the widget, that the label size should adjust to
;       accomodate the string, either enlaring or shrinking its
;       area as needed.
; @Keyword
;   Font {in}{optional}{type=string}
;       Set this keyword to the name of the font to be used to
;       display the text in the label.
; @Keyword
;   X_Pad {in}{optional}{type=integer}
;       Set this keyword to the number of pixels to the left and
;       right of the text to pad between the text and the bounds
;       of the label.
; @Keyword
;   Y_Pad {in}{optional}{type=integer}
;       Set this keyword to the number of pixels above and below
;       the text to pad between the text and the bounds of the
;       label.
; @Keyword
;   Background_Color {in}{optional}{type=BYTARR(3)}
;       Set this keyword to a 3-element byte vector indicating the red,
;       green and blue values to be used as the background color in the
;       label.
; @Keyword
;   Foreground_Color {in}{optional}{type=BYTARR(3)}
;       Set this keyword to a 3-element byte vector indicating the red,
;       green and blue values to be used as the text color in the
;       label.
;
; @Author
;   JLP, RSI Global Services
;
; @History
;   March 31, 2005 - Initial version
;-
Pro CW_ColoredLabel_SetProperty, ID, $
    Foreground_Color = Foreground_Color, $
    Background_Color = Background_Color, $
    X_Pad = X_Pad, $
    Y_Pad = Y_Pad, $
    Dynamic_Resize = Dynamic_Resize, $
    Font = Font
Compile_Opt StrictArr
On_Error, 2
If (~Widget_Info(ID, /Valid_ID) || ~Widget_Info(ID, /Realized)) then Begin
    Message, 'CW_COLOREDLABEL widget does not exist.', /Traceback
EndIf
StateBase = Widget_Info(ID, Find_by_UName = 'StateBase')
Widget_Control, StateBase, Get_UValue = State
If (N_elements(Foreground_Color) eq 3) then Begin
    State.Foreground_Color = Foreground_Color
EndIf
If (N_elements(Background_Color) eq 3) then Begin
    State.Background_Color = Background_Color
EndIf
If (N_elements(X_Pad) eq 1) then Begin
    State.X_Pad = X_Pad
EndIf
If (N_elements(Y_Pad) eq 1) then Begin
    State.Y_Pad = Y_Pad
EndIf
If (N_elements(Dynamic_Resize) eq 1) then Begin
    State.Dynamic_Resize = Dynamic_Resize
EndIf
If (N_elements(Font) eq 1) then Begin
    State.Font = Font
EndIf
Widget_Control, StateBase, Set_UValue = State
Widget_Control, ID, Set_Value = State.Value
End


;+
; This procedure is called when the colored label is
; destroyed.  At present it doesn't do anything, but
; if we eventually choose to use any pointers in the
; UVALUE structure, we may want to clean up the
; heap memory here.
;
; @Param
;   ID {in}{required}{type=long}
;       Set this parameter to the ID of the widget being destroyed.
;
; @Hidden
;
; @Author
;   JLP, RSI Global Services
;
; @History
;   March 29, 2005 - Initial version
;-
Pro CW_ColoredLabel_KillNotify, ID
Compile_Opt StrictArr
On_Error, 2
End


;+
; This method is called when WIDGET_CONTROL, GET_VALUE=val
; is called on the top-level base.  It returns the string
; value displayed in the label.
;
; @Param
;   ID {in}{required}{type=long}
;       Set this parameter to the widget ID of the top-level
;       base of the compound widget.
;
; @Hidden
;
; @Author
;   JLP, RSI Global Services
;
; @History
;   March 29, 2005 - Initial version
;
; @Returns
;   This function returns the string value associated with
;   the label.
;-
Function CW_ColoredLabel_GetValue, ID
Compile_Opt StrictArr
On_Error, 2
StateBase = Widget_Info(ID, Find_by_UName = 'StateBase')
Widget_Control, StateBase, Get_UValue = State
Return, State.Value
End


;+
; This method is called when WIDGET_CONTROL, SET_VALUE=val
; is called on the top-level base.  It sets the string
; value displayed in the label.
;
; @Param
;   ID {in}{required}{type=long}
;       Set this parameter to the ID of the top-level base
;       of the compound widget.
; @Param
;   Value {in}{required}{type=string scalar}
;       Set this parameter to the string to use for the
;       label value.
;
; @Hidden
;
; @Author
;   JLP, RSI Global Services
;
; @History
;   March 29, 2005 - Initial version
;
; @Uses
;   TextImage
;-
Pro CW_ColoredLabel_SetValue, ID, Value
Compile_Opt StrictArr
On_Error, 2
;
; First put the new string into the state structure.
;
StateBase = Widget_Info(ID, Find_by_UName = 'StateBase')
Widget_Control, StateBase, Get_UValue = State
State.Value = Value
Widget_Control, StateBase, Set_UValue = State
;
; We're building a new text image so we re-use the same
; font, colors, and padding as the original string.
;
If (State.Font ne '') then Begin
    Font = State.Font
EndIf
If (N_elements(State.Foreground_Color) eq 3) then Begin
    Foreground_Color = State.Foreground_Color
EndIf
If (N_elements(State.Background_Color) eq 3) then Begin
    Background_Color = State.Background_Color
EndIf
If (State.X_Pad ne -1) then Begin
    X_Pad = State.X_Pad
EndIf
If (State.Y_Pad ne -1) then Begin
    Y_Pad = State.Y_Pad
EndIf
;
; Create the new image of the text.
;
Image = TextImage(Value, /No_Transpose, $
    Font = Font, $
    Foreground_Color = Foreground_Color, $
    Background_Color = Background_Color, $
    X_Pad = X_Pad, $
    Y_Pad = Y_Pad)
;
; Update the graphics.
;
DrawWidget = Widget_Info(ID, Find_by_UName = 'ColoredLabelDraw')
Widget_Control, DrawWidget, Get_Value = oWindow
Widget_Control, DrawWidget, Set_UValue = Image
oWindow->GetProperty, Graphics_Tree = oView
If (State.Dynamic_Resize) then Begin
;
; If we had dynamic resizing turned on, we want to resize
; the draw window and viewplane to fit the image.  Otherwise,
; we may cut off text, which is the expected behavior if
; dynamic resizing is not explicitly set.
;
    Dimensions = (Size(Image, /Dimensions))[1:2]
    oView->SetProperty, Viewplane_Rect = [0, 0, Dimensions]
;
; We set update = 0 on the draw widget here to prevent
; flashing that'll occur if we resize the window.
;
    Widget_Control, DrawWidget, Update = 0
    oWindow->SetProperty, Dimensions = Dimensions
EndIf
;
; Update the image data and redraw the "label".
;
oImage = oView->GetByName('Model/Image')
oImage->SetProperty, Data = Image
oWindow->Draw
;
; Now that the draw widget is filled back in, we
; update the compound widget.  This prevents
; flashing during dynamic resizing.
;
Widget_Control, ID, Update = 1
End


;+
; This procedure is called when WIDGET_CONTROL, /REALIZE
; is executed on the top-level base of our compound widget
; base.  It constructs the graphics tree associated with
; the label image.
;
; @Param
;   ID {in}{required}{type=long}
;       Set this parameter to the ID of the first child
;       base of the compound widget's top-level base
;       being created.
;
; @Hidden
;
; @Author
;   JLP, RSI Global Services
;
; @History
;   March 29, 2005 - Initial version
;-
Pro CW_ColoredLabel_NotifyRealize, ID
Compile_Opt StrictArr
On_Error, 2
;
; The initial image is stored in the UVALUE of the image widget
; because we didn't have any place to draw it until now.
;
DrawWidget = Widget_Info(ID, Find_by_UName = 'ColoredLabelDraw')
Widget_Control, DrawWidget, Get_Value = oWindow, Get_UValue = Image
;
; Set up the viewplane_rect to match the window dimensions.
;
oWindow->GetProperty, Dimensions = Dimensions
oView = Obj_New('IDLgrView', Viewplane_Rect = [0, 0, Dimensions], $
    Color = [255, 255, 255])
;
; Create the graphics tree.  The label is actually a
; draw widget.
;
oWindow->SetProperty, Graphics_Tree = oView
oModel = Obj_New('IDLgrModel', Name = 'Model')
oView->Add, oModel
oImage = Obj_New('IDLgrImage', Image, Name = 'Image')
oModel->Add, oImage
;
; The final trick is to make the cursor switch back to the
; standard, non-graphics window pointer when the mouse is
; over the window.  The default is to display a crosshair
; which would make it distracting.
;
oWindow->SetCurrentCursor, 'Arrow'
oWindow->Draw
;
; Make the compound widget visible if it was hidden.
;
Parent = Widget_Info(ID, /Parent)
If (~Widget_Info(Parent, /Map)) then Begin
    Widget_Control, Parent, Map = 1
EndIf
End


;+
; This function creates a colored label compound widget providing
; most of the functionality of the standard WIDGET_LABEL but with
; with added capbility of setting foreground and background colors.
;
; @Param
;   Parent {in}{required}{type=long}
;       Set this parameter to the widget ID of the parent base in
;       which this compound widget will be created.
;
; @Keyword
;   Value {in}{required}{type=string scalar}
;       Set this keyword to the scalar string value to assign to
;       the label.
; @Keyword
;   Dynamic_Resize {in} {optional}{type=boolean}{default=0}
;       Set this keyword to a non-zero value to indiate that
;       if WIDGET_CONTROL, SET_VALUE is subsequently called
;       on the widget, that the label size should adjust to
;       accomodate the string, either enlaring or shrinking its
;       area as needed.  The default is to use the existing
;       label size.
; @Keyword
;   Font {in}{optional}{type=string}
;       Set this keyword to the name of the font to be used to
;       display the text in the label.  The default action is
;       to use the current default widget font.
; @Keyword
;   X_Pad {in}{optional}{type=integer}{default=3}
;       Set this keyword to the number of pixels to the left and
;       right of the text to pad between the text and the bounds
;       of the label.
; @Keyword
;   Y_Pad {in}{optional}{type=integer}{default=3}
;       Set this keyword to the number of pixels above and below
;       the text to pad between the text and the bounds of the
;       label.
; @Keyword
;   Background_Color {in}{optional}{type=BYTARR(3)}{default=system color}
;       Set this keyword to a 3-element byte vector indicating the red,
;       green and blue values to be used as the background color in the
;       label.  The default is to use the standard system widget background
;       color.
; @Keyword
;   Foreground_Color {in}{optional}{type=BYTARR(3)}{default=system color}
;       Set this keyword to a 3-element byte vector indicating the red,
;       green and blue values to be used as the text color in the
;       label.  The default is to use the standard system text widget color.
; @Keyword
;   _Extra {in}{optional}
;       Any extra parameters, such as UVALUE or UNAME, are passed
;       to the WIDGET_BASE call for the compound widget's top-level
;       base.
;
; @Author
;   JLP, RSI Global Services
;
; @Examples
;   Create a pair of labels, one standard, one colored, using the
;   same font<pre>
;   IDL> t = WIDGET_BASE(/COLUMN)
;   IDL> l = WIDGET_LABEL(t, VALUE = 'A test label', FONT = 'Tahoma')
;   IDL> cl = CW_COLOREDLABEL(t, VALUE = 'A test label', $
;   IDL>    /DYNAMIC_RESIZE, FOREGROUND_COLOR = [0, 0, 255], $
;   IDL>    FONT = 'Tahoma')
;   IDL> WIDGET_CONTROL, t, /REALIZE</pre>
;
;   Change the label text<pre>
;   IDL> WIDGET_CONTROL, cl, SET_VALUE = 'A longer label'</pre>
;
;   Make the label text flash between black and green<pre>
;   IDL> FOR I = 0, 10 DO BEGIN & $
;   IDL>    CW_COLOREDLABEL_SETPROPERTY, cl, $
;   IDL>    FOREGROUND_COLOR = [0,255,0]*(I MOD 2) & $
;   IDL>    WAIT, .5 & $
;   IDL> ENDFOR</pre>
;
; @History
;   March 29, 2005 - Initial version
;
; @Returns
;   This function returns the ID of the top-level base of the
;   compound widget.
;
; @Uses
;   CW_ColoredLabel_GetValue <br>
;   CW_ColoredLabel_KillNotify <br>
;   CW_ColoredLabel_Realize <br>
;   CW_ColoredLabel_SetValue <br>
;   TextImage
;
; @File_Comments
;   This function creates a colored label compound widget providing
;   most of the functionality of the standard WIDGET_LABEL but with
;   the added capability of setting foreground and background colors.<br>
;
;   Learn more about the IDLdoc documentation style at
;       http://www.rsinc.com/codebank/search.asp?FID=100
;-
Function CW_ColoredLabel, Parent, $
    Value = Value, $
    Dynamic_Resize = Dynamic_Resize, $
    Font = Font, $
    X_Pad = X_Pad, $
    Y_Pad = Y_Pad, $
    Background_Color = Background_Color, $
    Foreground_Color = Foreground_Color, $
    _Extra = Extra
Compile_Opt StrictArr
On_Error, 2
;
; Any extra keywords such as UVALUE or UNAME are passed
; to the base.
;
Base = Widget_Base(Parent, _Extra = Extra, $
    Func_Get_Value = 'CW_ColoredLabel_GetValue', $
    Pro_Set_Value = 'CW_ColoredLabel_SetValue')
;
; Initially hide the base until we've fully constructed it.
;
Widget_Control, Base, Map = 0
;
; Create the image to be used as the label from the text
; string and the associated color and geometry settings.
;
Image = TextImage(Value, /No_Transpose, $
    Font = Font, $
    X_Pad = X_Pad, $
    Y_Pad = Y_Pad, $
    Background_Color = Background_Color, $
    Foreground_Color = Foreground_Color)
;
; Get default colors to store in the state if they
; weren't specified by the caller.
;
Colors = Widget_Info(Base, /System_Colors)
;
; Create the state structure for the label.  We will use
; most of these values in the event that the user
; calls WIDGET_CONTROL, SET_VALUE with a new value.
;
State = { $
    Value : Value, $
    Font : (N_elements(Font) eq 1 ? Font : ''), $
    Dynamic_Resize : Keyword_Set(Dynamic_Resize), $
    Foreground_Color : (N_elements(Foreground_Color) eq 3 ? $
        Foreground_Color : Colors.Button_Text), $
    Background_Color : (N_elements(Background_Color) eq 3 ? $
        Background_Color : Colors.Face_3D), $
    X_Pad : (N_elements(X_Pad) eq 1) ? X_Pad : -1, $
    Y_Pad : (N_elements(Y_Pad) eq 1) ? Y_Pad : -1 $
    }
;
; The state is stored in the first child of the top-level base.
; We explicitly set its padding and so forth so there's no
; extra padding around the label text.
;
ChildBase = Widget_Base(Base, XPad = 0, YPad = 0, Space = 0, $
    UValue = State, $
    Notify_Realize = 'CW_ColoredLabel_NotifyRealize', $
    Kill_Notify = 'CW_ColoredLabel_KillNotify', $
    UName = 'StateBase')
;
; Create a draw widget the same size as the text image.  It will
; be populated with the image when the base is realized.  We
; explicitly use software rendering to avoid hardware quirks.
;
ImageSize = Size(Image, /Dimensions)
D = Widget_Draw(ChildBase, $
    Retain = 2, Graphics_Level = 2, Renderer = 1, $
    XSize = ImageSize[1], YSize = ImageSize[2], $
    UValue = Image, $
    UName = 'ColoredLabelDraw')
Return, Base
End
