eumandy/eugtk/examples/test60.ex
2016-11-25 00:33:18 -07:00

599 lines
16 KiB
Elixir

------------------------------------------------------------------------
--# Drawing with Cairo
-- At first glance, this looks horribly complicated, but
-- each of the 15 drawing shapes only require 10 to 20 lines
-- of code. Cut and paste the one(s) you need.
------------------------------------------------------------------------
include GtkEngine.e
include GtkCairo.e
include std/math.e
constant docs = `<b><u>Drawing with Cairo</u></b>
Original code for these objects was created by Øyvind Kolås, and put in the public domain.
`
constant win = create(GtkWindow,
"icon=applications-graphics,position=1,size=900x600,border=10,sig.destroy=Quit")
constant panel = create(GtkBox,VERTICAL)
add(win,panel)
constant lbl = create(GtkLabel)
set(lbl,"markup",docs)
add(panel,lbl)
constant hr = create(GtkSeparator)
add(panel,hr)
constant screen = create(GtkDrawingArea,
"background=white,size request=900x500")
constant box = create(GtkBox,VERTICAL)
add(box,screen)
add(panel,box)
object btn = {
create(GtkButton,"Paint","Paint"),
create(GtkButton,"Arc","Arc"),
create(GtkButton,"Arc neg","ArcNeg"),
create(GtkButton,"Clip","Clip"),
create(GtkButton,"Image","ClipImg"),
create(GtkButton,"Round Rect","RoundedRect"),
create(GtkButton,"LineCap","LineCap"),
create(GtkButton,"Curve to","CurveTo"),
create(GtkButton,"Pattern","ImagePattern"),
create(GtkButton,"Fill and Stroke","FillandStroke"),
create(GtkButton,"Fill Style","FillStyle"),
create(GtkButton,"Gradient","Gradient"),
create(GtkButton,"Line Join","LineJoin"),
create(GtkButton,"Hello","Hello"),
create(GtkButton,"G'Day","GoodDay"),
create(GtkButton,"gtk-save","Save"),
create(GtkButton,"gtk-clear","Clear"),
create(GtkButton,"gtk-quit","Quit")
}
set(btn[16],"tooltip text","Click to save the image in your home directory")
ifdef WINDOWS then
set(btn[16],"tooltip text","Doesn't work on Windows")
set(btn[16],"sensitive",FALSE)
end ifdef
constant
btnbox1 = create(GtkButtonBox,"layout=5"), -- 5 = GTK_BUTTONBOX_CENTER
btnbox2 = create(GtkButtonBox,"layout=5"),
btnbox3 = create(GtkButtonBox,"layout=5")
add(btnbox1,btn[1..7])
add(btnbox2,btn[8..13])
add(btnbox3,btn[14..18])
constant sep = create(GtkSeparator,"margin bottom=5")
pack(panel,{sep,-btnbox3,-btnbox2,-btnbox1})
show_all(win)
main()
------------------------------------------------------------------------
global function Clear()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"source rgba",255,255,255,255},
{"operator",CAIRO_OPERATOR_SOURCE},
{"paint"}})
return 1
end function
------------------------------------------------------------------------
global function Save() -- convert current drawing to image file
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
atom surf = get(cr,"target")
ifdef WINDOWS then
Error(win,"Sorry",
"Cannot write png files on Windows",
"Don't know why.",GTK_BUTTONS_OK)
end ifdef
get(surf,"write to png","image_from_test60.png")
return 1
end function
------------------------------------------------------------------------
global function Paint(atom ctl, atom event, atom data)
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window")) -- DRAWING CONTEXT
atom pat = create(CairoLinearGradient,100,200,200,100) -- FILL PATTERN
set(pat,{
{"add color stop rgba",0, 0,0,0,1},
{"add color stop rgba",1, 1,0,0,1}})
atom surf = get(cr,"target")
set(cr,{
-- TEXT
{"translate",160,-80},
{"source rgb",#FF,0,0},
{"move to",200,200},
{"show text","Hello World!"},
-- SHAPE
{"move to",100,200},
{"curve to",100,100,100,100,200,100},
{"curve to",200,200,200,200,100,200},
{"close path"},
{"save"}})
-- FILL SHAPE WITH PATTERN
set(cr,{
{"source",pat},
{"fill preserve"}})
-- DRAW BORDER AROUND PATTERN
set(cr,{
{"source rgb",0,0,0},
{"line width",3},
{"stroke"}})
-- CLEAN UP
set(cr,"destroy")
set(pat,"destroy")
return -1
end function
------------------------------------------------------------------------
global function Arc()
------------------------------------------------------------------------
atom xc = 128.0
atom yc = 128.0
atom radius = 100.0
-- angles are specified in radians
atom angle1 = 45.0 * DEGREES_TO_RADIANS
atom angle2 = 180.0 * DEGREES_TO_RADIANS
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"line width",10.0},
{"translate",20,40},
{"arc", xc, yc, radius, angle1, angle2},
{"stroke"},
-- draw helping lines
{"source rgba", 1, 0.2, 0.2, 0.6},
{"line_width",6.0},
{"arc",xc, yc, 10.0, 0, math:TWOPI},
{"fill"},
{"arc",xc, yc, radius, angle1, angle1},
{"line to", xc, yc},
{"arc", xc, yc, radius, angle2, angle2},
{"line to", xc, yc},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function ArcNeg(atom ctl)
------------------------------------------------------------------------
atom xc = 128.0
atom yc = 128.0
atom radius = 80.0
-- angles are specified in radians
atom angle1 = 45.0 * DEGREES_TO_RADIANS
atom angle2 = 180.0 * DEGREES_TO_RADIANS
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",1,-30},
{"line width",10.0},
{"arc negative", xc, yc, radius, angle1, angle2},
{"stroke"},
-- draw helping lines
{"source rgba", 1, 0.2, 0.2, 0.6},
{"line_width",6.0},
{"arc",xc, yc, 10.0, 0, math:TWOPI},
{"fill"},
{"arc",xc, yc, radius, angle1, angle1},
{"line to", xc, yc},
{"arc", xc, yc, radius, angle2, angle2},
{"line to", xc, yc},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function Clip()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",180,100},
{"arc", 128.0, 128.0, 76.8, 0, math:TWOPI}, -- full circle
{"clip"},
{"new path"}, -- current path is not consumed by cairo_clip()
{"rectangle", 0, 0, 256, 256},
{"fill"},
{"color",#00FF00}, -- bright green
{"move to", 0, 0},
{"line to", 256, 256},
{"move to", 256, 0},
{"line to", 0, 256},
{"line width", 10.0},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function ClipImg()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
atom surf = get(cr,"target")
atom image = create(CairoImageSurface,"thumbnails/MorningRain.png")
integer w = get(image,"width"), h = get(image,"height")
-- clip image to a circle;
set(cr,{
{"translate",350,100},
{"arc", 128.0, 128.0, 76.8, 0, math:TWOPI},
{"clip"},
{"new path"}, -- path not consumed by clip()
{"scale", 256/w, 256/h},
{"source surface", image, 0, 0},
{"paint"},
{"paint"}, -- ? don't know why
{"destroy"}})
return 1
end function
------------------------------------------------------------------------
global function RoundedRect()
------------------------------------------------------------------------
atom x = 25.6, -- rectangle
y = 25.6,
width = 204.8,
height = 204.8,
aspect = 1.0, -- aspect ratio
corner_radius = height / 5.0 -- corner curvature radius
atom radius = corner_radius / aspect
atom degrees = math:PI / 180.0
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",420,-10},
{"new sub path"},
{"arc", x+width-radius, y+radius, radius, -90*degrees, 0*degrees},
{"arc", x+width-radius, y+height-radius, radius, 0*degrees, 90*degrees},
{"arc", x+radius, y+height-radius, radius, 90*degrees, 180*degrees},
{"arc", x+radius, y+radius, radius, 180*degrees, 270*degrees},
{"close path"},
{"source rgb", 0.5, 0.5, 1},
{"fill preserve"},
{"source rgba",0.5, 0, 0, 0.5},
{"line width", 10.0},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function LineCap()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",410,-10},
{"line width",30.0},
{"line cap", CAIRO_LINE_CAP_BUTT},
{"move to", 64.0, 50.0},
{"line to", 64.0, 200.0},
{"stroke"},
{"line cap", CAIRO_LINE_CAP_ROUND},
{"move to", 128.0, 50.0},
{"line to", 128.0, 200.0},
{"stroke"},
{"line cap", CAIRO_LINE_CAP_SQUARE},
{"move to", 192.0, 50.0},
{"line to", 192.0, 200.0},
{"stroke"},
-- draw helping lines
{"source rgb", 1, 0.2, 0.2},
{"line width", 2.56},
{"move to", 64.0, 50.0},
{"line to", 64.0, 200.0},
{"move to", 128.0, 50.0},
{"line to", 128.0, 200.0},
{"move to", 192.0, 50.0},
{"line to", 192.0, 200.0},
{"stroke"},
{"destroy"}})
--NOTES:
--CAIRO_LINE_CAP_BUTT
--start(stop) the line exactly at the start(end) point
--CAIRO_LINE_CAP_ROUND
--use a round ending, the center of the circle is the end point
--CAIRO_LINE_CAP_SQUARE
--use squared ending, the center of the square is the end point
return 1
end function
------------------------------------------------------------------------
global function CurveTo()
------------------------------------------------------------------------
atom x = 25.6, y = 128.0,
x1 = 102.4, y1 = 230.4,
x2 = 153.6, y2 = 25.6,
x3 = 230.4, y3 = 128.0
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",20,260},
{"move to",x,y},
{"curve to",x1,y1,x2,y2,x3,y3},
{"line width",10.0},
{"stroke"},
{"source rgba",1,0.2,0.2,0.6},
{"line width",6.0},
{"move to",x,y},
{"line to",x1,y1},
{"move to",x2,y2},
{"line to",x3,y3},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function FillandStroke()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
-- create path for odd shape;
set(cr,{
{"translate",250,240},
{"move to",128,25.6},
{"line to",230.4,230.4},
{"rel line to",-102.4,0},
{"curve to",51.2,230.4,51.2,128,128,128},
{"close path"},
-- create path for rectangle;
{"move to",64,25.6},
{"rel line to",51.2,51.2},
{"rel line to",-51.2,51.2},
{"rel line to",-51.2,-51.2},
{"close path"},
-- fill color;
{"color","yellow"},
{"fill preserve"}, --save paths for next step;
-- draw outlines with broad brush;
{"line width",10},
{"color","blue"},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function FillStyle()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
-- draw a little 'cart' with wheels;
set(cr,{
{"translate",500,260},
{"line width",6},
{"rectangle",12,12,232,70},
{"new sub path"},
{"arc",64,64,40,0,math:TWOPI},
{"new sub path"},
{"arc negative",192,64,40,0,-math:TWOPI},
-- fill areas;
{"fill rule",CAIRO_FILL_RULE_EVEN_ODD},
{"color","green"},
{"fill preserve"},
{"source rgb",0,0,0},
{"stroke"},
-- draw another 'cart';
{"translate",0,128},
{"rectangle",12,12,232,70},
{"new sub path"},
{"arc",64,64,40,0,2*math:PI},
{"new sub path"},
{"arc negative",192,64,40,0,-math:TWOPI},
-- fill with a different algorithm;
{"fill rule",CAIRO_FILL_RULE_WINDING},
{"color","blue"},
{"fill preserve"},
{"source rgb",0,0,0},
{"stroke"}})
set(cr,"destroy")
--CAIRO_FILL_RULE_WINDING
--If the path crosses the ray from left-to-right, counts +1.
--If the path crosses the ray from right to left, counts -1.
--(Left and right are determined from the perspective of looking
--along the ray from the starting point.)
--If the total count is non-zero, the point will be filled.
--CAIRO_FILL_RULE_EVEN_ODD
--Counts the total number of intersections, without regard to the
--orientation of the contour. If the total number of intersections
--is odd, the point will be filled.
return 1
end function
------------------------------------------------------------------------
global function Gradient()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,"translate",650,-25)
-- background;
object bg = create(CairoLinearGradient,0,0,0,256)
set(bg,{ -- vertical shade light to dark green;
{"add color stop rgba",1,0,2,0,1},
{"add color stop rgba",0,1,1,1,1}})
set(cr,{ -- rectangle used as bkgnd;
{"rectangle",0,0,256,256},
{"source",bg},
{"fill"}})
set(bg,"destroy")
-- foreground;
object fg = create(CairoRadialGradient,115,102,25,102,102,128)
set(fg,{ -- 'ball' effect, circle with radial gradient 'highlight';
{"add color stop rgba",0,1,1,1,1},
{"add color stop rgba",1,0,0,0,1}})
set(cr,{
{"source",fg},
{"arc",128,128,76.8,0,math:TWOPI}, -- 2PI = full circle;
{"fill"}})
set(fg,"destroy")
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function ImagePattern() -- use an image as a repeating pattern
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
atom img = create(CairoImageSurface,"thumbnails/clown.png")
integer w = get(img,"width")
integer h = get(img,"height")
atom patt = create(CairoPattern,img)
set(patt,"extend",CAIRO_EXTEND_REPEAT)
set(cr,{
{"translate",170,240},
{"rotate",math:QUARTPI}, -- 45 degrees clockwise;
{"scale",1 / math:SQRT2, 1 / math:SQRT2},
{"translate",-128,-128},
{"source",patt},
{"rectangle",0,0,256,256},
{"fill"}})
set(cr,"destroy")
set(patt,"destroy")
return 1
end function
--------------------------------------------------------------------------------
global function LineJoin() -- corner appearance when two lines join at an angle
--------------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"translate",690,250},
{"line width",20.96},
{"move to",76.8,84.40},
{"rel line to",51.2,-51.2},
{"rel line to",51.2,51.2},
{"line join",CAIRO_LINE_JOIN_MITER},
{"color","red"},
{"stroke"},
{"move to",76.8,161.28},
{"rel line to",51.2,-51.2},
{"rel line to",51.2,51.2},
{"line join",CAIRO_LINE_JOIN_BEVEL},
{"color","green"},
{"stroke"},
{"move to",76.8,238.08},
{"rel line to",51.2,-51.2},
{"rel line to",51.2,51.2},
{"line join",CAIRO_LINE_JOIN_ROUND},
{"color","blue"},
{"stroke"}})
set(cr,"destroy")
return 1
end function
------------------------------------------------------------------------
global function Hello()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"select font face", "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD},
{"font size",rand(36+8)},
{"source rgb", rand(100)/100, rand(100)/100, rand(100)/100},
{"move to",rand(600), rand(500)},
{"show text","Hello, world"},
{"destroy"}})
return 1
end function
------------------------------------------------------------------------
global function GoodDay()
------------------------------------------------------------------------
atom cr = create(GdkCairo_t,get(screen,"window"))
set(cr,{
{"select font face","Purisa",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD},
{"font size",rand(36+8)},
{"source rgb",rand(100)/100, rand(100)/100, rand(100)/100},
{"move to",rand(600),rand(500)},
{"show text","G'Day, Mate!"},
{"destroy"}})
return 1
end function