#!/usr/bin/wish -f ## ## SCRIPT: draw_3colorGradient_isoscelesTriangle_create-imageWithShadedEdges.tk ## ## PURPOSE: This Tk GUI script 'draws' a color-filled 'isosceles triangle' ## --- with color-shading around the three edges of the triangle, to a ## background color. ## ## The pixel colors in the triangle are based on three user-selected colors ## assigned to the 3 vertices of the triangle --- and the color at any ## pixel inside the triangle is an average of the 3 colors using the ## barycentric coordinates of the point to compute the average. ## ## For example, if (L1,L2,L3) are the barycentric coordinates of a pixel, ## where L1 + L2 + L3 = 1, we use the RGB colors of the 3 vertices ## to calculate the RGB color at the pixel, as follows: ## ## Let the RGB values of vertex 1, 2, and 3 be ## (R1,G1,B1) and (R2,G2,B2) and (R3,G3,B3). ## Then ## Rpixel = (L1 * R1) + (L2 * R2) + (L3 * R3) ## Gpixel = (L1 * G1) + (L2 * G2) + (L3 * G3) ## Bpixel = (L1 * B1) + (L2 * B2) + (L3 * B3) ## ##+############################################# ## EXAMPLES OF USE of this triangle-shaped image: ## ## This 3D-like triangle could be used as ## ## 1) an icon or logo background. Nice quality text could be added ## on top of the triangle. ## ## 2) an unusual, triangle-shaped 'bullet' for line items on a web page ## or for menu items in a Tk GUI 'toolchest' --- if the image is ## shrunk to a small size. ## ##+############################ ## METHOD of creating the image, on the Tk canvas: ## ## This script makes this color-shaded shape via a Tk 'photo' image 'structure' ## placed on a Tk canvas widget. ## ## The in-memory image 'structure' is created by an 'image create photo' command. ## ## Then the image is put on the canvas via a Tk canvas 'create image' command. ## ## The image is (re)generated --- whenever there is a color change to a vertex, ## or whenever the size of the image area is changed --- or whenever some ## values are changed on some 'control' scale widgets. ## ## The image regeneration is done by building a list of lists of hexcolors ## for each row of pixels in the image area. Then the list-of-lists is ## 'put' on the image 'structure' with a single 'put' command. ## ## The triangle-shape lies within the 'photo' image structure on the canvas --- ## with a margin around a minimal, triangle-containing rectangle. ## ## In the margin, outside the triangle-shape on the canvas, a user-selected ## 'background' color is applied. ## ##+########## ## REFERENCES: ## ## This Tk script is based on techniques used in my Tk scripts for drawing ## other shapes --- which are 3D-like, color-gradient, edge-shadowed --- ## on a color background --- scripts such as: ## ## - "GUI for Drawing 'Super-ellipses', with nice shaded edges" ## at http://wiki.tcl.tk/37004 ## ## - "GUI for Drawing Rectangular 'Buttons' with nice shaded edges" ## at http://wiki.tcl.tk/37143 ## ## - "GUI for Drawing 'Super-formula' shapes, with nice shaded border" ## at http://wiki.tcl.tk/37156 ## ## - "GUI for Drawing 'Donut' shapes, with nice shaded border" ## at http://wiki.tcl.tk/37214 ## ## Thanks go to 'ulis' (deceased in 2008, R.I.P.) whose super-ellipse script ## on the Tcl-Tk wiki page 'Mathematics jewels' indicated to me that we could ## get nicely shaded edges on geometric shapes --- using 'image create photo' ## and a Tk canvas. ## ##+################################ ## METHOD of doing the EDGE SHADING: ## ## In my scripts above, I devised a 'color-shading-metric' v at each pixel point ## x,y that is within the rectangle/super-ellipse/super-formula/donut shape --- ## where v is between 0 and 1. And the value of v goes to 1 at the edges ## of these shapes --- and v is 0 in the middle of the shape. ## ## Then v and (1-v) are applied to a user-selected background color ## and a user-selected 'fill' color for any pixel within the shape --- to get ## a 'weighted-average' of the user-selected colors, for the color at a ## given pixel x,y. ## ## For this triangle, we use the barycentric coordinates of any pixel ## within the triangle --- to formulate our metric. ## ## For a given pixel x,y, let us say its barycentric coordinates ## are (L1,L2,L3) where L1 + L2 + L3 = 1. ## ## Note that at the edges (and vertices) of the triangle, at least one ## of the 3 barycentric coordinates is 0. And note that we want our ## metric, v(x,y) = v(L1,L2,L3), to be 1.0 at the edges of the triangle. ## Also, we want v to be 0.0 at the 'barycenter' of the triangle. ## ## (Having v be 1.0 at the outer border of the shape allows us to ## give a 'crisp' shading at the edges by using an 'extensity' exponent ## to set the extent-and-intensity of the shading at the edges.) ## ## Note that the 'barymetric center' of the triangle is at the point/pixel ## where (L1,L2,L3) = (1/3,1/3,1/3). And when one looks at any point ## within the triangle which is not on that center, at least one of the ## coordinates is less than 1/3. ## ## Note that the quantity u = 3.0 * min(L1,L2,L3) is 1.0 at the barycenter ## and is zero on the edges of the triangle. We want the opposite for ## our scalar 'color-shading-metric'. ## ## So for our 'color-shading-metric', we will use ## ## v(x,y) = v(L1,L2,L3) = 1.0 - ( 3.0 * min(L1,L2,L3) ) ## ## Note that v is 1.0 on the edges (and vertices) of the triangle, it is ## 0.0 at the barymetric center, and it is between 0 and 1 at other points ## in the triangle. ## ## So we have a suitable metric, v. ## ## At a point x,y, we determine the 'shaded color' at the point by ## using a color interpolated between ## ## 1) Rpixel,Gpixel,Bpixel --- 'color-bary', say --- which is ## the barymetrically-determined color of the point/pixel x,y ## calculated as indicated above --- namely: ## Let the RGB values of vertex 1, 2, and 3 be ## (R1,G1,B1) and (R2,G2,B2) and (R3,G3,B3). ## Then ## Rpixel = (L1 * R1) + (L2 * R2) + (L3 * R3) ## Gpixel = (L1 * G1) + (L2 * G2) + (L3 * G3) ## Bpixel = (L1 * B1) + (L2 * B2) + (L3 * B3) ## and ## 2) a user-selected background color, 'color-bkgd', say. ## ## We calculate the 'shaded color' at x,y by calulating a weighted average ## based on applying the factor v to 'color-bkgd' --- and applying ## (1 - v) to 'color-bary'. That is, ## shaded-color = v * color-bkgd + (1 - v) * color-bary. ## ## We actually calculate via formulas like ## Rshaded = v * Rbkgd + (1 - v) * Rbary ## Gshaded = v * Gbkgd + (1 - v) * Gbary ## Bshaded = v * Bbkgd + (1 - v) * Bbary ## ## Thus we will get the edge-shading (the 3D effect) for the ## 'triangle shape'. ## ## Actually, it turns out that v and 1-v give a rather washed-out (too ## gradual) shading effect. It is better if we raise v to a power N ## and use v^N and (1 - v^N), where we usually let N be an integer ## between 1 and 20. A value of N between 6 and 10 gives a pretty ## nice 'crisp' edge on this 3-colored triangle. ## ##+############## ## THE GUI DESIGN: ## ## The GUI made by this Tk script contains the following widgets. ## ## 1) a rectangular CANVAS widget on which the color-filled triangle ## shape will be drawn. ## ## 2) four color BUTTONS, to assign colors to the 3 triangle vertices ## and to the background. ## ## (Note that we could put another color selector button on the ## GUI to select the border-shading color to be a different color ## from the background color of the canvas area.) ## ## There are also 'Exit', 'Help', and 'ReDraw' BUTTONS on the GUI. ## ## 3) a SCALE widget for the exponent N to control the 'extensity' ## (the extent and intensity) of the edge-shading --- by using the ## two color-shading factors v^N and (1.0 - v^N). ## ## 4) a SCALE widget by which to determine a margin around the triangle ## ## 5) 2 SCALE widgets by which to set imgWidthPx and imgHeightPx, so that ## the user can request a specific image size. ## ##+################################## ## (RE)DRAW and RESIZE considerations: ## ## A redraw includes clearing the image on the canvas and redrawing ## the triangle shape on the solid color background in the image area. ## ## A redraw should be done whenever ## (a) a color button is used to change a vertex or background color, ## (b) the slider-button on the 'shading-exponent' scale is reset, ## (c) the slider-button on the 'margin' scale is reset, ## (d) the slider-buttons for image-size are reset. ## ## Note that we could someday implement a method by which the user could ## drag vertices on the canvas area --- even allowing the triangle to be ## non-isosceles. ## ##+########################## ## PERFORMANCE CONSIDERATIONS and the 'scale' widget: ## ## Since the redraw has a lot of pixels to color, especially when ## a large image size is requested, a redraw may take several seconds. ## ## So it is probably not going to be feasible/pleasing to do redraws ## 'dynamically' with the '-command' option of the 'scale' widgets. ## ## For now, I have defined a button1-release binding on the ## 'shading-exponent' scale widget to trigger a redraw --- only ## when the user finishes moving the slider-button of the scale. ## Similarly for the 'margin' widget. ## ## And the user can change the 2 scale widgets for the image size and ## then click the 'ReDraw' button to redraw the triangle in the newly ## resized image area. ## ## However, it should be pointed out that if erasing the image ## and (re)calculating-colors and putting the colors on the rectangular ## 'photo' image completes within a small fraction of a second, it ## would be feasible to do the redraws 'dynamically' with each movement ## of the slider-button, via the '-command' option. (But it might heat up ## the CPU doing those operations --- by quite a few degrees.) ## ##+######################### ## USING THE GENERATED IMAGE: ## ## A screen/window capture utility (like 'gnome-screenshot' on ## Linux) can be used to capture the GUI image in a PNG file, say. ## ## If necessary, an image editor (like 'mtpaint' on Linux) ## can be used to crop the window capture image. The image ## could also be down-sized --- say to make a 'bullet' image ## file or an icon/logo-background image file. ## ## The colored image file could be used with a utility (like the ## ImageMagick 'convert' command) to change the background ## color to TRANSPARENT, making a partially transparent GIF ## (or PNG) file. Then the semi-transparent image file could be used, ## for 'bullets' or icons or logos in HTML pages --- or for icons on ## desktops --- or for bullets or icons in (Tk) GUIs or 'toolchests'. ## ##+######################################################################## ## 'CANONICAL' STRUCTURE OF THIS TK CODE: ## ## 0) Set general window & widget parms (win-name, win-position, win-color-scheme, ## fonts, widget-geometry-parms, win-size-control, text-array-for-labels-etc). ## ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack ALL frames and sub-frames. ## ## 2) Define all widgets in the frames, frame by frame. ## After all the widgets for a frame are defined, pack them in the frame. ## ## 3) Define keyboard or mouse/touchpad/touch-sensitive-screen 'event' ## BINDINGS, if needed. ## ## 4) Define PROCS, if needed. ## ## 5) Additional GUI INITIALIZATION (typically with one or two of ## the procs), if needed. ## ## ## Some detail about the code structure of this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : '.fRbuttons' '.fRmsg' '.fRcontrols' '.fRimgsize' '.fRcanvas' ## No sub-frames. ## ## 1b) Pack ALL frames. ## ## 2) Define all widgets in the frames (and pack them): ## ## - In '.fRbuttons': the buttons 'Exit','Help','ReDraw', ## 'Vertex1color','Vertex2color','Vertex3color', 'BkgdColor' ## ## - In '.fRmsg': one Label widget ## ## - In '.fRcontrols': ## 1 'label' and 1 'scale' widget --- for N ('extensity' exponent) ## and ## 1 'label' and 1 'scale' widget --- for 'margin-fraction'. ## ## - In '.fRimgsize': ## 1 'label' and 1 'scale' widget --- for image width (in pixels) ## and ## 1 'label' and 1 'scale' widget --- for image height (in pixels). ## ## - In '.fRcanvas': 1 'canvas' widget ## ## 3) Define bindings: ## ## - a button1-release on the 'shading-exponent' scale widget, ## to do a redraw ## ## - a button1-release on the 'margin-fraction' scale widget, ## to do a redraw ## ## NOTE: The color changes should trigger a redraw, but we do not ## need bindings to do those redraws. ## The redraws can be done in procs that are used to ## set each of the colors. ## ## 4) Define procs: ## ## 'ReDraw' - to clear the canvas and redraw the pixels ## in the image rectangle that contains the ## triangle shape ## --- for the current values of the 3 vertex ## colors, the background color, and the ## 'shading-exponent' scale parameter value ## --- and for the current size of the canvas. ## ## 'advise_user' - shows a message in the '.fRmsg' frame ## ## 'show_user_hexcolorCodes' - shows a message on a label widget ## in the '.fRbuttons' frame ## ## 'set_vertex_color1' - shows a color selector GUI and uses the ## user-selected color to set the color ## of vertex1 --- and call 'ReDraw'. ## ## 'set_vertex_color2' - shows a color selector GUI and uses the ## user-selected color to set the color ## of vertex2 --- and call 'ReDraw'. ## ## 'set_vertex_color3' - shows a color selector GUI and uses the ## user-selected color to set the color ## of vertex3 --- and call 'ReDraw'. ## ## 'set_color_background' - shows a color selector GUI and uses the ## user-selected color to set the background ## color --- and call 'ReDraw'. ## ## 5) Additional GUI initialization: ## Set some initial values of parms ## --- 3 vertex colors, 1 background ## color --- an intial value for the ## 'shading-exponent' N --- an initial ## value for the 'margin-fraction' --- ## initial values for image size (width ## and height in pixels). ## ## Then execute proc 'ReDraw' once ## to start with a triangle shape on ## the canvas rather than a blank canvas. ##+######################################################################## ## DEVELOPED WITH: ## Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october release, 'Karmic Koala'). ## ## $ wish ## % puts "$tcl_version $tk_version" ## showed 8.5 8.5 on Ubuntu 9.10 ## after Tcl-Tk 8.4 was replaced by 8.5 --- to get anti-aliased fonts. ##+####################################################################### ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2013aug26 Started coding the GUI. ## Changed by: Blaise Montandon 2013aug30 Implemented ReDraw proc --- i.e. ## the barymetric calculations. ## Changed by: Blaise Montandon 2013sep04 Reviewed comments and code. ## Did some experimenting with the ## N exponent and scale limits. ## Changed by: Blaise Montandon 2015jan21 Changed location of color-selector ## script to use a common script in ## the 'tkGooies' FE system. ## Changed by: Blaise Montandon 2016jan07 Changed the way 'v' is calculated, ## for 'crisper' edge shading. ## Added a scale widget for ## 'margin-fraction'. Added 2 scale ## widgets for better control of ## size of the image area. Added ## procs 'advise_user' and ## 'show_user_hexcolorCodes'. ## Added scrollbars to the canvas. ##+####################################################################### ##+####################################################################### ## Set WINDOW TITLE and intial POSITION. ##+####################################################################### wm title . "3D-like, edge-shaded 'isosceles triangle' shape, on a single-color canvas" wm iconname . "ShadedTriangle" wm geometry . +15+30 ##+###################################################### ## Set the COLOR SCHEME for the window and set the ## background color for the 'trough' in some widgets. ##+###################################################### tk_setPalette "#e0e0e0" # set listboxBKGD "#f0f0f0" # set entryBKGD "#f0f0f0" set scaleBKGD "#f0f0f0" ##+######################################################## ## DEFINE (temporary) FONT NAMES. ## ## We use a VARIABLE-WIDTH FONT for LABEL and BUTTON widgets. ## ## We use a FIXED-WIDTH FONT for LISTBOXES (and ENTRY fields ## and TEXT widgets, if any). ##+######################################################## font create fontTEMP_varwidth \ -family {comic sans ms} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_varwidth \ -family {comic sans ms} \ -size -12 \ -weight bold \ -slant roman ## Some other possible (similar) variable-width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana font create fontTEMP_fixedwidth \ -family {liberation mono} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_fixedwidth \ -family {liberation mono} \ -size -12 \ -weight bold \ -slant roman ## Some other possible fixed-width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## DejaVu Sans Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+########################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padding and borderwidths --- and ## width and height of canvas) ##+########################################################### ## BUTTON geom parameters: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 ## LABEL geom parameters: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 ## CANVAS geom parameters: set initCanWidthPx 500 set initCanHeightPx 400 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 ## SCALE geom parameters: set BDwidthPx_scale 2 set scaleThicknessPx 10 # set initScaleLengthPx 100 ##+################################################################### ## Set MIN-SIZE of the window (roughly). ## ## For WIDTH, allow for the minwidth of the '.fRbuttons' frame: ## about 7 buttons (Exit,Help,ReDraw,Color1,Color2,Color3,ColorBkgd). ## We want to at least be able to see the Exit button. ## ## For HEIGHT, allow ## 2 chars high for the '.fRbuttons' frame, ## 2 char high for the '.fRcontrols' frame, ## 24 pixels high for the '.fRcanvas' frame. ##+################################################################### set minWinWidthPx [font measure fontTEMP_varwidth \ "Exit Help ReDraw Vertex1 Vertex2 Vertex3 Background"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 7 x 4 pixels/widget for borders/padding for ## 7 widgets --- 7 buttons. set minWinWidthPx [expr {36 + $minWinWidthPx}] ## MIN HEIGHT --- allow ## 2 char high for 'fRbuttons' ## 1 char high for 'fRmsg' ## 2 char high for 'fRcontrols' ## 2 char high for 'fRimgsize' ## 24 pixels high for 'fRcanvas' set CharHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {7 * $CharHeightPx}] ## Add about 28 pixels for top-bottom window decoration, ## about 5x4 pixels for each of the 5 stacked frames and their ## widgets (their borders/padding) --- and 24 pixels for canvas. set minWinHeightPx [expr {72 + $minWinHeightPx}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by enlarging ## the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+#################################################################### ## if { "$VARlocale" == "en"} ## For widgets in frame '.fRbuttons': set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonDRAW) "ReDraw" set aRtext(buttonCOLOR1) "Vertx1colr" set aRtext(buttonCOLOR2) "Vertx2colr" set aRtext(buttonCOLOR3) "Vertx3colr" set aRtext(buttonCOLORBKGD) "BkgdColr" ## For widgets in frame '.fRcontrols': set aRtext(labelEXPONENT) "N, exponent for 'extensity' of edge shading:" set aRtext(labelMARGIN) "Margin fraction:" ## For widgets in frame 'fRimgsize': set aRtext(labelXmaxPx) "Image width (in pixels):" set aRtext(labelYmaxPx) "Image Height (in pixels):" ## END OF if { "$VARlocale" == "en"} ##+################################################################ ## DEFINE *ALL* THE FRAMES: ## ## Top-level : '.fRbuttons' '.fRmsg' '.fRcontrols' '.fRimgsize' '.fRcanvas' ## Sub-frames: none ##+################################################################ ## FOR TESTING change 0 to 1: ## (Example1: To see appearance of frames when borders are drawn.) ## (Example2: To see sizes of frames for various '-fill' options.) ## (Example3: To see how frames expand as window is resized.) if {0} { set RELIEF_frame raised set BDwidthPx_frame 2 } else { set RELIEF_frame flat set BDwidthPx_frame 0 } frame .fRbuttons -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRmsg -relief raised -borderwidth 2 frame .fRcontrols -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRimgsize -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRcanvas -relief raised -borderwidth 2 ##+############################## ## PACK the top-level FRAMES. ##+############################## pack .fRbuttons \ .fRmsg \ .fRcontrols \ .fRimgsize \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcanvas \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+######################################################### ## Frames are defined and packed. ## Now we are ready to define the widgets in the frames. ##+######################################################### ##+##################################################################### ## In the '.fRbuttons' FRAME --- DEFINE-and-PACK ## BUTTONS (for Exit,Help,Vertex1color,Vertex2color,Vertex3color, ## and BackgroundColor) ##+##################################################################### button .fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} button .fRbuttons.buttDRAW \ -text "$aRtext(buttonDRAW)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {ReDraw 0} button .fRbuttons.buttCOLOR1 \ -text "$aRtext(buttonCOLOR1)" \ -font fontTEMP_SMALL_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command "set_vertex_color1" button .fRbuttons.buttCOLOR2 \ -text "$aRtext(buttonCOLOR2)" \ -font fontTEMP_SMALL_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command "set_vertex_color2" button .fRbuttons.buttCOLOR3 \ -text "$aRtext(buttonCOLOR3)" \ -font fontTEMP_SMALL_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command "set_vertex_color3" button .fRbuttons.buttCOLORBKGD \ -text "$aRtext(buttonCOLORBKGD)" \ -font fontTEMP_SMALL_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command "set_background_color" label .fRbuttons.labelCOLORS \ -text "" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ##+########################################### ## Pack the widgets in the '.fRbuttons' frame. ##+########################################### pack .fRbuttons.buttEXIT \ .fRbuttons.buttHELP \ .fRbuttons.buttDRAW \ .fRbuttons.buttCOLOR1 \ .fRbuttons.buttCOLOR2 \ .fRbuttons.buttCOLOR3 \ .fRbuttons.buttCOLORBKGD \ .fRbuttons.labelCOLORS \ -side left \ -anchor w \ -fill none \ -expand 0 ##+##################################################################### ## In the '.fRmsg' FRAME --- DEFINE-and-PACK one LABEL widget. ##+##################################################################### label .fRmsg.labelINFO \ -text "" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief flat \ -bg "#ff9999" \ -bd $BDwidthPx_label pack .fRmsg.labelINFO \ -side left \ -anchor w \ -fill x \ -expand 1 ##+################################################################## ## In the '.fRcontrols' FRAME ---- DEFINE-and-PACK ## 1 LABEL and 1 SCALE widget for N, the 'shading-exponent'. ##+################################################################### label .fRcontrols.label_N \ -text "$aRtext(labelEXPONENT)" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief ridge \ -bd $BDwidthPx_label ## Set this widget var in the GUI initialization section ## at the bottom of this script. # set N 0.4 scale .fRcontrols.scale_N \ -from 1 -to 20 \ -resolution 1 \ -length 200 \ -font fontTEMP_SMALL_varwidth \ -variable N \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx ## We do not supply the redraw command to this scale widget, ## because the redraw is probably not going to proceed within a ## fraction of a second. Instead, we supply a button1-release ## binding on the scale widget, to do the redraw. # -command "ReDraw" label .fRcontrols.labelMARGIN \ -text "$aRtext(labelMARGIN)" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief ridge \ -bd $BDwidthPx_label ## Set this widget var in the GUI initialization section ## at the bottom of this script. # set marginFRACTION 0.1 scale .fRcontrols.scaleMARGIN \ -from 0.00 -to 0.40 \ -resolution 0.01 \ -length 200 \ -font fontTEMP_SMALL_varwidth \ -variable marginFRACTION \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx ## We do not supply the redraw command to this scale widget, ## because the redraw is probably not going to proceed within a ## fraction of a second. Instead, we supply a button1-release ## binding on the scale widget, to do the redraw. # -command "ReDraw" ## PACK the scale widgets in frame '.fRcontrols'. pack .fRcontrols.label_N \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRcontrols.scale_N \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRcontrols.labelMARGIN \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRcontrols.scaleMARGIN \ -side left \ -anchor w \ -fill none \ -expand 0 ##+################################################################## ## In the '.fRimgsize' FRAME ---- DEFINE ## 1 LABEL and 1 SCALE widget for Xmax ## 1 LABEL and 1 SCALE widget for Ymax. ## Then PACK them. ##+################################################################### label .fRimgsize.labelXmaxPx \ -text "$aRtext(labelXmaxPx)" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief ridge \ -bd $BDwidthPx_label ## Set this widget var in the GUI initialization section ## at the bottom of this script. # set XmaxPx 500 scale .fRimgsize.scaleXmaxPx \ -from 10 -to 1000 \ -resolution 1 \ -bigincrement 1 \ -repeatdelay 1000 \ -length 250 \ -font fontTEMP_SMALL_varwidth \ -variable XmaxPx \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx # -command "Redraw" pack .fRimgsize.labelXmaxPx \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRimgsize.scaleXmaxPx \ -side left \ -anchor w \ -fill x \ -expand 0 ## DEFINE SCALE for YmaxPx. label .fRimgsize.labelYmaxPx \ -text "$aRtext(labelYmaxPx)" \ -font fontTEMP_SMALL_varwidth \ -justify left \ -anchor w \ -relief ridge \ -bd $BDwidthPx_label ## Set this widget var in the GUI initialization section ## at the bottom of this script. # set YmaxPx 400 scale .fRimgsize.scaleYmaxPx \ -from 10 -to 1000 \ -resolution 1 \ -bigincrement 1 \ -repeatdelay 1000 \ -length 250 \ -font fontTEMP_SMALL_varwidth \ -variable YmaxPx \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx # -command "Redraw" pack .fRimgsize.labelYmaxPx \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRimgsize.scaleYmaxPx \ -side left \ -anchor w \ -fill x \ -expand 0 ##+###################################################### ## In the '.fRcanvas' FRAME - ## DEFINE-and-PACK the 'canvas' widget ##+###################################################### ## We set highlightthickness & borderwidth of the canvas to ## zero, as suggested on page 558, Chapter 37, 'The Canvas ## Widget', in the 4th edition of the book 'Practical ## Programming in Tcl and Tk'. ##+###################################################### canvas .fRcanvas.can \ -width $initCanWidthPx \ -height $initCanHeightPx \ -relief flat \ -highlightthickness 0 \ -borderwidth 0 \ -yscrollcommand ".fRcanvas.scrolly set" \ -xscrollcommand ".fRcanvas.scrollx set" scrollbar .fRcanvas.scrolly \ -orient vertical \ -command ".fRcanvas.can yview" scrollbar .fRcanvas.scrollx \ -orient horizontal \ -command ".fRcanvas.can xview" ##+####################################################### ## PACK the widgets in frame '.fRcanvas'. ## ## NOTE: ## NEED TO PACK THE SCROLLBARS BEFORE THE CANVAS WIDGET. ## OTHERWISE THE CANVAS WIDGET TAKES ALL THE FRAME SPACE. ##+####################################################### pack .fRcanvas.scrolly \ -side right \ -anchor e \ -fill y \ -expand 0 pack .fRcanvas.scrollx \ -side bottom \ -anchor s \ -fill x \ -expand 0 ## !!!NEED TO USE '-expand 0' FOR THE X AND Y SCROLLBARS, so that ## the canvas is allowed to fill the remaining frame-space nicely ## --- without a gap between the canvas and its scrollbars. pack .fRcanvas.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+######################################## ## END OF the DEFINITION OF THE GUI WIDGETS ##+######################################## ##+############################### ## BINDINGS SECTION: ##+############################### ##+######################################################### ## If these button1-release bindings on the scale widgets is ## annoying to the user (causing redraws when the user does not ## want redraws to occur), we could comment this and have the ## user use the 'ReDraw' button instead. ##+######################################################### bind .fRcontrols.scale_N "ReDraw 0" bind .fRcontrols.scaleMARGIN "ReDraw 0" ## If user resizes window (in x direction, y direction, or both), ## a canvas resize command does not cause the window to expand/contract ## in the user-changed direction ## --- whereas it worked before the user intervenes in window resizing. ## (This is on Linux, Gnome2 desktop environment.) ## ## QUESTIONS: ## How to get window to resize as before?? ## (Depends on window manager?? Some wm's are OK??) ## ## 'wm geometry . {}' WORKS! See ReDraw proc. ## ## FOR TESTING: # bind . {puts "Width of %W is %w and height is %h"} # bind . {puts "Window %W has changed width to %w and height to %h"} ##+###################################################################### ## PROCS SECTION: ## ## 'ReDraw' - called by ## - the 'Additional GUI Initialization' section ## at the bottom of this script, ## - the set-color procs, ## - a button1-release binding on the N and MARGIN ## scale widgets, OR ## - the ReDraw button. ## ## Draws the triangle shape on the image area for ## the current color var values --- and for the ## current 'shading-exponent' scale parameter value ## and the current 'margin-fraction' scale parameter. ## ## 'advise_user' - called by the ReDraw proc ## ## 'show_user_hexcolorCodes' - called by the 'set_*_color*' procs below ## ## 'set_vertex_color1' - called by vertex1-color button '-command' ## ## 'set_vertex_color2' - called by vertex2-color button '-command' ## ## 'set_vertex_color3' - called by vertex3-color button '-command' ## ## 'set_background_color' - called by background color button '-command' ## ## 'update_color_labels' - called by the color procs to update ## colors and text on the color buttons ## ## 'popup_msgVarWithScroll' - called by 'Help' button ## ##+####################################################################### ##+####################################################################### ## proc ReDraw - ## ## PURPOSE: ## Draws the triangle shape on the canvas. ## ## METHOD: ## 1) We will build rows of pixels in a Tcl list var 'onerowLISTcolors'. ## 2) After building each row, we will add this list to a Tcl list var ## 'allrowsLISTcolors'. ## 3) We put ALL the pixels 'at once' into the 'image structure' with ## one 'put' command: ## imgID put $allrowsLISTcolors -to 0 0 ## where (0 0) is the upper left corner of the image area. ## ## CALLED BY: - the GUI initialization section at the bottom of ## this script, ## - the ReDraw button, ## - the 3 set-color procs, and ## - a button1-release binding on the 'extensity' exponent ## 'scale' widget and on the 'margin-fraction' scale widget. ##+######################################################################## ## NOTE: The 'x' argument is to avoid an error when the scale '-command' ## passes a scale value as an argument to the command. This is in ## case we try using the '-command' option of a scale widget to ## do the redraws 'dynamically' as a slider-button is moved. ## (We could ignore the 'x' value and use values in global variables.) ##+####################################################################### ## METHOD OF SETTING THE VERTICES OF THE TRIANGLE: ## ## We set the vertices of the isoceles triangle by setting the coordinates ## according to the current canvas width and height --- ## imgWidthPx and imgHeightPx. ## ## Say vertex 1 (x1px,y1px) is at the peak of the triangle, and vertex 2 and 3 ## (x2px,y2px) and (x3px,y3px) are at the base of the triangle. ## Then we set the vertex coordinates (in pixels), relative to the upper-left ## corner of the image, by: ## x1px = 0.5 * imgWidthPx ## y1px = $marginFRACTION * imgHeightPx ## x2px = $marginFRACTION * imgWidthPx ## y2px = (1.0 - $marginFRACTION) * imgHeightPx ## x3px = (1.0 - $marginFRACTION) * imgWidthPx ## y3px = (1.0 - $marginFRACTION) * imgHeightPx ##+####################################################################### ## METHOD OF SETTING THE COLOR OF PIXELS: ## ## The color at any pixel in the triangle is an average of the 3 colors using ## the barycentric coordinates of the point to compute the average. ## ## For example, if (L1,L2,L3) is the barycentric coordinate of a pixel, ## where L1 + L2 + L3 = 1, we use the RGB colors of the 3 vertices ## to calculate the RGB color at the pixel, as follows: ## ## Let the RGB values of vertex 1, 2, and 3 be ## (R1,G1,B1) and (R2,G2,B2) and (R3,G3,B3). ## Then ## Rbary = (L1 * R1) + (L2 * R2) + (L3 * R3) ## Gbary = (L1 * G1) + (L2 * G2) + (L3 * G3) ## Bbary = (L1 * B1) + (L2 * B2) + (L3 * B3) ## ##+####################################################################### ## METHOD OF SHADING THE COLORS OF THE PIXELS: ## ## For shading the edges of the triangle, we use a ## scalar 'color-shading-metric', v(x,y), given by ## ## v = 1.0 - ( 3.0 * min(L1,L2,L3) ) ## ## where the Li are the barycentric coordinates of a point x,y in the ## triangle. ## ## Note that u = 3.0 * min(L1,L2,L3) is 1.0 at the barycenter of the triangle ## and u is zero on the outer edges of the triangle. ## Hence v is 0.0 at the barycenter of the triangle and v is 1.0 ## on the outer edges of the triangle. ## ## Then for a pixel whose color was calculated to be (Rbary,Gbary,Bbary), ## we calculate the 'shaded color' of the pixel via ## Rshaded = (1 - v) * Rbary + v * Rbkgd ## Gshaded = (1 - v) * Gbary + v * Gbkgd ## Bshaded = (1 - v) * Bbary + v * Bbkgd ## ## In the case when the background color is black, then ## (Rbkgd,Gbkgd,Bbkgd) = (0,0,0), so the equations above become ## Rshaded = (1 - v) * Rbary ## Gshaded = (1 - v) * Gbary ## Bshaded = (1 - v) * Bbary ## and (1 - v) = 1.0 at the barycenter of the triangle. ## ##+####################################################################### ## USING THE 'EXTENSITY' EXPONENT, N: ## ## To allow the user to get 'crisper' shading at the edges of the triangle, ## we actually use v^N instead of v in the above shading calculations. ## So we actually use ## Rshaded = (1 - v^N) * Rbary + v^N * Rbkgd ## Gshaded = (1 - v^N) * Gbary + v^N * Gbkgd ## Bshaded = (1 - v^N) * Bbary + v^N * Bbkgd ## ##+##################################################################### ## METHOD OF CALCULATING THE BARYCENTRIC COORDINATES OF A POINT/PIXEL: ## ## FROM a PDF file titled: ## The Simplex and Barycentric Coordinates ## by James Emery ## Latest Edit: 8/30/2012 ## ## We get the following formulas for computing the barymentric coordinates ## --- L1,L2,L3 --- of a point P relative to a triangle with vertices ## P1,P2,P3. ## ## If all 3 barycentric coordinates are between 0 and 1, the point is ## inside the triangle. ## ## The general computation to determine an interior point, requires 11 ## additions or subtractions, 6 multiplications, 2 divisions, and 3 ## comparisons. The computation may be done as follows. ## ## We let P1=(x1,y1), P2=(x2,y2), P3=(x3,y3), P=(x,y). Let ## ## a11 = x1 - x3 ## a21 = y1 - y3 ## a12 = x2 - x3 ## a22 = y2 - y3 ## and ## b1 = x - x3 ## b2 = y - y3 . ## ## Let D be the determinant ## D = (a11 * a22) - (a21 * a12) ## ## Then we have ## L1 = ((b1 * a22) - (b2 * a12)) / D ## ## L2 = ((a11 * b2) - (a21 * b1)) / D ## ## L3 = 1 - (L1 + L2) ## ## ---- ## Furthermore Emery provides this C program code for the above calculations. ## ## //c+ bary2 barycentric coordinates of a point in the plane ## int bary2(double* p,double* p1,double* p2,double* p3,double* lambda){ ## double d,a11,a12,a21,a22,b1,b2; ## int i; ## a11=p1[0]-p3[0]; ## a21=p1[1]-p3[1]; ## a12=p2[0]-p3[0]; ## a22=p2[1]-p3[1]; ## b1=p[0]-p3[0]; ## b2=p[1]-p3[1]; ## d=a11*a22-a21*a12; ## if(d == 0.){ ## return(0); ## } ## lambda[0]=(b1*a22 - b2*a12)/d; ## lambda[1]=(a11*b2-a21*b1)/d; ## lambda[2]=1.-lambda[0] - lambda[1]; ## for(i=0;i<3;i++){ ## if((lambda[i] <= - EPSILON) || (lambda[i] >= 1.+ EPSILON)){ ## return(0); ## } ## } ## return(1); ## } ## ## END OF procedure 'bary2' ##+######################################################################### ## We may use EPSILON to check if the determinant is near zero. ## (NOT USED currently, because we have a 'well-behaved' triangle.) ## (Might be useful if we allow the user to move the vertices around.) set EPSILON 0.0005 ## If we draw ovals at the vertex points, we may use a ## radius parameter like this. # set radiusPx 4 proc ReDraw {x} { ## FOR TESTING: (To dummy out this redraw proc while ## it is 'under consruction' --- ## so that we can test out the GUI ## without doing any draws.) # return global N marginFRACTION EPSILON XmaxPx YmaxPx \ COLOR1r COLOR1g COLOR1b COLOR1hex \ COLOR2r COLOR2g COLOR2b COLOR2hex \ COLOR3r COLOR3g COLOR3b COLOR3hex \ COLORBKGDr COLORBKGDg COLORBKGDb COLORBKGDhex ################################################### ## Indicate that drawing calculations are starting. ################################################### advise_user "*BUSY* ... calculating pixel colors." ################################################ ## Set the current time, for determining elapsed ## time for building the 'photo' image. ################################################ set t0 [clock milliseconds] ################################################ ## Change the cursor to a 'watch' cursor. ################################################ # . config -cursor watch ## Make the cursor visible. # update ######################################################################### ## Delete the current image structure. ## We may need to do this when the canvas has been re-sized, ## so that we can redraw the image according to the new canvas size. (?) ######################################################################### catch {image delete imgID} ############################################################################# ## Let us make each dimension of the image an odd integer (pixels), ## so there are an equal number of pixels on either side of the center pixel. ############################################################################# set imgWidthPx $XmaxPx set imgHeightPx $YmaxPx if {$imgWidthPx % 2 == 0} { incr imgWidthPx -1 } if {$imgHeightPx % 2 == 0} { incr imgHeightPx -1 } ######################################################### ## Clear the canvas of previous vertex markers. ## (NOT USED, since we are not placing markers, like circles ## with 'create oval', at the vertices --- yet.) ######################################################### # .fRcanvas.can delete all ##################################### ## Make the new image structure. ##################################### image create photo imgID -width $imgWidthPx -height $imgHeightPx ############################################################################ ## Put the new image 'structure' on the canvas. ## (Note to myself: Should this statement be at top or bottom of this proc?) ############################################################################ .fRcanvas.can create image 0 0 -anchor nw -image imgID ######################################################## ## Set the 'scrollregion' of the canvas according to the ## size of the image. (A simple 'update' does not work.) ######################################################## .fRcanvas.can configure -scrollregion "0 0 $imgWidthPx $imgHeightPx" ######################################################## ## Make the canvas area as big as we can to accomodate ## a large image. ## (We try some 'wm' commands to get the window to resize ## according to the canvas resize --- even after the ## user has manually resized the top window.) ######################################################## # wm sizefrom . program ;# NO HELP. # wm withdraw . ;# This pair of commands causes a temporary # wm deiconify . ;# 'transparent window' to display. NO HELP. # wm geometry . {} ;# from http://wiki.tcl.tk/10720 ; WORKS! .fRcanvas.can configure -width $imgWidthPx -height $imgHeightPx wm geometry . {} ;# WORKS here too. #################################################################### ## We set the coordinates that will be used to contain ## the rectangle that contains the triangle. That rectangle defines ## a margin around the triangle that is the background color. ## These values also help us set the coordinates of the 3 vertices. #################################################################### set ytopPx [expr {int($marginFRACTION * $imgHeightPx)}] set ybotPx [expr {int( (1.0 - $marginFRACTION) * $imgHeightPx ) }] set xleftPx [expr {int($marginFRACTION * $imgWidthPx)}] set xrightPx [expr {int( (1.0 - $marginFRACTION) * $imgWidthPx ) }] ###################################################################### ## Get the half width and height of the image rectangle --- with which ## to calculate the pixel-coordinates of at least one vertex. ###################################################################### set xmidPx [expr {1 + int($imgWidthPx / 2)}] set ymidPx [expr {1 + int($imgHeightPx / 2)}] ##################################################################### ## We define the coordinates of the 3 vertices. ##################################################################### set vert1Xpx $xmidPx set vert1Ypx $ytopPx set vert2Xpx $xleftPx set vert2Ypx $ybotPx set vert3Xpx $xrightPx set vert3Ypx $ybotPx ######################################################## ## Calculate the determinant, D, based on the 3 vertices. ######################################################## set a11 [expr {$vert1Xpx - $vert3Xpx}] set a21 [expr {$vert1Ypx - $vert3Ypx}] set a12 [expr {$vert2Xpx - $vert3Xpx}] set a22 [expr {$vert2Ypx - $vert3Ypx}] set D [expr {double(($a11 * $a22) - ($a21 * $a12))}] ## FOR TESTING: # puts "Determinant D: $D" ######################################################################### ## HERE IS THE 'GUTS' OF DRAWING THE TRIANGLE (a double loop): ## In a loop over yPx and xPx, where yPx and xPx are measured from the ## top left of the canvas/image rectangle, we calculate the hex-color ## for each pixel, according to barycentric coordinates (L1,L2,L3) and ## according to our 'color-merging-metric': ## v = 1.0 - ( 3.0 * min(L1,L2,L3) ) ####################################################################### ####################################################### ## Remove var 'allrowsLISTcolors' so that it can be ## re-created by a first 'lappend' command below. ## ## "You can call 'lappend' with the name of an undefined ## variable and the variable will be created." from ## page 66 of Chapter 5 'Tcl Lists' of the book ## 'Practical Programming in Tcl and Tk' (4th edition) ## by Brent Welch, Ken Jones, Jeffrey Hobbs. ####################################################### catch {unset allrowsLISTcolors} ####################################################### ## Start the double loop over the pixels of the image. ####################################################### for {set yPx 0} {$yPx < $imgHeightPx} {incr yPx} { ####################################################### ## Remove var 'onerowLISTcolors' so that it can be ## re-created by a first 'lappend' command below. ## ## "You can call 'lappend' with the name of an undefined ## variable and the variable will be created." from ## page 66 of Chapter 5 'Tcl Lists' of the book ## 'Practical Programming in Tcl and Tk' (4th edition) ## by Brent Welch, Ken Jones, Jeffrey Hobbs. ####################################################### catch {unset onerowLISTcolors} ######################################################## ## Start the next loop over a row of pixels of the image. ######################################################## for {set xPx 0} {$xPx <= $imgWidthPx} {incr xPx} { ############################################################### ## If we are on the left (or right) of the rectangle containing ## the triangle, set the pixel to the background color ## and skip out ('continue') to the next pixel. ############################################################### if {$xPx < $xleftPx || $xPx > $xrightPx || \ $yPx < $ytopPx || $yPx > $ybotPx} { lappend onerowLISTcolors $COLORBKGDhex continue } ############################################################### ## Determine whether the xPx,yPx point is within the triangle ## by determining its barycentric coordinates. ## ## If any of the 3 coordinates is less than 0 or greater than 1, ## the point is outside the triangle and we set its color to the ## background color and 'continue' to the next step in this loop. ############################################################### set b1 [expr {$xPx - $vert3Xpx}] set b2 [expr {$yPx - $vert3Ypx}] set L1 [expr { (($b1 * $a22) - ($b2 * $a12)) / $D }] set L2 [expr { (($a11 * $b2) - ($a21 * $b1)) / $D }] set L3 [expr {1.0 - ($L1 + $L2)}] ## FOR TESTING: # puts "xPx: $xPx yPx: $yPx L1: $L1 L2: $L2 L3: $L3" if {$L1 < 0.0 || $L2 < 0.0 || $L3 < 0.0} { lappend onerowLISTcolors $COLORBKGDhex continue } ############################################################# ## The L1,L2,L3<0 check above will probably catch most cases ## of the point being outside the triangle. This check may ## catch other cases. ############################################################# if {$L1 > 1.0 || $L2 > 1.0 || $L3 > 1.0} { lappend onerowLISTcolors $COLORBKGDhex continue } ############################################################# ## At this point, (xPx,yPx) is inside the triangle. ## Compute the color-average for the pixel at xPx,yPx --- by ## averaging based on the barycentric coordinates of xPx,yPx. ############################################################# set Rbary [expr {int( ($L1 * $COLOR1r) + ($L2 * $COLOR2r) + ($L3 * $COLOR3r) )}] set Gbary [expr {int( ($L1 * $COLOR1g) + ($L2 * $COLOR2g) + ($L3 * $COLOR3g) )}] set Bbary [expr {int( ($L1 * $COLOR1b) + ($L2 * $COLOR2b) + ($L3 * $COLOR3b) )}] ############################################################## ## Now we need to 'shade' this color according to our ## 'color-shading-metric' : v = 1.0 - ( 3.0 * min(L1,L2,L3) ) ## ## where the Li are the barycentric coordinates of a point x,y ## in the triangle, and where u = 3.0 * min(L1,L2,L3) ## is between 1.0 and 0.0, and where u = 1.0 at the barycenter ## and u = 0.0 on the outer boundary of the triangle. ## ## Thus v = 0.0 at the barycenter and v = 1.0 on the outer ## boundary of the triangle --- as we want for our ## 'color-shading-metric'. ## ## We calculate v and v^N where N is the 'extensity' exponent. ## We use v^N and (1.0 - v^N) to weight the background (edge) ## color and the triangle color, respectively. ############################################################## set v [expr {1.0 - ( 3.0 * min($L1,$L2,$L3) ) } ] set Vpow [expr {pow($v,$N)}] set oneMinusVpow [expr {1.0 - $Vpow}] ## FOR TESTING: # if {$xPx == $xmidPx} { # puts "Vpow: $Vpow oneMinusVpow: $oneMinusVpow" # } set Rshaded [expr { int( ($oneMinusVpow * $Rbary) + ($Vpow * $COLORBKGDr) ) }] set Gshaded [expr { int( ($oneMinusVpow * $Gbary) + ($Vpow * $COLORBKGDg) ) }] set Bshaded [expr { int( ($oneMinusVpow * $Bbary) + ($Vpow * $COLORBKGDb) ) }] set hexcolor [format #%02X%02X%02X $Rshaded $Gshaded $Bshaded] ############################################################# ## Draw the color-shaded pixel at x,y. ############################################################# lappend onerowLISTcolors $hexcolor ## NOTE: ## As an alternative to appending a pixel-color to a row-of-image LIST, ## we could use a checkbutton variable on the GUI to signal that the user ## wants to 'put' a pixel and redisplay the image before ## building the color of the next pixel. } ## END OF the x-loop ################################################################## ## Append an entire row of hexcolors here to the list of ## all-color-rows. ################################################################## lappend allrowsLISTcolors $onerowLISTcolors ## NOTE: ## As an alternative to appending a row of colors to an all-of-image LIST, ## we could use a checkbutton variable on the GUI to signal that the user ## wants to 'put' a horizontal line of pixels and redisplay the image ## before building the next row. } ## END OF the y-loop ################################################################## ## Put the list-of-lists of row colors (the complete image) ## into the 'image structure'. ################################################################## imgID put $allrowsLISTcolors -to 0 0 ## Reset the cursor from a 'watch' cursor. # . config -cursor {} ######################################################### ## Change the title of the window to show execution time. ######################################################### advise_user \ "** DONE drawing. [expr [clock milliseconds]-$t0] milliseconds elapsed **" } ## END OF proc 'ReDraw' ##+##################################################################### ## proc 'advise_user' ##+##################################################################### ## PURPOSE: To display a text message to the user --- in some ## widget of the GUI, such as a 'label' widget. ## ## (Alternatively, we could display the message at the ## top of the window using a 'wm title .' window manager ## command. However, the user may not notice that message.) ## ## CALLED BY: the ReDraw proc ##+#################################################################### proc advise_user {text} { .fRmsg.labelINFO configure -text "$text" ## An alternative: (put the msg in the window title bar) # wm title . "$text" ## This 'update' is needed to make sure that this label update ## is displayed in a timely fashion. update } ## END OF proc 'advise_user' ##+##################################################################### ## proc 'show_user_hexcolorCodes' ##+##################################################################### ## PURPOSE: To display a text message to the user --- in some ## widget of the GUI, such as a 'label' widget. ## ## (Alternatively, we could display the message at the ## top of the window using a 'wm title .' window manager ## command. However, the user may not notice that message.) ## ## CALLED BY: the 'set_*_color*' procs below ##+#################################################################### proc show_user_hexcolorCodes {} { global COLOR1hex COLOR2hex COLOR3hex COLORBKGDhex .fRbuttons.labelCOLORS configure -text \ "Current colors for 3 vertices and background: $COLOR1hex $COLOR2hex $COLOR3hex $COLORBKGDhex" } ## END OF proc 'show_user_hexcolorCodes' ##+##################################################################### ## proc 'set_vertex_color1' ##+##################################################################### ## PURPOSE: ## ## This procedure is invoked to get an RGB triplet ## via 3 RGB slider bars on the FE Color Selector GUI. ## ## Uses that RGB value to set a 'fill' color. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCOLOR1 button ##+##################################################################### proc set_vertex_color1 {} { global COLOR1r COLOR1g COLOR1b COLOR1hex ColorSelectorScript ## FOR TESTING: # puts "COLOR1r: $COLOR1r" # puts "COLOR1g: $COLOR1g" # puts "COLOR1b: $COLOR1b" set TEMPrgb [ exec $ColorSelectorScript $COLOR1r $COLOR1g $COLOR1b] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB set COLOR1hex "#$hexRGB" set COLOR1r $r255 set COLOR1g $g255 set COLOR1b $b255 show_user_hexcolorCodes ## Update the colors on the color buttons. update_color_buttons ## Redraw the geometry in the new interior color. ReDraw 0 } ## END OF proc 'set_vertex_color1' ##+##################################################################### ## proc 'set_vertex_color2' ##+##################################################################### ## PURPOSE: ## ## This procedure is invoked to get an RGB triplet ## via 3 RGB slider bars on the FE Color Selector GUI. ## ## Uses that RGB value to set an 'edge' color. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCOLOR2 button ##+##################################################################### proc set_vertex_color2 {} { global COLOR2r COLOR2g COLOR2b COLOR2hex ColorSelectorScript ## FOR TESTING: # puts "COLOR2r: $COLOR2r" # puts "COLOR2g: $COLOR2g" # puts "COLOR2b: $COLOR2b" set TEMPrgb [ exec $ColorSelectorScript $COLOR2r $COLOR2g $COLOR2b] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB set COLOR2hex "#$hexRGB" set COLOR2r $r255 set COLOR2g $g255 set COLOR2b $b255 show_user_hexcolorCodes ## Update the colors on the color buttons. update_color_buttons ## Redraw the geometry in the new edge color. ReDraw 0 } ## END OF proc 'set_vertex_color2' ##+##################################################################### ## proc 'set_vertex_color3' ##+##################################################################### ## PURPOSE: ## ## This procedure is invoked to get an RGB triplet ## via 3 RGB slider bars on the FE Color Selector GUI. ## ## Uses that RGB value to set an 'edge' color. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCOLOR3 button ##+##################################################################### proc set_vertex_color3 {} { global COLOR3r COLOR3g COLOR3b COLOR3hex ColorSelectorScript ## FOR TESTING: # puts "COLOR3r: $COLOR3r" # puts "COLOR3g: $COLOR3g" # puts "COLOR3b: $COLOR3b" set TEMPrgb [ exec $ColorSelectorScript $COLOR3r $COLOR3g $COLOR3b] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB set COLOR3hex "#$hexRGB" set COLOR3r $r255 set COLOR3g $g255 set COLOR3b $b255 show_user_hexcolorCodes ## Update the colors on the color buttons. update_color_buttons ## Redraw the geometry in the new edge color. ReDraw 0 } ## END OF proc 'set_vertex_color3' ##+##################################################################### ## proc 'set_background_color' ##+##################################################################### ## PURPOSE: ## ## This procedure is invoked to get an RGB triplet ## via 3 RGB slider bars on the FE Color Selector GUI. ## ## Uses that RGB value to set the color of the canvas --- ## on which all the tagged items (lines) lie. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCOLORBKGD button ##+##################################################################### proc set_background_color {} { global COLORBKGDr COLORBKGDg COLORBKGDb COLORBKGDhex ColorSelectorScript ## FOR TESTING: # puts "COLORBKGDr: $COLORBKGDr" # puts "COLORBKGDg: $COLORBKGDb" # puts "COLORBKGDb: $COLORBKGDb" set TEMPrgb [ exec $ColorSelectorScript $COLORBKGDr $COLORBKGDg $COLORBKGDb] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB set COLORBKGDhex "#$hexRGB" set COLORBKGDr $r255 set COLORBKGDg $g255 set COLORBKGDb $b255 show_user_hexcolorCodes ## Update the colors on the color buttons. update_color_buttons ## Redraw the geometry in the new background color. ReDraw 0 } ## END OF proc 'set_background_color' ##+##################################################################### ## proc 'update_color_buttons' ##+##################################################################### ## PURPOSE: ## This procedure is invoked to update the colors and text on 4 set-color ## buttons, to show current colors (and perhaps hex values of those colors) ## on vertex1xolor, vertex2color, vertex3color, and background-color buttons. ## ## This proc sets the background color of each of those buttons ## to its current color --- and sets foreground color to a ## suitable black or white color, so that the label text is readable. ## ## Arguments: global color vars ## ## CALLED BY: 4 colors procs: ## 'set_vertex_color1' ## 'set_vertex_color2' ## 'set_vertex_color3' ## 'set_background_color' ## and the additional-GUI-initialization section at ## the bottom of this script. ##+##################################################################### proc update_color_buttons {} { global aRtext \ COLOR1r COLOR1g COLOR1b COLOR1hex \ COLOR2r COLOR2g COLOR2b COLOR2hex \ COLOR3r COLOR3g COLOR3b COLOR3hex \ COLORBKGDr COLORBKGDg COLORBKGDb COLORBKGDhex ## Set background color on the COLOR1 button, and ## put the background color in the text on the button, and ## set the foreground color of the button. .fRbuttons.buttCOLOR1 configure -bg $COLOR1hex .fRbuttons.buttCOLOR1 configure -text "$aRtext(buttonCOLOR1) $COLOR1hex" set sumCOLOR1 [expr {$COLOR1r + $COLOR1g + $COLOR1b}] if {$sumCOLOR1 > 300} { .fRbuttons.buttCOLOR1 configure -fg #000000 } else { .fRbuttons.buttCOLOR1 configure -fg #f0f0f0 } ## Set background color on the COLOR2 button, and ## put the background color in the text on the button, and ## set the foreground color of the button. .fRbuttons.buttCOLOR2 configure -bg $COLOR2hex .fRbuttons.buttCOLOR2 configure -text "$aRtext(buttonCOLOR2) $COLOR2hex" set sumCOLOR2 [expr {$COLOR2r + $COLOR2g + $COLOR2b}] if {$sumCOLOR2 > 300} { .fRbuttons.buttCOLOR2 configure -fg #000000 } else { .fRbuttons.buttCOLOR2 configure -fg #f0f0f0 } ## Set background color on the COLOR3 button, and ## put the background color in the text on the button, and ## set the foreground color of the button. .fRbuttons.buttCOLOR3 configure -bg $COLOR3hex .fRbuttons.buttCOLOR3 configure -text "$aRtext(buttonCOLOR3) $COLOR3hex" set sumCOLOR3 [expr {$COLOR3r + $COLOR3g + $COLOR3b}] if {$sumCOLOR3 > 300} { .fRbuttons.buttCOLOR3 configure -fg #000000 } else { .fRbuttons.buttCOLOR3 configure -fg #f0f0f0 } ## Set background color on the COLORBKGD button, and ## put the background color in the text on the button, and ## set the foreground color of the button. .fRbuttons.buttCOLORBKGD configure -bg $COLORBKGDhex .fRbuttons.buttCOLORBKGD configure -text "$aRtext(buttonCOLORBKGD) $COLORBKGDhex" set sumCOLORBKGD [expr {$COLORBKGDr + $COLORBKGDg + $COLORBKGDb}] if {$sumCOLORBKGD > 300} { .fRbuttons.buttCOLORBKGD configure -fg #000000 } else { .fRbuttons.buttCOLORBKGD configure -fg #f0f0f0 } } ## END OF proc 'update_color_buttons' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 wm geometry $toplevName +100+50 wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+######################## ## END of PROC definitions. ##+######################## ## Set HELPtext variable. ##+######################## set HELPtext "\ *** HELP for this utility to *** DRAW a 3-COLOR-GRADIENT Isosceles TRIANGLE *** --- with 3D-like, Shaded Edges This Tk GUI script draws a color-filled 'isosceles triangle' --- with shading around the three edges of the triangle. The pixel colors in the triangle are based on 3 user-selected colors assigned to the 3 vertices of the triangle --- and the 'fill' color at any pixel inside the triangle is an average of the 3 colors using the barycentric coordinates of the point (pixel) to compute the average. For example, if (L1,L2,L3) are the barycentric coordinates of a pixel, where L1 + L2 + L3 = 1, we use the RGB colors of the 3 vertices to calculate the RGB color at the pixel, as follows: Let the RGB values of vertex 1, 2, and 3 be (R1,G1,B1) and (R2,G2,B2) and (R3,G3,B3). Then Rpixel = (L1 * R1) + (L2 * R2) + (L3 * R3) Gpixel = (L1 * G1) + (L2 * G2) + (L3 * G3) Bpixel = (L1 * B1) + (L2 * B2) + (L3 * B3) ********************************************** EXAMPLES OF USE of this triangle-shaped image: This 3D-like triangle could be used as 1) an icon or logo background. Nice quality text could be added on top of the triangle. 2) an unusual, triangle-shaped 'bullet' for line items on a web page or for menu items in a Tk GUI 'toolchest' --- if the image is shrunk to a small size. ******************************** RESIZE and REDRAW considerations: The user can resize the (isosceles) triangle on the canvas by using a couple of widgets to set image width and height (in pixels). When both these values are set as desired, the user can use the 'ReDraw' button to draw the image at the newly requested size. A redraw is done automatically (at button1-release) whenever (a) a color button is used to change a vertex or background color, (b) the slider-button of the 'edge-shading-exponent' (N) scale is reset, (c) the slider-button of the 'margin-fraction' scale is reset. A redraw includes clearing the image and redrawing the triangle shape on a solid color background. In the current implementation, the redraw of a large image (greater than 1000x1000 pixels) may take 10 seconds or more --- on a small image (less than 400x400), less than 1 second. If the automatic redraw in case (b) or (c) is annoying, you can comment out the 'bind' command in this script and use the 'ReDraw' button. **************************** CONTROLLING THE EDGE-SHADING: (a scalar 'color-shading-metric') In several similar scripts that do nice 'edge-shading' of various shapes, namely - \"GUI for Drawing 'Super-ellipses', with nice shaded edges\" at http://wiki.tcl.tk/37004 - \"GUI for Drawing Rectangular 'Buttons' with nice shaded edges\" at http://wiki.tcl.tk/37143 - \"GUI for Drawing 'Super-formula' shapes, with nice shaded border\" at http://wiki.tcl.tk/37156 - \"GUI for Drawing 'Donut' shapes, with nice shaded border\" at http://wiki.tcl.tk/37214 I devised a scalar 'color-shading-metric' --- 'v' --- at each pixel point (x,y) that is within the rectangle/super-ellipse/super-formula/donut shape --- where v is between 0 and 1. And the value of v goes to 1.0 at the edges of these shapes --- and is 0.0 in the middle of the shape. Then v and (1-v) are applied to a user-selected background color and a user-determined 'fill' color for any pixel within the shape --- to get a 'weighted-average' of the user-selected colors, for the color at a given pixel x,y. For this triangle, we use the barycentric coordinates of any pixel within the triangle --- to formulate our metric. For a given pixel x,y, let us say its barycentric coordinates are (L1,L2,L3) where L1 + L2 + L3 = 1. Note that at the edges (and vertices) of the triangle, at least one of the 3 barycentric coordinates is 0. And note that we want our metric, v(x,y) = v(L1,L2,L3), to be 1.0 at the edges of the triangle. Also, we want v to be 0.0 at the 'barycenter' of the triangle. (Having v be 1.0 at the outer border of the shape allows us to give a 'crisp' shading at the edges by using an 'extensity' exponent to set the extent-and-intensity of the shading at the edges.) Note that the 'barymetric center' of the triangle is at the point/pixel where (L1,L2,L3) = (1/3,1/3,1/3). And when one looks at any point within the triangle which is not on that center, at least one of the coordinates is less than 1/3. Note that the quantity u = 3.0 * min(L1,L2,L3) is 1.0 at the barycenter and is zero on the edges of the triangle. We want the opposite for our scalar 'color-shading-metric'. So for our 'color-shading-metric', we will use v(x,y) = v(L1,L2,L3) = 1.0 - ( 3.0 * min(L1,L2,L3) ) Note that v is 1.0 on the edges (and vertices) of the triangle, it is 0.0 at the barymetric center, and it is between 0 and 1 at other points in the triangle. So we have a suitable 'color-shading-metric', v. ******************** SETTING PIXEL COLORS inside the triangle: The 'shaded color' at x,y is determined by calulating a weighted average based on applying the factor v to 'color-bkgd' --- and by applying (1 - v) to 'color-bary', the 'fill' color of the pixel. That is, shaded-color = v * color-bkgd + (1 - v) * color-bary. Actually there are 3 calculations: Rshaded = v * Rbkgd + (1 - v) * Rbary Gshaded = v * Gbkgd + (1 - v) * Gbary Bshaded = v * Bbkgd + (1 - v) * Bbary Thus we will get the edge-shading (the 3D effect) for the 'triangle shape'. But, it turns out that v and 1-v give a rather washed-out (too gradual) shading effect. It is better if we raise v to a power N and use v^N and (1 - v^N), where N can be taken to be an integer greater than or equal to 1. For example, we could use N = 6. In fact, N in the range of 6 to 10 gives a nice 'crisp' edge on this 3-color triangle. So a scale widget is available on the GUI for adjusting the N exponent to change the 'extensity' (extent-and-intensity) of the 'shading-to-background-color' over the triangle --- and especially the shading at the edges of triangle. ********************************** FINE CONTROL OF THE SLIDER BUTTONS: Most people know that you can drag the slider of the 'scale' widget by clicking on the 'slider button' with mouse-button1 and dragging the slider button. This is a rather coarse way of moving the slider button. It is not so obvious that the Tk scale widget also allows you to move the 'slider button' by clicking in the 'trough' on EITHER SIDE of the slider button. By repeated clicking in the trough, the slider can be advanced one scale resolution-unit per click. Furthermore, one can RAPIDLY move the slider button ONE RESOLUTION UNIT per click by clicking in the trough and HOLDING down the mouse button. The slider moves one resolution unit at a time UNTIL the mouse button is RELEASED. ***************************** CAPTURING THE GENERATED IMAGE: A screen/window capture utility (like 'gnome-screenshot' on Linux) can be used to capture the GUI image in a PNG file, say. If necessary, an image editor (like 'mtpaint' on Linux) can be used to crop the window capture image. The image could also be down-sized --- say to make a 'bullet' image file or an icon-background image file. The image could also be brightened by using the 'gamma correction' feature of an image editor like 'mtpaint'. The colored image file could be used with a utility (like the ImageMagick 'convert' command) to change the background color to TRANSPARENT, making a partially transparent GIF (or PNG) file. Then the semi-transparent image file could be used, for 'bullets' in HTML pages or in Tk GUI's --- or for icons on desktops --- or for the background of icons or buttons in (Tk) GUIs or 'toolchests'. " ##+##################################################### ##+##################################################### ## ADDITIONAL GUI INITIALIZATION SECTION: ##+##################################################### ##+##################################################### ##+###################################################### ## Set initial 'shading-exponent' scale widget variable ## --- the 'extensity' exponent. ##+###################################################### # set N 6 set N 10 ##+###################################################### ## Set initial margin-fraction scale widget variable. ##+###################################################### set marginFRACTION 0.1 ##+############################################################# ## Set the initial color for the three triangle vertices ## and the initial background color (outside the triangle-shape). ##+############################################################# ## Initialize the triangle vertex1 color. # set COLOR1r 255 # set COLOR1g 0 # set COLOR1b 0 set COLOR1r 255 set COLOR1g 255 set COLOR1b 0 set COLOR1hex [format "#%02X%02X%02X" $COLOR1r $COLOR1g $COLOR1b] ## Initialize the triangle vertex2 color. # set COLOR2r 0 # set COLOR2g 255 # set COLOR2b 0 set COLOR2r 255 set COLOR2g 0 set COLOR2b 255 set COLOR2hex [format "#%02X%02X%02X" $COLOR2r $COLOR2g $COLOR2b] ## Initialize the triangle vertex3 color. # set COLOR3r 0 # set COLOR3g 0 # set COLOR3b 255 set COLOR3r 0 set COLOR3g 255 set COLOR3b 255 set COLOR3hex [format "#%02X%02X%02X" $COLOR3r $COLOR3g $COLOR3b] ## Initialize the background color for the canvas. # set COLORBKGDr 60 # set COLORBKGDg 60 # set COLORBKGDb 60 set COLORBKGDr 0 set COLORBKGDg 0 set COLORBKGDb 0 set COLORBKGDhex \ [format "#%02X%02X%02X" $COLORBKGDr $COLORBKGDg $COLORBKGDb] ##+####################################################### ## Set the colors and text in the color buttons, based on ## the initial setting for the colors. ##+####################################################### update_color_buttons ##+###################################################### ## Set initial values for the image widht & height ## scale widget variables. ##+###################################################### set XmaxPx 500 set YmaxPx 400 ##+################################################### ## Initialize the canvas with 'ReDraw'. ##+################################################## ReDraw 0 ##+##################################################### ## Set the full-name of the RGB color-selector Tk script ## that is used in several procs above. ##+##################################################### ## FOR TESTING: # puts "argv0: $argv0" set DIRthisScript "[file dirname $argv0]" ## For ease of testing in a Linux/Unix terminal and located at the ## directory containing this Tk script. Set the full directory name. if {"$DIRthisScript" == "."} { set DIRthisScript "[pwd]" } set DIRupOne "[file dirname "$DIRthisScript"]" set DIRupTwo "[file dirname "$DIRupOne"]" set ColorSelectorScript "$DIRupTwo/SELECTORtools/tkRGBselector/sho_colorvals_via_sliders3rgb.tk" ## Alternatively: Put the RGB color-selector Tk script in the ## same directory as this Tk script and uncomment the following. # set ColorSelectorScript "$DIRthisScript/sho_colorvals_via_sliders3rgb.tk"