graphic_context_state.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Flexlay - A Generic 2D Game Editor
  2. # Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. from typing import Optional
  17. import math
  18. from flexlay.graphic_context import GraphicContext
  19. from flexlay.math import Pointf, Rectf, Sizef
  20. class GraphicContextState:
  21. def __init__(self, w: int = 1, h: int = 1) -> None:
  22. self.width: int = w
  23. self.height: int = h
  24. self.offset: Pointf = Pointf(0, 0)
  25. self.zoom: float = 1.0
  26. self.rotation: float = 0
  27. def set_size(self, w: int, h: int) -> None:
  28. self.width = w
  29. self.height = h
  30. def push(self, gc: GraphicContext) -> None:
  31. gc.push_modelview()
  32. gc.translate(self.width / 2, self.height / 2)
  33. gc.rotate(self.rotation)
  34. gc.translate(-self.width / 2, -self.height / 2)
  35. gc.scale(self.get_zoom(), self.get_zoom())
  36. gc.translate(self.offset.x, self.offset.y)
  37. def pop(self, gc: GraphicContext) -> None:
  38. gc.pop_modelview()
  39. def get_clip_rect(self) -> Rectf:
  40. return Rectf.from_ps(Pointf(-self.offset.x,
  41. -self.offset.y),
  42. Sizef(self.width / self.zoom,
  43. self.height / self.zoom))
  44. def set_pos(self, pos: Pointf) -> None:
  45. self.offset.x = -pos.x + (self.width / 2 / self.zoom)
  46. self.offset.y = -pos.y + (self.height / 2 / self.zoom)
  47. def get_pos(self) -> Pointf:
  48. return Pointf(-self.offset.x + (self.width / 2 / self.zoom),
  49. -self.offset.y + (self.height / 2 / self.zoom))
  50. def set_zoom(self, z: float, pos: Optional[Pointf] = None) -> None:
  51. if pos is None:
  52. self.zoom = z
  53. else:
  54. old_zoom = self.zoom
  55. self.set_zoom(z)
  56. self.offset.x = pos.x / self.zoom - pos.x / old_zoom + self.offset.x
  57. self.offset.y = pos.y / self.zoom - pos.y / old_zoom + self.offset.y
  58. def get_zoom(self) -> float:
  59. return self.zoom
  60. def zoom_to(self, rect: Rectf) -> None:
  61. center_x = (rect.left + rect.right) / 2.0
  62. center_y = (rect.top + rect.bottom) / 2.0
  63. width = rect.right - rect.left
  64. height = rect.bottom - rect.top
  65. screen_relation = float(self.height) / float(self.width)
  66. rect_relation = height / width
  67. if rect_relation < screen_relation: # take width, ignore height
  68. self.zoom = self.width / width
  69. else: # take height, ignore width
  70. self.zoom = self.height / height
  71. self.offset.x = (self.width / (2 * self.zoom)) - center_x
  72. self.offset.y = (self.height / (2 * self.zoom)) - center_y
  73. def screen2world(self, pos: Pointf) -> Pointf:
  74. pos = pos.copy()
  75. sa = math.sin(-self.rotation / 180.0 * math.pi)
  76. ca = math.cos(-self.rotation / 180.0 * math.pi)
  77. dx = pos.x - self.width / 2
  78. dy = pos.y - self.height / 2
  79. pos.x = self.width / 2 + (ca * dx - sa * dy)
  80. pos.y = self.height / 2 + (sa * dx + ca * dy)
  81. return Pointf((float(pos.x) / self.zoom) - self.offset.x,
  82. (float(pos.y) / self.zoom) - self.offset.y)
  83. def set_rotation(self, angle: float) -> None:
  84. self.rotation = angle
  85. def get_rotation(self) -> float:
  86. return self.rotation
  87. # EOF #