PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/src/girl/gui/view/pixelcv.lua

http://princess.codeplex.com
Lua | 645 lines | 606 code | 28 blank | 11 comment | 0 complexity | 0704e4207cd353d763b8ca3b5710263e MD5 | raw file
  1. ----------------------------------------------------------------
  2. -- write by xerysherry
  3. -- ??View?
  4. local View = getClass("Object.View");
  5. local Rect = getClass("Object.Rect");
  6. local ViewMouseEnum = getClass("Object.ViewMouseEnum");
  7. local Graphics = getClass("Object.Graphics");
  8. local lg = love.graphics;
  9. local tinsert = table.insert;
  10. local mfloor = math.floor;
  11. local mabs = math.abs;
  12. local msqrt = math.sqrt;
  13. local DrawTool = {
  14. Point=0, -- ?
  15. Line=1, -- ?,?????
  16. Rectangle=2, -- ??
  17. Circle=3 -- ?,?????
  18. };
  19. -- ????(?????????)
  20. local Pixelcv = class("Pixelcv", View,
  21. {
  22. click = false,
  23. -- ????
  24. cv_w = 32,
  25. cv_h = 32,
  26. cv = nil,
  27. -- ??
  28. rb_eraser_mode = true,
  29. -- ????
  30. zoom = 8, -- 1.0?? ??1pixel=??1pixel
  31. -- ??
  32. offset_x = 0,
  33. offset_y = 0,
  34. -- ????
  35. bg_color = nil, -- ????
  36. cvbg_color = nil, -- ????
  37. line_color = nil, -- ??????
  38. cvclear_color = nil,-- ??clear??
  39. -- ????
  40. draw_color = nil,
  41. points_list = nil,
  42. draw_tool = DrawTool.Point,
  43. eraser = false,
  44. fill = false,
  45. draw_quality = "rough",
  46. draw_size = 1,
  47. -- ???/???
  48. start_pt = nil,
  49. end_pt = nil,
  50. });
  51. function Pixelcv:initialize(w, h)
  52. View.initialize(self, w, h);
  53. self.bg_color = {128, 128, 128};
  54. self.cvbg_color = {255, 255, 255, 255};
  55. self.line_color = {0, 0, 0, 255};
  56. self.draw_color = {0, 0, 0, 255};
  57. self.cvclear_color = {255, 255, 255, 0};
  58. end
  59. function Pixelcv:setNewCanvas(w, h)
  60. self.cv_w = w;
  61. self.cv_h = h;
  62. self.cv = lg.newCanvas(self.cv_w, self.cv_h);
  63. self.cv:setFilter("nearest", "nearest");
  64. self:clearCv();
  65. end
  66. function Pixelcv:setDrawQuality(quality)
  67. self.draw_quality = quality;
  68. end
  69. function Pixelcv:setDrawSize(size)
  70. self.draw_size = size;
  71. end
  72. function Pixelcv:setCanvas(cv)
  73. self.cv_w = cv:getWidth();
  74. self.cv_h = cv:getHeight();
  75. self.cv = cv;
  76. self.cv:setFilter("nearest", "nearest");
  77. end
  78. function Pixelcv:setCanvasFilter(min, mag)
  79. self.cv:setFilter(min, mag);
  80. end
  81. function Pixelcv:getDrawQuality()
  82. return self.draw_quality;
  83. end
  84. function Pixelcv:getDrawSize()
  85. return self.draw_size;
  86. end
  87. function Pixelcv:getCanvas(cv)
  88. return self.cv;
  89. end
  90. function Pixelcv:getCanvasFilter(min, mag)
  91. return self.cv:getFilter();
  92. end
  93. function Pixelcv:setBgColor(color)
  94. self.bg_color = color or {128, 128, 128};
  95. end
  96. function Pixelcv:setCvColor(color)
  97. self.cvbg_color = color or {255, 255, 255, 255};
  98. end
  99. function Pixelcv:setLineColor(color)
  100. self.line_color = color or {0, 0, 0, 255};
  101. end
  102. function Pixelcv:setDrawColor(color)
  103. self.draw_color = color or {0, 0, 0, 255};
  104. end
  105. function Pixelcv:setEraseColor(color)
  106. self.cvclear_color = color or {255, 255, 255, 0};
  107. end
  108. function Pixelcv:setDrawTool(tool)
  109. assert(DrawTool[tool]~=nil, "the tool's name of \""..tool.."\" is not exist");
  110. self.draw_tool = DrawTool[tool];
  111. end
  112. function Pixelcv:setEraser(v)
  113. self.eraser = v or false;
  114. end
  115. function Pixelcv:setFill(v)
  116. self.fill = v or false;
  117. end
  118. function Pixelcv:setZoom(zoom)
  119. self.zoom = zoom;
  120. end
  121. function Pixelcv:setOffsetX(offset)
  122. self.offset_x = offset;
  123. if self.offset_x>0 then
  124. self.offset_x = -self.offset_x;
  125. end
  126. end
  127. function Pixelcv:setOffsetY(offset)
  128. self.offset_y = offset;
  129. if self.offset_y>0 then
  130. self.offset_y = -self.offset_y;
  131. end
  132. end
  133. function Pixelcv:getZoomWidth()
  134. return self.zoom*self.cv_w;
  135. end
  136. function Pixelcv:getZoomHeight()
  137. return self.zoom*self.cv_h;
  138. end
  139. function Pixelcv:clearCv()
  140. self.cv:clear(unpack(self.cvclear_color));
  141. end
  142. function Pixelcv:getCanvasLocAndSize()
  143. local fx = self.offset_x;
  144. local fy = self.offset_y;
  145. local fw = self.cv_w * self.zoom;
  146. local fh = self.cv_h * self.zoom;
  147. if fw<self.rect.width then
  148. fx = (self.rect.width - fw)/2;
  149. end
  150. if fh<self.rect.height then
  151. fy = (self.rect.height - fh)/2;
  152. end
  153. return fx, fy, fw, fh;
  154. end
  155. function Pixelcv:getLinePoints(ex, ey)
  156. self.points_list = {};
  157. local dx = ex-self.start_pt[1];
  158. local dy = ey-self.start_pt[2];
  159. if mabs(dx)>mabs(dy) then
  160. local k = (ey-self.start_pt[2])/(ex-self.start_pt[1]);
  161. local ax = 1;
  162. if dx<0 then
  163. ax=-1;
  164. end
  165. for i=0, dx, ax do
  166. local ix = self.start_pt[1]+i;
  167. local iy = self.start_pt[2]+mfloor(k*i);
  168. table.insert(self.points_list, {ix*self.zoom, iy*self.zoom});
  169. end
  170. else
  171. local k = (ex-self.start_pt[1])/(ey-self.start_pt[2]);
  172. local ay = 1;
  173. if dy<0 then
  174. ay=-1;
  175. end
  176. for i=0, dy, ay do
  177. local ix = self.start_pt[1]+mfloor(k*i);
  178. local iy = self.start_pt[2]+i;
  179. table.insert(self.points_list, {ix*self.zoom, iy*self.zoom});
  180. end
  181. end
  182. end
  183. function Pixelcv:saveCanvas(...)
  184. Graphics.encodeCanvas(self.cv, ...);
  185. end
  186. function Pixelcv:drawCvPoint(x, y)
  187. lg.setCanvas(self.cv);
  188. local p1, p2 = lg.getLineWidth(), lg.getLineStyle();
  189. lg.setLine(self.draw_size, self.draw_quality)
  190. lg.setColor(self.draw_color);
  191. lg.line(x, y, x+1, y+1);
  192. lg.setLine(p1, p2);
  193. lg.setCanvas();
  194. end
  195. function Pixelcv:drawCvLine(x, y)
  196. lg.setCanvas(self.cv);
  197. lg.setColor(self.draw_color);
  198. local sx=self.start_pt[1];
  199. if x<self.start_pt[1] then
  200. dx=x;
  201. end
  202. local dy=self.start_pt[2];
  203. if y<self.start_pt[2] then
  204. dy=y;
  205. end
  206. local p1, p2 = lg.getLineWidth(), lg.getLineStyle();
  207. lg.setLine(self.draw_size, self.draw_quality)
  208. lg.line(self.start_pt[1], self.start_pt[2], x, y);
  209. lg.setLine(p1, p2);
  210. lg.setCanvas();
  211. end
  212. function Pixelcv:drawCvRectangle(x, y)
  213. lg.setCanvas(self.cv);
  214. lg.setColor(self.draw_color);
  215. local dx=self.start_pt[1];
  216. if x<self.start_pt[1] then
  217. dx=x;
  218. end
  219. local dy=self.start_pt[2];
  220. if y<self.start_pt[2] then
  221. dy=y;
  222. end
  223. if self.fill then
  224. lg.rectangle("fill", dx, dy,
  225. mabs(self.start_pt[1]-x)+1, mabs(self.start_pt[2]-y)+1);
  226. else
  227. local p1, p2 = lg.getLineWidth(), lg.getLineStyle();
  228. lg.setLine(self.draw_size, self.draw_quality)
  229. lg.rectangle("line", dx+1, dy+1,
  230. mabs(self.start_pt[1]-x), mabs(self.start_pt[2]-y));
  231. lg.setLine(p1, p2);
  232. end
  233. lg.setCanvas();
  234. end
  235. function Pixelcv:drawCvCircle(x, y)
  236. lg.setCanvas(self.cv);
  237. lg.setColor(self.draw_color);
  238. local dx=self.start_pt[1];
  239. local dy=self.start_pt[2];
  240. local da=dx-x;
  241. local db=dy-y;
  242. local r=msqrt(da*da+db*db)
  243. if self.fill then
  244. lg.circle("fill", dx, dy, r);
  245. else
  246. local p1, p2 = lg.getLineWidth(), lg.getLineStyle();
  247. lg.setLine(self.draw_size, self.draw_quality)
  248. lg.circle("line", dx, dy, r);
  249. lg.setLine(p1, p2);
  250. end
  251. lg.setCanvas();
  252. end
  253. function Pixelcv:eraseCvPoint(x, y)
  254. lg.setCanvas(self.cv);
  255. local ds2rd = mfloor(self.draw_size/2);
  256. if ds2rd==self.draw_size/2 then
  257. y=y+1;
  258. end
  259. lg.setScissor(x-ds2rd, y-ds2rd, self.draw_size, self.draw_size);
  260. self.cv:clear(unpack(self.cvclear_color));
  261. lg.setScissor();
  262. lg.setCanvas();
  263. end
  264. function Pixelcv:eraseCvRectangle(x, y)
  265. local dx=self.start_pt[1];
  266. if x<self.start_pt[1] then
  267. dx=x;
  268. end
  269. local dy=self.start_pt[2];
  270. if y<self.start_pt[2] then
  271. dy=y;
  272. end
  273. lg.setCanvas(self.cv);
  274. lg.setScissor(dx, dy,
  275. mabs(self.start_pt[1]-x)+1, mabs(self.start_pt[2]-y)+1);
  276. self.cv:clear(unpack(self.cvclear_color));
  277. lg.setScissor();
  278. lg.setCanvas();
  279. end
  280. function Pixelcv:drawFakePoint(color)
  281. if self.start_pt==nil then
  282. return;
  283. end
  284. local vl, vt, vw, vh = self.rect:getRect();
  285. local cx, cy, cw, ch = self:getCanvasLocAndSize();
  286. local sx, sy, sw, sh = MergeRect(0, 0, vw, vh, cx, cy, cw, ch);
  287. if sx==nil then
  288. return;
  289. end
  290. --?????
  291. self.gui.graph._setScissor(sx+vl, sy+vt, sw, sh);
  292. --??
  293. self.gui.graph._push();
  294. self.gui.graph._translate(cx, cy);
  295. lg.setColor(color);
  296. lg.rectangle("fill", self.start_pt[1]*self.zoom,
  297. self.start_pt[2]*self.zoom, self.zoom, self.zoom);
  298. self.gui.graph._setScissor(vl, vt, vw, vh);
  299. self.gui.graph._pop();
  300. end
  301. function Pixelcv:drawFakeLine(color)
  302. if self.start_pt==nil then
  303. return;
  304. end
  305. local vl, vt, vw, vh = self.rect:getRect();
  306. local cx, cy, cw, ch = self:getCanvasLocAndSize();
  307. local sx, sy, sw, sh = MergeRect(0, 0, vw, vh, cx, cy, cw, ch);
  308. if sx==nil then
  309. return;
  310. end
  311. --?????
  312. self.gui.graph._setScissor(sx+vl, sy+vt, sw, sh);
  313. --??
  314. self.gui.graph._push();
  315. self.gui.graph._translate(cx, cy);
  316. local dx=self.start_pt[1];
  317. if self.end_pt[1]<self.start_pt[1] then
  318. dx=self.end_pt[1];
  319. end
  320. local dy=self.start_pt[2];
  321. if self.end_pt[2]<self.start_pt[2] then
  322. dy=self.end_pt[2];
  323. end
  324. local p1, p2 = lg.getLineWidth(), lg.getLineStyle();
  325. lg.setColor(color);
  326. lg.line(self.start_pt[1]*self.zoom,
  327. self.start_pt[2]*self.zoom,
  328. self.end_pt[1]*self.zoom,
  329. self.end_pt[2]*self.zoom);
  330. lg.setLine(p1, p2);
  331. self.gui.graph._setScissor(vl, vt, vw, vh);
  332. self.gui.graph._pop();
  333. end
  334. function Pixelcv:drawFakeRectangle(color)
  335. if self.start_pt==nil then
  336. return;
  337. end
  338. local vl, vt, vw, vh = self.rect:getRect();
  339. local cx, cy, cw, ch = self:getCanvasLocAndSize();
  340. local sx, sy, sw, sh = MergeRect(0, 0, vw, vh, cx, cy, cw, ch);
  341. if sx==nil then
  342. return;
  343. end
  344. --?????
  345. self.gui.graph._setScissor(sx+vl, sy+vt, sw, sh);
  346. --??
  347. self.gui.graph._push();
  348. self.gui.graph._translate(cx, cy);
  349. local dx=self.start_pt[1];
  350. if self.end_pt[1]<self.start_pt[1] then
  351. dx=self.end_pt[1];
  352. end
  353. local dy=self.start_pt[2];
  354. if self.end_pt[2]<self.start_pt[2] then
  355. dy=self.end_pt[2];
  356. end
  357. lg.setColor(color);
  358. lg.rectangle("line", dx*self.zoom, dy*self.zoom,
  359. mabs(self.start_pt[1]-self.end_pt[1])*self.zoom+self.zoom,
  360. mabs(self.start_pt[2]-self.end_pt[2])*self.zoom+self.zoom);
  361. self.gui.graph._setScissor(vl, vt, vw, vh);
  362. self.gui.graph._pop();
  363. end
  364. function Pixelcv:drawFakeCircle(color)
  365. if self.start_pt==nil then
  366. return;
  367. end
  368. local vl, vt, vw, vh = self.rect:getRect();
  369. local cx, cy, cw, ch = self:getCanvasLocAndSize();
  370. local sx, sy, sw, sh = MergeRect(0, 0, vw, vh, cx, cy, cw, ch);
  371. if sx==nil then
  372. return;
  373. end
  374. --?????
  375. self.gui.graph._setScissor(sx+vl, sy+vt, sw, sh);
  376. --??
  377. self.gui.graph._push();
  378. self.gui.graph._translate(cx, cy);
  379. local dx=self.start_pt[1];
  380. local dy=self.start_pt[2];
  381. local da=self.end_pt[1]-dx;
  382. local db=self.end_pt[2]-dy;
  383. local r=msqrt(da*da+db*db)
  384. lg.setColor(color);
  385. lg.circle("line", dx*self.zoom, dy*self.zoom, r*self.zoom)
  386. self.gui.graph._setScissor(vl, vt, vw, vh);
  387. self.gui.graph._pop();
  388. end
  389. function Pixelcv:drawBackground()
  390. self.gui.graph._setColor(self.bg_color);
  391. self.gui.graph._rectangle("fill", 0, 0, self.rect.width, self.rect.height);
  392. end
  393. function Pixelcv:drawCanvasBackground(x, y, w, h)
  394. self.gui.graph._setColor(self.cvbg_color);
  395. self.gui.graph._rectangle("fill", x, y, w, h);
  396. end
  397. function Pixelcv:drawLine(x, y, w, h)
  398. if self.zoom < 8 then
  399. return;
  400. end
  401. self.gui.graph._setColor(self.line_color);
  402. for ox=0, w, self.zoom do
  403. local ix = ox + x;
  404. if ox>=0 then
  405. self.gui.graph._rectangle("fill", ix-1, y, 1, h);
  406. elseif ix>self.rect.width then
  407. break;
  408. end
  409. end
  410. for oy=0, h, self.zoom do
  411. local iy = oy + y;
  412. if oy>=0 then
  413. self.gui.graph._rectangle("fill", x-1, iy-1, w, 1);
  414. elseif iy>self.rect.height then
  415. break;
  416. end
  417. end
  418. end
  419. function Pixelcv:drawCanvas(x, y, w, h)
  420. self.gui.graph._setColor({255,255,255});
  421. self.gui.graph._draw(self.cv, x, y, 0, w/self.cv_w, h/self.cv_h);
  422. end
  423. function Pixelcv:onDraw()
  424. local fx, fy, fw, fh = self:getCanvasLocAndSize();
  425. self:drawBackground();
  426. self:drawCanvasBackground(fx, fy, fw, fh);
  427. self:drawCanvas(fx, fy, fw, fh);
  428. if not self.eraser then
  429. if self.draw_tool==DrawTool.Point and self.click then
  430. self:drawFakePoint(self.draw_color);
  431. elseif self.draw_tool==DrawTool.Line and self.click then
  432. self:drawFakeLine(self.draw_color);
  433. elseif self.draw_tool==DrawTool.Rectangle and self.click then
  434. self:drawFakeRectangle(self.draw_color);
  435. elseif self.draw_tool==DrawTool.Circle and self.click then
  436. self:drawFakeCircle(self.draw_color);
  437. else
  438. self:drawFakePoint(self.draw_color);
  439. end
  440. else
  441. if self.draw_tool==DrawTool.Point and self.click then
  442. self:drawFakePoint(self.cvclear_color);
  443. elseif self.draw_tool==DrawTool.Rectangle and self.click then
  444. self:drawFakeRectangle({128,128,128});
  445. else
  446. self:drawFakePoint(self.cvclear_color);
  447. end
  448. end
  449. self:drawLine(fx, fy, fw, fh);
  450. end
  451. function Pixelcv:onMousePressed(x, y, button)
  452. local fx, fy, fw, fh = self:getCanvasLocAndSize();
  453. if x<fx or y<fy then
  454. return;
  455. end
  456. local dx = mfloor((x-fx)/self.zoom);
  457. local dy = mfloor((y-fy)/self.zoom);
  458. if button==ViewMouseEnum.LB then
  459. self.start_pt = {dx, dy};
  460. if self.draw_tool==DrawTool.Point then
  461. self:drawCvPoint(dx, dy);
  462. elseif self.draw_tool==DrawTool.Line or
  463. self.draw_tool==DrawTool.Rectangle or
  464. self.draw_tool==DrawTool.Circle then
  465. self.end_pt = {dx, dy};
  466. else
  467. return;
  468. end
  469. self.click = true;
  470. self:grab();
  471. elseif button==ViewMouseEnum.RB then
  472. if not self.rb_eraser_mode then
  473. return;
  474. end
  475. self.start_pt = {dx, dy};
  476. if self.draw_tool==DrawTool.Point then
  477. self:eraseCvPoint(dx, dy);
  478. elseif self.draw_tool==DrawTool.Rectangle then
  479. self.end_pt = {dx, dy};
  480. else
  481. return;
  482. end
  483. self.click = true;
  484. self.eraser = true;
  485. self:grab();
  486. end
  487. end
  488. function Pixelcv:onMouseMove(x, y)
  489. local fx, fy, fw, fh = self:getCanvasLocAndSize();
  490. if self.click then
  491. if x<fx or y<fy then
  492. return;
  493. end
  494. local dx = mfloor((x-fx)/self.zoom);
  495. local dy = mfloor((y-fy)/self.zoom);
  496. if self.draw_tool==DrawTool.Point then
  497. if not self.eraser then
  498. self:drawCvPoint(dx, dy);
  499. else
  500. self:eraseCvPoint(dx, dy);
  501. end
  502. elseif self.draw_tool==DrawTool.Line or
  503. self.draw_tool==DrawTool.Rectangle or
  504. self.draw_tool==DrawTool.Circle then
  505. self.end_pt = {dx, dy};
  506. end
  507. else
  508. if x<fx or y<fy then
  509. self.start_pt = nil;
  510. return;
  511. else
  512. local dx = mfloor((x-fx)/self.zoom);
  513. local dy = mfloor((y-fy)/self.zoom);
  514. self.start_pt = {dx, dy};
  515. end
  516. end
  517. end
  518. function Pixelcv:onMouseReleased(x, y, button)
  519. if not self.click then
  520. return;
  521. end
  522. local fx, fy, fw, fh = self:getCanvasLocAndSize();
  523. if x<fx or y<fy then
  524. return;
  525. end
  526. local dx = mfloor((x-fx)/self.zoom);
  527. local dy = mfloor((y-fy)/self.zoom);
  528. if self.draw_tool==DrawTool.Line then
  529. if not self.eraser then
  530. -- ????
  531. self:drawCvLine(dx, dy);
  532. end
  533. elseif self.draw_tool==DrawTool.Rectangle then
  534. if not self.eraser then
  535. -- ????
  536. self:drawCvRectangle(dx, dy);
  537. else
  538. -- ????
  539. self:eraseCvRectangle(dx, dy);
  540. end
  541. elseif self.draw_tool==DrawTool.Circle then
  542. if not self.eraser then
  543. -- ????
  544. self:drawCvCircle(dx, dy);
  545. end
  546. end
  547. self.click = false;
  548. self.start_pt = nil;
  549. self.eraser = false;
  550. self:ungrab();
  551. end
  552. function Pixelcv:onLeave()
  553. self.start_pt = nil;
  554. end
  555. return Pixelcv;