3.e3.source-code.DrawContextP5.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of p5_2.13 Show documentation
Show all versions of p5_2.13 Show documentation
draw drx types in the processing.org environment
The newest version!
/*
Copyright 2010 Aaron J. Radke
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cc.drx.p5
import cc.drx._
import processing.core._
import processing.core.PConstants._
// import processing.core.PApplet._
// import P5._
//TODO implement the core interface to draw the included draw implicits that have been used for a long time
class DrawContextP5(val g:PGraphics) extends DrawContext{
import Style._
override def !(p:Default.type):Unit = {
//g.background(White)
super.!(p)
//--canvas/context
g.rectMode(CORNERS) //draw rect from NW to SE
g.ellipseMode(CENTER) //specify an ellipse by x, y radius ??
g.noStroke
g.noFill
}
//--query
def size:Vec = Vec(g.width, g.height)
def stroke:Option[Color] = ???
def fill:Option[Color] = ???
def weight:Double = ???
//--required properties `p`
// note this argument based dispatching is applied at compile time and does not need runtime pattern matching
//---coloring
def !(p:Background):Unit = g.background(p.c)
def !(p:Fill):Unit = g.fill(p.c)
def !(p:Stroke):Unit = g.stroke(p.c)
def !(p:FillNone.type):Unit = g.noFill
def !(p:StrokeNone.type):Unit = g.noStroke
def !(p:Weight):Unit = g.strokeWeight(p.value)
def !(p:Font):Unit = g.textFont(pFont(p), p.size)
//--cache to auto load and keep resources, this removes the initialization requirement and implementation details to the surface drawn context
def textSize(text:Text,font:Font):Vec = Vec(textWidth(font,text.value), font.size) //FIXME properly set the y size
/**compute the width of represented string*/
def textWidth(f:Font,str:String):Double = {
val p = pFont(f) //store to prevent re-calling the def
str.foldLeft(0d){case (a,c) => a + p.width(c)}*f.size
}
def pFont(font:Font) = fontCache(font)
override def save(file:File):Try[File] = Try{g save file.path; file} //TODO thow an error if the file could not be saved...
private val fontCache:Cache[Style.Font,PFont] = Cache{font:Style.Font =>
import java.awt.{Font => JFont}
def mkFont(in: => Input) = Try{JFont.createFont(JFont.TRUETYPE_FONT, in.is).deriveFont(JFont.PLAIN,font.size)}
val jFont = mkFont(File(font.name).in) orElse
mkFont(Input.resource(File(font.name))) getOrElse //get is wrapped in the try for the failure to get
new JFont(font.name, JFont.PLAIN, font.size.round.toInt)
new PFont(jFont, true) //use smoothing by default
}
private val svgCache = Cache{xml:String =>
new PShapeSVG(processing.data.XML.parse(xml))
}
private val imgCache = Cache{f:File =>
val awtImg = Img.loadAwt(f) getOrElse new javax.swing.ImageIcon(Array.empty[Byte]).getImage
val pImg = new PImage(awtImg)
pImg.format = ARGB
pImg
}
def emptyCache() = { //TODO or use the word clear
fontCache.empty
svgCache.empty
imgCache.empty
}
//--Alignment
def !(p:Align):Unit = g.textAlign(
p.horz match { case Left => LEFT case Center => CENTER case Right => RIGHT },
p.vert match { case Top => TOP case Midline => CENTER case Bottom => BOTTOM }
)
//--transform (use affine matrix instead?)
def !(p:Translate):Unit = g.translate(p.t.x,p.t.y)
def !(p:ScaleProperty):Unit = g.scale(p.t.x,p.t.y)
def !(p:Rotate):Unit = g.rotate(p.r.rad)
//-- shapes `s`
def !(p:Path):Unit = {
val head:Vec = p.vertices.head.last
val rest:Iterable[Vertex] = p.vertices.tail
g.beginShape()
rest.foreach{ //TODO it would be nice if these didn't require pattern match but to make something working (run with it for now and optimize/generalize later)
case Vec(x,y,_) => g.vertex(x,y)
case BezierVertex(ca,cb,b) => g.bezierVertex(ca.x,ca.y, cb.x,cb.y, b.x,b.y)
}
if(p.isClosed) g.endShape(CLOSE) else g.endShape
}
def !(s:Circ):Unit = g.ellipse(s.c.x , s.c.y , s.r*2 , s.r*2)
def !(s:Line):Unit = g.line(s.a.x,s.a.y, s.b.x,s.b.y)
def !(s:Rect):Unit = g.rect(s.a.x , s.a.y , s.b.x , s.b.y) //assuming rectMode(CORNERS)
def !(s:Text):Unit = g.text(s.value , s.pos.x , s.pos.y)
private def shape(f: => Unit):Unit = {g.beginShape(); f; g.endShape(CLOSE)}
def !(s:Poly):Unit = shape{s.vertices.foreach{v => g.vertex(v.x, v.y)}}
def !(tri:Tri):Unit = shape{
g.vertex(tri.a.x, tri.a.y)
g.vertex(tri.b.x, tri.b.y)
g.vertex(tri.c.x, tri.c.y)
}
def style(f: =>Unit):Unit = {g.pushStyle; f; g.popStyle}
def matrix(f: =>Unit):Unit = {g.pushMatrix; f; g.popMatrix}
def !(a:Arc):Unit = style{
g.noFill
g.strokeWeight(a.w)
g.strokeCap(SQUARE)
val w = a.r*2
//g.ellipseMode(is set to CENTER as default which means RADIUS ???)
g.arc(a.c.x,a.c.y, w,w, a.angle.min.rad, a.angle.max.rad, OPEN)
}
def !(e:Ellipse):Unit = {
if(e.rotation == Angle(0))
g.ellipse(e.c.x,e.c.y, e.r.x*2,e.r.y*2)
else matrix{
g.translate(e.c.x, e.c.y)
g.rotate(e.rotation.rad)
g.ellipse(0,0, e.r.x*2,e.r.y*2)
}
}
private def rawImageOf(img:Img):PImage = img match {
case ImgFile(file, _) => imgCache(file)
case _ => ??? //TODO Img wrapped Pimage
}
def !(img:Img):Unit = {
val p:PImage = rawImageOf(img)
val box = Rect(p.width,p.height) fitIn img.box //fit the picture size including aspect ratio into the drawing box //TODO check if rotations can also work here...
g.image(p, box.a.x, box.a.y, box.width, box.height)
}
def !(svg:Svg):Unit = g.shape(svgCache(svg.xml))
def !(video:Video):Unit = ???
def !(html:Html):Unit = ???
def remote(video:Video):MediaRemote = ???
// def !(arrow:Arrow):Unit = ???
def !(star:Star):Unit = shape{for(v <- star.vertices) g.vertex(v.x, v.y)}
override def !(z:Bezier):Unit = g.bezier(z.a.x, z.a.y, z.ca.x, z.ca.y, z.cb.x, z.cb.y, z.b.x,z.b.y) //general bezier
def close():Unit = {} //TODO close some elements
}