/GHPC_Source/org/lateralgm/components/visual/VisualPanel.java

https://github.com/piluke/GameMaker-HTML5-Player · Java · 271 lines · 230 code · 34 blank · 7 comment · 33 complexity · 40795ae2bae3be5d44758bc1e9c1a041 MD5 · raw file

  1. /*
  2. * Copyright (C) 2009 Quadduc <quadduc@gmail.com>
  3. *
  4. * This file is part of LateralGM.
  5. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY.
  6. * See LICENSE for details.
  7. */
  8. package org.lateralgm.components.visual;
  9. import static org.lateralgm.main.Util.negDiv;
  10. import java.awt.Color;
  11. import java.awt.Dimension;
  12. import java.awt.Graphics;
  13. import java.awt.Graphics2D;
  14. import java.awt.Point;
  15. import java.awt.Rectangle;
  16. import java.awt.RenderingHints;
  17. import java.util.TreeMap;
  18. import javax.swing.JPanel;
  19. import org.lateralgm.ui.swing.visuals.BoundedVisual;
  20. import org.lateralgm.ui.swing.visuals.Visual;
  21. import org.lateralgm.ui.swing.visuals.VisualContainer;
  22. public class VisualPanel extends JPanel
  23. {
  24. private static final long serialVersionUID = 1L;
  25. public static final Point ORIGIN_MOUSE = new Point();
  26. private final TreeMap<Integer,Visual> visuals = new TreeMap<Integer,Visual>();
  27. private final Rectangle overallBounds = new Rectangle();
  28. public final VisualContainer container = new PanelVisualContainer();
  29. private int zoom = 1;
  30. protected Point zoomOrigin;
  31. private boolean boundsLocked = false;
  32. private boolean boundsUpdated = false;
  33. public VisualPanel()
  34. {
  35. setBackground(Color.GRAY);
  36. setOpaque(true);
  37. }
  38. protected void componentToVisual(Point p)
  39. {
  40. componentToVisual(p,zoom);
  41. }
  42. protected void componentToVisual(Point p, int z)
  43. {
  44. p.x = zoom(p.x - visualOffsetX(z),2 - z) + overallBounds.x;
  45. p.y = zoom(p.y - visualOffsetY(z),2 - z) + overallBounds.y;
  46. }
  47. protected void componentToVisual(Rectangle r, int z)
  48. {
  49. Point p = r.getLocation();
  50. componentToVisual(p,z);
  51. r.setLocation(p);
  52. r.width = zoom(r.width,2 - z);
  53. r.height = zoom(r.height,2 - z);
  54. }
  55. protected void visualToComponent(Point p)
  56. {
  57. visualToComponent(p,zoom);
  58. }
  59. protected void visualToComponent(Point p, int z)
  60. {
  61. p.x = zoom(p.x - overallBounds.x,z) + visualOffsetX(z);
  62. p.y = zoom(p.y - overallBounds.y,z) + visualOffsetY(z);
  63. }
  64. protected void visualToComponent(Rectangle r, int z)
  65. {
  66. Point p = r.getLocation();
  67. visualToComponent(p,z);
  68. r.setLocation(p);
  69. r.width = zoom(r.width,z);
  70. r.height = zoom(r.height,z);
  71. }
  72. protected double zoom(double d, int z)
  73. {
  74. return z > 0 ? z * d : d / (2 - z);
  75. }
  76. protected int zoom(int i, int z)
  77. {
  78. return z > 0 ? z * i : negDiv(i,2 - z);
  79. }
  80. protected int zoomAlign(int i, int z, boolean ceil)
  81. {
  82. return z <= 0 ? (2 - z) * negDiv(i + (ceil ? 1 - z : 0),2 - z) : i;
  83. }
  84. protected void zoomAlign(Rectangle r, int z, boolean out)
  85. {
  86. int x0 = zoomAlign(r.x,z,!out);
  87. int y0 = zoomAlign(r.y,z,!out);
  88. r.setBounds(x0,y0,zoomAlign(r.width + r.x - x0,z,out),zoomAlign(r.height + r.y - y0,z,out));
  89. }
  90. protected void zoom(Rectangle r, int z)
  91. {
  92. r.x = zoom(r.x,z);
  93. r.y = zoom(r.y,z);
  94. r.width = zoom(r.width,z);
  95. r.height = zoom(r.height,z);
  96. }
  97. protected int visualOffsetX(int z)
  98. {
  99. return (getWidth() - zoom(overallBounds.width,z)) / 2;
  100. }
  101. protected int visualOffsetY(int z)
  102. {
  103. return (getHeight() - zoom(overallBounds.height,z)) / 2;
  104. }
  105. protected Rectangle getOverallBounds(Rectangle r)
  106. {
  107. if (r == null) return new Rectangle(overallBounds);
  108. r.setBounds(overallBounds);
  109. return r;
  110. }
  111. protected void calculateOverallBounds(Rectangle b)
  112. {
  113. b.grow(128,128);
  114. b.add(0,0);
  115. }
  116. @Override
  117. public Dimension getPreferredSize()
  118. {
  119. Dimension s = overallBounds.getSize();
  120. s.width = zoom(s.width,zoom);
  121. s.height = zoom(s.height,zoom);
  122. return s;
  123. }
  124. @Override
  125. public Dimension getMinimumSize()
  126. {
  127. return getPreferredSize();
  128. }
  129. @Override
  130. public void paintComponent(Graphics g)
  131. {
  132. super.paintComponent(g);
  133. Graphics g2 = g.create();
  134. if (g2.getClip() == null) g2.setClip(0,0,getWidth(),getHeight());
  135. g2.translate(visualOffsetX(zoom),visualOffsetY(zoom));
  136. if (zoom != 1)
  137. {
  138. double s = zoom(1.0,zoom);
  139. Graphics2D g3 = ((Graphics2D) g2);
  140. g3.scale(s,s);
  141. g3.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
  142. zoom < 1 ? RenderingHints.VALUE_INTERPOLATION_BILINEAR
  143. : RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
  144. }
  145. g2.translate(-overallBounds.x,-overallBounds.y);
  146. paintVisuals(g2);
  147. g2.dispose();
  148. }
  149. protected void paintVisuals(Graphics g)
  150. {
  151. for (Visual v : visuals.values())
  152. v.paint(g);
  153. }
  154. public void put(int layer, Visual v)
  155. {
  156. Visual pv = v == null ? visuals.remove(layer) : visuals.put(layer,v);
  157. if (pv == v) return;
  158. if (v instanceof BoundedVisual || pv instanceof BoundedVisual) container.updateBounds();
  159. repaint();
  160. }
  161. protected void lockBounds()
  162. {
  163. boundsLocked = true;
  164. }
  165. protected void unlockBounds()
  166. {
  167. boundsLocked = false;
  168. if (boundsUpdated)
  169. {
  170. container.updateBounds();
  171. boundsUpdated = false;
  172. }
  173. }
  174. private class PanelVisualContainer implements VisualContainer
  175. {
  176. private int oldZoom = zoom;
  177. public void repaint(Rectangle r)
  178. {
  179. if (r == null)
  180. VisualPanel.this.repaint();
  181. else
  182. {
  183. Rectangle cr = r.getBounds();
  184. zoomAlign(cr,zoom,true);
  185. visualToComponent(cr,zoom);
  186. VisualPanel.this.repaint(cr);
  187. }
  188. }
  189. public void updateBounds()
  190. {
  191. boolean uob = (!boundsLocked);
  192. if (boundsLocked) boundsUpdated = true;
  193. boolean uz = zoom != oldZoom;
  194. if (!uob && !uz) return;
  195. Point o = zoomOrigin;
  196. Point co;
  197. if (o == null || o == ORIGIN_MOUSE)
  198. {
  199. co = o == null ? null : getMousePosition();
  200. if (co == null)
  201. {
  202. Rectangle vr = getVisibleRect();
  203. co = new Point(vr.x + vr.width / 2,vr.y + vr.height / 2);
  204. }
  205. o = co.getLocation();
  206. componentToVisual(o,oldZoom);
  207. }
  208. else
  209. {
  210. co = o.getLocation();
  211. visualToComponent(co,oldZoom);
  212. }
  213. Rectangle oob = overallBounds.getBounds();
  214. if (uob)
  215. {
  216. overallBounds.setSize(-1,-1);
  217. for (Visual v : visuals.values())
  218. if (v instanceof BoundedVisual) ((BoundedVisual) v).extendBounds(overallBounds);
  219. calculateOverallBounds(overallBounds);
  220. }
  221. zoomAlign(overallBounds,zoom,true);
  222. if (oob.equals(overallBounds) && !uz) return;
  223. Point p = getLocation();
  224. setBounds(p.x + co.x - zoom(o.x - overallBounds.x,zoom),p.y + co.y
  225. - zoom(o.y - overallBounds.y,zoom),Math.max(getWidth(),zoom(overallBounds.width,zoom)),
  226. Math.max(getHeight(),zoom(overallBounds.height,zoom)));
  227. oldZoom = zoom;
  228. revalidate();
  229. }
  230. }
  231. public void setZoom(int z)
  232. {
  233. if (zoom == z) return;
  234. zoom = z;
  235. container.updateBounds();
  236. }
  237. }