expander.vala 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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.Box _header_box;
  14. private Gtk.Image _arrow_image;
  15. private Gtk.Widget _header_widget;
  16. private Gtk.Widget _child = null;
  17. public Expander(string? label = null)
  18. {
  19. Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0);
  20. _header_event_box = new Gtk.EventBox();
  21. _header_event_box.button_press_event.connect(on_header_clicked);
  22. _header_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
  23. _header_box.homogeneous = false;
  24. _arrow_image = new Gtk.Image.from_icon_name("pan-end-symbolic", Gtk.IconSize.BUTTON);
  25. _header_box.pack_start(_arrow_image, false, false, 0);
  26. _header_widget = new Gtk.Label(label);
  27. _header_box.pack_start(_header_widget, true, true, 0);
  28. _header_event_box.add(_header_box);
  29. this.pack_start(_header_event_box, false, false, 0);
  30. }
  31. public bool expanded
  32. {
  33. get
  34. {
  35. return _expanded;
  36. }
  37. set
  38. {
  39. if (_expanded == value)
  40. return;
  41. _expanded = value;
  42. if (_expanded)
  43. _arrow_image.set_from_icon_name("pan-down-symbolic", Gtk.IconSize.BUTTON);
  44. else
  45. _arrow_image.set_from_icon_name("pan-end-symbolic", Gtk.IconSize.BUTTON);
  46. if (_child != null) {
  47. if (_expanded)
  48. _child.show();
  49. else
  50. _child.hide();
  51. }
  52. }
  53. }
  54. private bool on_header_clicked(Gtk.Widget widget, Gdk.EventButton event)
  55. {
  56. if (event.button == Gdk.BUTTON_PRIMARY) {
  57. expanded = !expanded;
  58. return Gdk.EVENT_STOP;
  59. }
  60. return Gdk.EVENT_PROPAGATE;
  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 */