pixbuf_view.vala 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (c) 2012-2026 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. public class PixbufView : Gtk.DrawingArea
  8. {
  9. public static Cairo.Pattern _checker_pattern;
  10. public static void create_checkered_pattern()
  11. {
  12. if (_checker_pattern != null)
  13. return;
  14. int width = 16;
  15. int height = 16;
  16. Cairo.Surface checker_surface = new Cairo.ImageSurface(Cairo.Format.RGB24, width, height);
  17. Cairo.Context cr = new Cairo.Context(checker_surface);
  18. cr.set_source_rgb(0.9, 0.9, 0.9);
  19. cr.paint();
  20. cr.set_source_rgb(0.7, 0.7, 0.7);
  21. cr.rectangle(width / 2, 0, width / 2, height / 2);
  22. cr.rectangle(0, height / 2, width / 2, height / 2);
  23. cr.fill();
  24. _checker_pattern = new Cairo.Pattern.for_surface(checker_surface);
  25. _checker_pattern.set_filter(Cairo.Filter.NEAREST);
  26. _checker_pattern.set_extend(Cairo.Extend.REPEAT);
  27. }
  28. public double _zoom;
  29. public double _zoom_speed;
  30. public Gtk.EventControllerScroll _controller_scroll;
  31. public Gdk.Pixbuf _pixbuf;
  32. public Cairo.Pattern _pixbuf_pattern;
  33. public Cairo.Filter _filter;
  34. public Cairo.Extend _extend;
  35. public PixbufView()
  36. {
  37. create_checkered_pattern();
  38. _zoom = 1.0;
  39. _zoom_speed = 0.2;
  40. _controller_scroll = new Gtk.EventControllerScroll(this, Gtk.EventControllerScrollFlags.VERTICAL);
  41. _controller_scroll.scroll.connect(on_scroll);
  42. _filter = Cairo.Filter.NEAREST;
  43. _extend = Cairo.Extend.NONE;
  44. this.draw.connect(on_draw);
  45. }
  46. public void set_pixbuf(Gdk.Pixbuf pixbuf)
  47. {
  48. _pixbuf = pixbuf;
  49. _pixbuf_pattern = new Cairo.Pattern.for_surface(Gdk.cairo_surface_create_from_pixbuf(_pixbuf, 1, null));
  50. _pixbuf_pattern.set_filter(Cairo.Filter.NEAREST);
  51. _pixbuf_pattern.set_filter(_filter);
  52. _pixbuf_pattern.set_extend(_extend);
  53. }
  54. public void on_scroll(double dx, double dy)
  55. {
  56. _zoom = double.min(10.0, double.max(0.25, _zoom - dy * _zoom_speed));
  57. this.queue_draw();
  58. }
  59. public bool on_draw(Cairo.Context cr)
  60. {
  61. if (_pixbuf == null)
  62. return Gdk.EVENT_PROPAGATE;
  63. int allocated_width = this.get_allocated_width();
  64. int allocated_height = this.get_allocated_height();
  65. cr.set_source_rgb(0.1, 0.1, 0.1);
  66. cr.paint();
  67. cr.set_source(_checker_pattern);
  68. cr.rectangle(allocated_width*0.5 - _zoom*_pixbuf.width*0.5
  69. , allocated_height*0.5 - _zoom*_pixbuf.height*0.5
  70. , _zoom * _pixbuf.width
  71. , _zoom * _pixbuf.height
  72. );
  73. cr.clip();
  74. cr.paint();
  75. cr.translate(allocated_width * 0.5, allocated_height * 0.5);
  76. cr.scale(_zoom, _zoom);
  77. cr.translate(-_pixbuf.width * 0.5, -_pixbuf.height * 0.5);
  78. cr.set_source(_pixbuf_pattern);
  79. cr.paint();
  80. return Gdk.EVENT_PROPAGATE;
  81. }
  82. }
  83. } /* namespace Crown */