RenderView.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // SuperTux Editor
  2. // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
  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. using System;
  17. using Gtk;
  18. using Gdk;
  19. using OpenGl;
  20. using Drawing;
  21. using SceneGraph;
  22. using DataStructures;
  23. public class RenderView : GLWidgetBase
  24. {
  25. public static TargetEntry [] DragTargetEntries = new TargetEntry[] {
  26. new TargetEntry("GameObject", TargetFlags.App, 0)
  27. };
  28. public Node SceneGraphRoot;
  29. private bool dragging;
  30. private Vector dragStartMouse;
  31. private Vector dragStartTranslation;
  32. private Vector MousePos;
  33. private ITool editor;
  34. public ITool Editor {
  35. set {
  36. if(this.editor != null) {
  37. this.editor.Redraw -= QueueDraw;
  38. if(this.editor is IToolCursorChange) {
  39. ((IToolCursorChange) this.editor).CursorChange -= CursorChange;
  40. //TODO: find a way how to reset it to default, this is wrong
  41. GdkWindow.Cursor = new Cursor(CursorType.LeftPtr);
  42. }
  43. if(this.editor is IDisposable)
  44. ((IDisposable) this.editor).Dispose();
  45. }
  46. this.editor = value;
  47. if(this.editor != null) {
  48. this.editor.Redraw += QueueDraw;
  49. if(this.editor is IToolCursorChange)
  50. ((IToolCursorChange) this.editor).CursorChange += CursorChange;
  51. }
  52. }
  53. get {
  54. return editor;
  55. }
  56. }
  57. public RenderView()
  58. {
  59. ButtonPressEvent += OnButtonPress;
  60. ButtonReleaseEvent += OnButtonRelease;
  61. MotionNotifyEvent += OnMotionNotify;
  62. ScrollEvent += OnScroll;
  63. AddEvents((int) Gdk.EventMask.ButtonPressMask);
  64. AddEvents((int) Gdk.EventMask.ButtonReleaseMask);
  65. AddEvents((int) Gdk.EventMask.PointerMotionMask);
  66. AddEvents((int) Gdk.EventMask.ScrollMask);
  67. CanFocus = true;
  68. Gtk.Drag.DestSet(this, DestDefaults.Drop | DestDefaults.Motion, DragTargetEntries, Gdk.DragAction.Copy);
  69. DragMotion += OnDragMotion;
  70. DragDataReceived += OnDragDataReceived;
  71. }
  72. protected override void DrawGl()
  73. {
  74. gl.ClearColor(0.4f, 0, 0.4f, 1);
  75. gl.Clear(gl.COLOR_BUFFER_BIT);
  76. if(SceneGraphRoot != null)
  77. SceneGraphRoot.Draw(GetClipRect());
  78. if(!dragging && Editor != null)
  79. Editor.Draw(GetClipRect());
  80. }
  81. private void OnDragMotion(object o, DragMotionArgs args)
  82. {
  83. //pass motion event to editor
  84. if(Editor != null) {
  85. MousePos = MouseToWorld(new Vector((float) args.X, (float) args.Y));
  86. Editor.OnMouseMotion(MousePos, ModifierType.Button1Mask);
  87. }
  88. }
  89. private void OnDragDataReceived(object o, DragDataReceivedArgs args)
  90. {
  91. // string data = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data); //no data transmitted on "fake drag"s
  92. if(Editor != null) {
  93. MousePos = MouseToWorld(new Vector((float) args.X, (float) args.Y));
  94. //emulated click on current editor to place object and perform "fake drag"
  95. Editor.OnMouseButtonPress(MousePos, 1, ModifierType.Button1Mask);
  96. Editor.OnMouseButtonRelease(MousePos, 1, ModifierType.Button1Mask);
  97. Gtk.Drag.Finish (args.Context, true, false, args.Time);
  98. } else {
  99. LogManager.Log(LogLevel.Warning, "DragDataRecieved OK, but there is no editor that can handle it");
  100. Gtk.Drag.Finish (args.Context, false, false, args.Time);
  101. }
  102. }
  103. private void OnButtonPress(object o, ButtonPressEventArgs args)
  104. {
  105. try {
  106. MousePos = MouseToWorld(
  107. new Vector((float) args.Event.X, (float) args.Event.Y));
  108. if(args.Event.Button == 2) {
  109. dragStartMouse = new Vector((float) args.Event.X, (float) args.Event.Y);
  110. dragStartTranslation = Translation;
  111. dragging = true;
  112. QueueDraw();
  113. } else if(Editor != null) {
  114. Editor.OnMouseButtonPress(MousePos, (int) args.Event.Button, args.Event.State);
  115. }
  116. args.RetVal = true;
  117. } catch(Exception e) {
  118. ErrorDialog.Exception(e);
  119. }
  120. }
  121. private void OnButtonRelease(object o, ButtonReleaseEventArgs args)
  122. {
  123. try {
  124. MousePos = MouseToWorld(
  125. new Vector((float) args.Event.X, (float) args.Event.Y));
  126. if(args.Event.Button == 2) {
  127. dragging = false;
  128. QueueDraw();
  129. } else if(Editor != null) {
  130. Editor.OnMouseButtonRelease(MousePos, (int) args.Event.Button, args.Event.State);
  131. }
  132. args.RetVal = true;
  133. } catch(Exception e) {
  134. ErrorDialog.Exception(e);
  135. }
  136. }
  137. private void OnMotionNotify(object o, MotionNotifyEventArgs args)
  138. {
  139. try {
  140. Vector pos = new Vector((float) args.Event.X, (float) args.Event.Y);
  141. MousePos = MouseToWorld(pos);
  142. if(dragging) {
  143. SetTranslation(dragStartTranslation +
  144. (pos - dragStartMouse) / Zoom);
  145. } else if(Editor != null) {
  146. Editor.OnMouseMotion(MousePos, args.Event.State);
  147. }
  148. args.RetVal = true;
  149. } catch(Exception e) {
  150. ErrorDialog.Exception(e);
  151. }
  152. }
  153. private void OnScroll(object o, ScrollEventArgs args)
  154. {
  155. float oldZoom = Zoom;
  156. Vector realMousePos = (MousePos + Translation) * Zoom;
  157. if(args.Event.Direction == ScrollDirection.Down) {
  158. Zoom /= (float) Math.Sqrt(2);
  159. } else if(args.Event.Direction == ScrollDirection.Up) {
  160. Zoom *= (float) Math.Sqrt(2);
  161. }
  162. //Limit the Zoom to useful values;
  163. if( Zoom < 0.002 || Zoom > 500 ){
  164. Zoom = oldZoom;
  165. }
  166. SetTranslation(Translation
  167. + realMousePos / Zoom - realMousePos / oldZoom);
  168. MousePos = MouseToWorld(realMousePos);
  169. if(Editor != null) {
  170. Editor.OnMouseMotion(MousePos, args.Event.State);
  171. }
  172. args.RetVal = true;
  173. }
  174. private void UpdateAdjustments()
  175. {
  176. if(hadjustment != null) {
  177. hadjustment.SetBounds(minx, maxx, 32/Zoom, 256/Zoom, Allocation.Width/Zoom);
  178. hadjustment.ClampPage(-Translation.X, -Translation.X + (Allocation.Width/Zoom));
  179. }
  180. if(vadjustment != null) {
  181. vadjustment.SetBounds(miny, maxy, 32/Zoom, 256/Zoom, Allocation.Height/Zoom);
  182. vadjustment.ClampPage(-Translation.Y, -Translation.Y + (Allocation.Height/Zoom));
  183. }
  184. }
  185. public void SetZoom(float newZoom)
  186. {
  187. float oldZoom = Zoom;
  188. Zoom = newZoom;
  189. // Limit the Zoom to useful values;
  190. if( Zoom < 0.002 || Zoom > 500 ){
  191. Zoom = oldZoom;
  192. }
  193. UpdateAdjustments();
  194. QueueDraw();
  195. }
  196. public float GetZoom()
  197. {
  198. return Zoom;
  199. }
  200. public void ZoomIn()
  201. {
  202. SetZoom( Zoom * (float) Math.Sqrt(2));
  203. }
  204. public void ZoomOut()
  205. {
  206. SetZoom( Zoom / (float) Math.Sqrt(2));
  207. }
  208. /// <summary>Zoom by factor, while keeping pos (in World
  209. /// coordinates) at the same spot on the screen</summary>
  210. public void ZoomTo(Vector pos, float factor)
  211. {
  212. Vector old_translation = Translation;
  213. SetZoom(Zoom * factor);
  214. SetTranslation((pos * (1 - factor) + old_translation) / factor);
  215. }
  216. /// <summary>Zoom by factor, while keeping the center of the
  217. /// window at the same spot on the screen</summary>
  218. public void ZoomTo(float factor)
  219. {
  220. Vector pos = MouseToWorld(new Vector(Allocation.Width/2.0f, Allocation.Height/2.0f));
  221. ZoomTo(pos, factor);
  222. }
  223. public void ZoomTo(RectangleF rect)
  224. {
  225. float window_aspect = Allocation.Width / Allocation.Height;
  226. float rect_aspect = rect.Width / rect.Height;
  227. if (window_aspect > rect_aspect)
  228. {
  229. SetZoom(Allocation.Height / rect.Height);
  230. SetPosition(rect.Center);
  231. }
  232. else
  233. {
  234. SetZoom(Allocation.Width / rect.Width);
  235. SetPosition(rect.Center);
  236. }
  237. }
  238. /// <summary>Set the Translatation so that the center of the
  239. /// window poinst to pos (in World coordinates)</summary>
  240. public void SetPosition(Vector pos)
  241. {
  242. SetTranslation(new Vector(Allocation.Width/2.0f/Zoom - pos.X, Allocation.Height/2.0f/Zoom - pos.Y));
  243. }
  244. public void SetTranslation(Vector tr)
  245. {
  246. Translation = tr;
  247. UpdateAdjustments();
  248. QueueDraw();
  249. }
  250. public Vector GetTranslation()
  251. {
  252. return Translation;
  253. }
  254. /// <summary>
  255. /// Returns a <see cref="Gdk.Rectangle"/> for the currently
  256. /// visible area in world coordinates.
  257. /// </summary>
  258. /// <returns>A <see cref="Gdk.Rectangle"/>.</returns>
  259. public Gdk.Rectangle GetClipRect() {
  260. return new Gdk.Rectangle(
  261. (int)-Translation.X, (int)-Translation.Y,
  262. (int)(Allocation.Width / Zoom), (int)(Allocation.Height / Zoom));
  263. }
  264. private Vector MouseToWorld(Vector MousePos)
  265. {
  266. return MousePos / Zoom - Translation;
  267. }
  268. private void CursorChange(Cursor cursor)
  269. {
  270. GdkWindow.Cursor = cursor;
  271. }
  272. /**
  273. * Add gtk adjustments for vertical and horizontal scrolling
  274. * (This is used for scrollbars)
  275. */
  276. public void SetAdjustments(Adjustment hadjustment, Adjustment vadjustment)
  277. {
  278. this.vadjustment = vadjustment;
  279. this.hadjustment = hadjustment;
  280. if(vadjustment != null) {
  281. vadjustment.ValueChanged += OnVAdjustmentChanged;
  282. }
  283. if(hadjustment != null) {
  284. hadjustment.ValueChanged += OnHAdjustmentChanged;
  285. }
  286. UpdateAdjustments();
  287. }
  288. private void OnHAdjustmentChanged(object sender, EventArgs e)
  289. {
  290. SetTranslation(new Vector((float) -hadjustment.Value, Translation.Y));
  291. }
  292. private void OnVAdjustmentChanged(object sender, EventArgs e)
  293. {
  294. SetTranslation(new Vector(Translation.X, (float) -vadjustment.Value));
  295. }
  296. private Adjustment vadjustment;
  297. private Adjustment hadjustment;
  298. protected float minx = -1000, maxx = 1000;
  299. protected float miny = -1000, maxy = 1000;
  300. }
  301. /* EOF */