dock.vala 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /********************************************************************
  2. # Copyright 2014-2022 Daniel 'grindhold' Brendle
  3. #
  4. # This file is part of libgtkflow.
  5. #
  6. # libgtkflow is free software: you can redistribute it and/or
  7. # modify it under the terms of the GNU Lesser General Public License
  8. # as published by the Free Software Foundation, either
  9. # version 3 of the License, or (at your option) any later
  10. # version.
  11. #
  12. # libgtkflow is distributed in the hope that it will be
  13. # useful, but WITHOUT ANY WARRANTY; without even the implied
  14. # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. # PURPOSE. See the GNU Lesser General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Lesser General Public
  18. # License along with libgtkflow.
  19. # If not, see http://www.gnu.org/licenses/.
  20. *********************************************************************/
  21. namespace GtkFlow {
  22. /**
  23. * A widget that displays a {@link GFlow.Dock}
  24. *
  25. * Users may draw connections from and to this widget.
  26. * These widgets are only to be used inside implementations
  27. * of {@link GtkFlow.Node}
  28. */
  29. public class Dock : Gtk.Widget {
  30. construct {
  31. set_css_name("gtkflow_dock");
  32. }
  33. public GFlow.Dock d {get; protected set;}
  34. private Gtk.GestureClick ctr_click;
  35. internal Value? last_value = null;
  36. /**
  37. * Creates a new Dock
  38. *
  39. * Requires the programmer to pass a {@link GFlow.Dock} to
  40. * the d-parameter.
  41. */
  42. public Dock(GFlow.Dock d) {
  43. this.d = d;
  44. this.d.unlinked.connect(()=>{this.queue_draw();});
  45. this.d.linked.connect(()=>{this.queue_draw();});
  46. this.valign = Gtk.Align.CENTER;
  47. this.halign = Gtk.Align.CENTER;
  48. this.margin_start = 8;
  49. this.margin_end = 8;
  50. this.margin_top = 4;
  51. this.margin_bottom = 4;
  52. this.ctr_click = new Gtk.GestureClick();
  53. this.add_controller(this.ctr_click);
  54. this.ctr_click.pressed.connect((n, x, y) => { this.press_button(n,x,y); });
  55. this.d.changed.connect(this.cb_changed);
  56. }
  57. private GtkFlow.NodeView? get_nodeview() {
  58. var parent = this.get_parent();
  59. while (true) {
  60. if (parent == null) {
  61. return null;
  62. } else if (parent is NodeView) {
  63. return (NodeView)parent;
  64. } else {
  65. parent = parent.get_parent();
  66. }
  67. }
  68. }
  69. private void cb_changed(Value? value = null, string? flow_id = null) {
  70. var nv = this.get_nodeview();
  71. if (nv == null) {
  72. warning("Could not react to dock change: no nodeview");
  73. return;
  74. }
  75. if (value != null) {
  76. value.copy(ref this.last_value);
  77. } else {
  78. this.last_value = null;
  79. }
  80. nv.queue_draw();
  81. this.queue_draw();
  82. }
  83. /**
  84. * Request for the color of this dock
  85. *
  86. * Use {@link GLib.Signal.connect_after} to override this
  87. * method and let your application decide what color to use
  88. * for connections that are going off this node.
  89. * Be aware that only {@link GFlow.Source}s dictate the colors of the
  90. * connections. If this Dock holds a {@link GFlow.Sink} it
  91. * will have no visible effect.
  92. */
  93. public virtual signal Gdk.RGBA resolve_color(Dock d, Value? v) {
  94. return {0.0f,0.0f,0.0f,1.0f};
  95. }
  96. protected override void snapshot (Gtk.Snapshot sn) {
  97. var nv = this.get_nodeview();
  98. if (nv == null) {
  99. warning("Dock could not snapshot: no nodeview");
  100. return;
  101. }
  102. var rect = Graphene.Rect().init(0,0,16, 16);
  103. var rrect = Gsk.RoundedRect().init_from_rect(rect, 8f);
  104. Gdk.RGBA color = {0.5f,0.5f,0.5f,1.0f};
  105. Gdk.RGBA[] border_color = {color,color,color,color};
  106. float[] thicc = {1f,1f,1f,1f};
  107. sn.append_border(rrect, thicc, border_color);
  108. base.snapshot(sn);
  109. var cr = sn.append_cairo(rect);
  110. cr.save();
  111. cr.set_source_rgba(0.0,0.0,0.0,0.0);
  112. cr.set_operator(Cairo.Operator.SOURCE);
  113. cr.paint();
  114. cr.restore();
  115. if (this.d.is_linked()) {
  116. Gdk.RGBA dot_color = {0.0f,0.0f,0.0f,1.0f};
  117. if (this.d is GFlow.Source) {
  118. dot_color = this.resolve_color(this, this.last_value);
  119. } else if (this.d is GFlow.Sink && this.d.is_linked()) {
  120. var sink = (GFlow.Sink) this.d;
  121. var sourcedock = nv.retrieve_dock(sink.sources.nth_data(0));
  122. if (sourcedock != null) {
  123. dot_color = sourcedock.resolve_color(this, this.last_value);
  124. }
  125. }
  126. thicc = {8f, 8f, 8f, 8f};
  127. cr.save();
  128. cr.set_source_rgba(
  129. dot_color.red,
  130. dot_color.green,
  131. dot_color.blue,
  132. dot_color.alpha
  133. );
  134. cr.arc(8d,8d,4d,0.0,2*Math.PI);
  135. cr.fill();
  136. cr.restore();
  137. }
  138. }
  139. private void press_button(int n_clicked, double x, double y) {
  140. var nv = this.get_nodeview();
  141. if (nv == null) {
  142. warning("Dock could not process button press: no nodeview");
  143. return;
  144. }
  145. nv.start_temp_connector(this);
  146. nv.queue_allocate();
  147. }
  148. protected override void measure(Gtk.Orientation o, int for_size, out int min, out int pref, out int min_base, out int pref_base) {
  149. min = 16;
  150. pref = 16;
  151. min_base = -1;
  152. pref_base = -1;
  153. }
  154. }
  155. }