input_enum.vala 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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 InputEnum : InputField
  8. {
  9. public bool _inconsistent;
  10. public Gtk.ListStore _store;
  11. public Gtk.TreeModelFilter _filter;
  12. public Gtk.ComboBox _combo;
  13. public Gtk.EventControllerScroll _controller_scroll;
  14. public override void set_inconsistent(bool inconsistent)
  15. {
  16. if (_inconsistent != inconsistent) {
  17. _inconsistent = inconsistent;
  18. _filter.refilter();
  19. if (_inconsistent) {
  20. _combo.set_active_id(INCONSISTENT_ID);
  21. }
  22. }
  23. }
  24. public override bool is_inconsistent()
  25. {
  26. return _inconsistent;
  27. }
  28. public override GLib.Value union_value()
  29. {
  30. return this.value;
  31. }
  32. public override void set_union_value(GLib.Value v)
  33. {
  34. this.value = (string)v;
  35. }
  36. public string value
  37. {
  38. get
  39. {
  40. return _combo.get_active_id();
  41. }
  42. set
  43. {
  44. _filter.refilter();
  45. bool success = _combo.set_active_id(value);
  46. set_inconsistent(!success);
  47. }
  48. }
  49. public bool filter_visible_func(Gtk.TreeModel model, Gtk.TreeIter iter)
  50. {
  51. Value id_val;
  52. model.get_value(iter, 0, out id_val);
  53. if (!_inconsistent && (string)id_val == INCONSISTENT_ID)
  54. return false;
  55. return true;
  56. }
  57. public InputEnum(string default_id = "DEFAULT", string[]? labels = null, string[]? ids = null)
  58. {
  59. _inconsistent = false;
  60. _store = new Gtk.ListStore(2
  61. , typeof(string) // ID
  62. , typeof(string) // Label
  63. );
  64. _filter = new Gtk.TreeModelFilter(_store, null);
  65. _filter.set_visible_func(filter_visible_func);
  66. _combo = new Gtk.ComboBox();
  67. _combo.model = _filter;
  68. _combo.id_column = 0;
  69. _combo.entry_text_column = 1;
  70. Gtk.CellRendererText renderer = new Gtk.CellRendererText();
  71. _combo.pack_start(renderer, true);
  72. _combo.add_attribute(renderer, "text", 1);
  73. insert_special_values();
  74. if (labels != null) {
  75. Gtk.TreeIter iter;
  76. for (int ii = 0; ii < ids.length; ++ii) {
  77. unowned string? id = ids != null ? ids[ii] : null;
  78. _store.insert_with_values(out iter, -1, 0, id, 1, labels[ii], -1);
  79. }
  80. // if (ids != null && default_id < ids.length)
  81. this.value = default_id;
  82. }
  83. _combo.changed.connect(on_changed);
  84. #if CROWN_GTK3
  85. _combo.scroll_event.connect(() => {
  86. GLib.Signal.stop_emission_by_name(_combo, "scroll-event");
  87. return Gdk.EVENT_PROPAGATE;
  88. });
  89. #else
  90. _controller_scroll = new Gtk.EventControllerScroll(_combo, Gtk.EventControllerScrollFlags.BOTH_AXES);
  91. _controller_scroll.set_propagation_phase(Gtk.PropagationPhase.CAPTURE);
  92. _controller_scroll.scroll.connect(() => {
  93. // Do nothing, just consume the event to stop
  94. // the annoying scroll default behavior.
  95. });
  96. #endif
  97. this.add(_combo);
  98. }
  99. public void append(string? id, string label)
  100. {
  101. _combo.changed.disconnect(on_changed);
  102. Gtk.TreeIter iter;
  103. _store.insert_with_values(out iter, -1, 0, id, 1, label, -1);
  104. _combo.changed.connect(on_changed);
  105. }
  106. public void clear()
  107. {
  108. _combo.changed.disconnect(on_changed);
  109. _store.clear();
  110. insert_special_values();
  111. _inconsistent = false;
  112. _combo.changed.connect(on_changed);
  113. }
  114. public string any_valid_id()
  115. {
  116. string some_id = INCONSISTENT_ID;
  117. if (_store.iter_n_children(null) > 1u) {
  118. _store.foreach((model, path, iter) => {
  119. Value id_val;
  120. model.get_value(iter, 0, out id_val);
  121. if ((string)id_val != INCONSISTENT_ID) {
  122. some_id = (string)id_val;
  123. return true;
  124. }
  125. return false;
  126. });
  127. }
  128. return some_id;
  129. }
  130. public void on_changed()
  131. {
  132. if (_combo.get_active_id() == null)
  133. return;
  134. if (_inconsistent && _combo.get_active_id() == INCONSISTENT_ID)
  135. return;
  136. if (_inconsistent) {
  137. _inconsistent = false;
  138. _filter.refilter();
  139. }
  140. value_changed(this);
  141. }
  142. public void insert_special_values()
  143. {
  144. assert(_store.iter_n_children(null) == 0u);
  145. // Insert the "inconsistent" ID and label.
  146. Gtk.TreeIter iter;
  147. _store.insert_with_values(out iter, -1, 0, INCONSISTENT_ID, 1, INCONSISTENT_LABEL, -1);
  148. }
  149. }
  150. } /* namespace Crown */