-- primitives for editing drawings Drawing = {} geom = require 'geom' -- All drawings span 100% of some conceptual 'page width' and divide it up -- into 256 parts. function Drawing.draw(line) local pmx,pmy = love.mouse.getX(), love.mouse.getY() if pmx < 16+Line_width and pmy > line.y and pmy < line.y+Drawing.pixels(line.h) then love.graphics.setColor(0.75,0.75,0.75) love.graphics.rectangle('line', 16,line.y, Line_width,Drawing.pixels(line.h)) if icon[Current_drawing_mode] then icon[Current_drawing_mode](16+Line_width-20, line.y+4) else icon[Previous_drawing_mode](16+Line_width-20, line.y+4) end if love.mouse.isDown('1') and love.keyboard.isDown('h') then draw_help_with_mouse_pressed(line) return end end if line.show_help then draw_help_without_mouse_pressed(line) return end local mx,my = Drawing.coord(pmx-16), Drawing.coord(pmy-line.y) for _,shape in ipairs(line.shapes) do assert(shape) if geom.on_shape(mx,my, line, shape) then love.graphics.setColor(1,0,0) else love.graphics.setColor(0,0,0) end Drawing.draw_shape(16,line.y, line, shape) end for i,p in ipairs(line.points) do if p.deleted == nil then if Drawing.near(p, mx,my) then love.graphics.setColor(1,0,0) love.graphics.circle('line', Drawing.pixels(p.x)+16,Drawing.pixels(p.y)+line.y, 4) else love.graphics.setColor(0,0,0) love.graphics.circle('fill', Drawing.pixels(p.x)+16,Drawing.pixels(p.y)+line.y, 2) end if p.name then -- todo: clip local x,y = Drawing.pixels(p.x)+16+5, Drawing.pixels(p.y)+line.y+5 love.graphics.print(p.name, x,y, 0, Zoom) if Current_drawing_mode == 'name' and i == line.pending.target_point then -- create a faint red box for the name love.graphics.setColor(1,0,0,0.1) local name_text -- TODO: avoid computing name width on every repaint if p.name == '' then name_text = love.graphics.newText(love.graphics.getFont(), 'm') -- 1em else name_text = love.graphics.newText(love.graphics.getFont(), p.name) end love.graphics.rectangle('fill', x,y, math.floor(name_text:getWidth()*Zoom), math.floor(15*Zoom)) end end end end love.graphics.setColor(0.75,0.75,0.75) Drawing.draw_pending_shape(16,line.y, line) end function Drawing.draw_shape(left,top, drawing, shape) if shape.mode == 'freehand' then local prev = nil for _,point in ipairs(shape.points) do if prev then love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(point.x)+left,Drawing.pixels(point.y)+top) end prev = point end elseif shape.mode == 'line' or shape.mode == 'manhattan' then local p1 = drawing.points[shape.p1] local p2 = drawing.points[shape.p2] love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(p2.x)+left,Drawing.pixels(p2.y)+top) elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then local prev = nil for _,point in ipairs(shape.vertices) do local curr = drawing.points[point] if prev then love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top) end prev = curr end -- close the loop local curr = drawing.points[shape.vertices[1]] love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top) elseif shape.mode == 'circle' then -- todo: clip local center = drawing.points[shape.center] love.graphics.circle('line', Drawing.pixels(center.x)+left,Drawing.pixels(center.y)+top, Drawing.pixels(shape.radius)) elseif shape.mode == 'arc' then local center = drawing.points[shape.center] love.graphics.arc('line', 'open', Drawing.pixels(center.x)+left,Drawing.pixels(center.y)+top, Drawing.pixels(shape.radius), shape.start_angle, shape.end_angle, 360) elseif shape.mode == 'deleted' then -- ignore else print(shape.mode) assert(false) end end function Drawing.draw_pending_shape(left,top, drawing) local shape = drawing.pending if shape.mode == nil then -- nothing pending elseif shape.mode == 'freehand' then Drawing.draw_shape(left,top, drawing, shape) elseif shape.mode == 'line' then local mx,my = Drawing.coord(love.mouse.getX()-left), Drawing.coord(love.mouse.getY()-top) if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then return end local p1 = drawing.points[shape.p1] love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(mx)+left,Drawing.pixels(my)+top) elseif shape.mode == 'manhattan' then local mx,my = Drawing.coord(love.mouse.getX()-left), Drawing.coord(love.mouse.getY()-top) if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then return end local p1 = drawing.points[shape.p1] if math.abs(mx-p1.x) > math.abs(my-p1.y) then love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(mx)+left,Drawing.pixels(p1.y)+top) else love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(p1.x)+left,Drawing.pixels(my)+top) end elseif shape.mode == 'polygon' then -- don't close the loop on a pending polygon local prev = nil for _,point in ipairs(shape.vertices) do local curr = drawing.points[point] if prev then love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top) end prev = curr end love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, love.mouse.getX(),love.mouse.getY()) elseif shape.mode == 'rectangle' then local pmx,pmy = love.mouse.getX(), love.mouse.getY() local first = drawing.points[shape.vertices[1]] if #shape.vertices == 1 then love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, pmx,pmy) return end local second = drawing.points[shape.vertices[2]] local mx,my = Drawing.coord(pmx-left), Drawing.coord(pmy-top) local thirdx,thirdy, fourthx,fourthy = Drawing.complete_rectangle(first.x,first.y, second.x,second.y, mx,my) love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top) love.graphics.line(Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top) love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top) love.graphics.line(Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top, Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top) elseif shape.mode == 'square' then local pmx,pmy = love.mouse.getX(), love.mouse.getY() local first = drawing.points[shape.vertices[1]] if #shape.vertices == 1 then love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, pmx,pmy) return end local second = drawing.points[shape.vertices[2]] local mx,my = Drawing.coord(pmx-left), Drawing.coord(pmy-top) local thirdx,thirdy, fourthx,fourthy = Drawing.complete_square(first.x,first.y, second.x,second.y, mx,my) love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top) love.graphics.line(Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top) love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top) love.graphics.line(Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top, Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top) elseif shape.mode == 'circle' then local center = drawing.points[shape.center] local mx,my = Drawing.coord(love.mouse.getX()-left), Drawing.coord(love.mouse.getY()-top) if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then return end local cx,cy = Drawing.pixels(center.x)+left, Drawing.pixels(center.y)+top love.graphics.circle('line', cx,
/*
 * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#include <stdio.h>
#include <string.h>

#include "draw.h"
#include "util.h"

static void
drawborder(Display *dpy, Brush *b)
{
	XPoint points[5];
	XSetLineAttributes(dpy, b->gc, 1, LineSolid, CapButt, JoinMiter);
	XSetForeground(dpy, b->gc, b->border);
	points[0].x = b->rect.x;
	points[0].y = b->rect.y;
	points[1].x = b->rect.width - 1;
	points[1].y = 0;
	points[2].x = 0;
	points[2].y = b->rect.height - 1;
	points[3].x = -(b->rect.width - 1);
	points[3].y = 0;
	points[4].x = 0;
	points[4].y = -(b->rect.height - 1);
	XDrawLines(dpy, b->drawable, b->gc, points, 5, CoordModePrevious);
}

void
draw(Display *dpy, Brush *b, Bool border, const char *text)
{
	unsigned int x, y, w, h, len;
	static char buf[256];
	XGCValues gcv;

	XSetForeground(dpy, b->gc, b->bg);
	XFillRectangles(dpy, b->drawable, b->gc, &b->rect, 1);

	if(border)
		drawborder(dpy, b);

	if(!text)
		return;

	len = strlen(text);
	if(len >= sizeof(buf))
		len = sizeof(buf) - 1;
	memcpy(buf, text, len);
	buf[len] = 0;

	h = b->font.ascent + b->font.descent;
	y = b->rect.y + (b->rect.height / 2) - (h / 2) + b->font.ascent;
	x = b->rect.x + (h / 2);

	/* shorten text if necessary */
	while(len && (w = textwidth_l(&b->font, buf, len)) > b->rect.width - h)
		buf[--len] = 0;

	if(w > b->rect.width)
		return; /* too long */

	gcv.foreground = b->fg;
	gcv.background = b->bg;
	if(b->font.set) {
		XChangeGC(dpy, b->gc, GCForeground | GCBackground, &gcv);
		XmbDrawImageString(dpy, b->drawable, b->font.set, b->gc,
				x, y, buf, len);