expander.vala 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. /// Drop-in replacement (sort-of) for Gtk.Expander with
  8. /// ability to set a custom widget alongside Expander's label.
  9. public class Expander : Gtk.Box
  10. {
  11. private bool _expanded = false;
  12. private Gtk.EventBox _header_event_box;
  13. private Gtk.GestureMultiPress _gesture_click;
  14. private Gtk.Box _header_box;
  15. private Gtk.Image _arrow_image;
  16. private Gtk.Widget _header_widget;
  17. private Gtk.Widget _child = null;
  18. public Expander(string? label = null)
  19. {
  20. Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0);
  21. _header_event_box = new Gtk.EventBox();
  22. _gesture_click = new Gtk.GestureMultiPress(_header_event_box);
  23. _gesture_click.pressed.connect(on_header_button_pressed);
  24. _header_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
  25. _header_box.homogeneous = false;
  26. _arrow_image = new Gtk.Image.from_icon_name("pan-end-symbolic", Gtk.IconSize.BUTTON);
  27. _header_box.pack_start(_arrow_image, false, false, 0);
  28. _header_widget = new Gtk.Label(label);
  29. _header_box.pack_start(_header_widget, true, true, 0);
  30. _header_event_box.add(_header_box);
  31. this.pack_start(_header_event_box, false, false, 0);
  32. }
  33. public bool expanded
  34. {
  35. get
  36. {
  37. return _expanded;
  38. }
  39. set
  40. {
  41. if (_expanded == value)
  42. return;
  43. _expanded = value;
  44. if (_expanded)
  45. _arrow_image.set_from_icon_name("pan-down-symbolic", Gtk.IconSize.BUTTON);
  46. else
  47. _arrow_image.set_from_icon_name("pan-end-symbolic", Gtk.IconSize.BUTTON);
  48. if (_child != null) {
  49. if (_expanded)
  50. _child.show();
  51. else
  52. _child.hide();
  53. }
  54. }
  55. }
  56. private void on_header_button_pressed(int n_press, double x, double y)
  57. {
  58. uint button = _gesture_click.get_current_button();
  59. if (button == Gdk.BUTTON_PRIMARY)
  60. expanded = !expanded;
  61. }
  62. public string label
  63. {
  64. get
  65. {
  66. if (_header_widget is Gtk.Label)
  67. return ((Gtk.Label)_header_widget).label;
  68. else
  69. return "";
  70. }
  71. set
  72. {
  73. if (_header_widget is Gtk.Label) {
  74. ((Gtk.Label)_header_widget).label = value;
  75. } else {
  76. _header_box.remove(_header_widget);
  77. _header_widget = new Gtk.Label(value);
  78. _header_box.pack_start(_header_widget, true, true, 0);
  79. _header_box.show_all();
  80. }
  81. }
  82. }
  83. public Gtk.Widget custom_header
  84. {
  85. get
  86. {
  87. return _header_widget;
  88. }
  89. set
  90. {
  91. if (_header_widget != null)
  92. _header_box.remove(_header_widget);
  93. _header_widget = value;
  94. _header_box.pack_start(_header_widget, true, true, 0);
  95. _header_box.show_all();
  96. }
  97. }
  98. public override void add(Gtk.Widget widget)
  99. {
  100. assert(_child == null);
  101. _child = widget;
  102. base.add(_child);
  103. if (!_expanded)
  104. _child.hide();
  105. show_all();
  106. }
  107. public override void remove(Gtk.Widget widget)
  108. {
  109. if (widget == _child)
  110. _child = null;
  111. base.remove(widget);
  112. }
  113. }
  114. } /* namespace Crown */