combo_box_map.vala 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. using Gtk;
  6. namespace Crown
  7. {
  8. public class ComboBoxMap : Gtk.ComboBox, Property
  9. {
  10. // Data
  11. public bool _stop_emit;
  12. public bool _inconsistent;
  13. public Gtk.ListStore _store;
  14. public Gtk.TreeModelFilter _filter;
  15. // Signals
  16. public signal void value_changed();
  17. public void set_inconsistent(bool inconsistent)
  18. {
  19. if (_inconsistent != inconsistent) {
  20. _inconsistent = inconsistent;
  21. _filter.refilter();
  22. if (_inconsistent) {
  23. _stop_emit = true;
  24. this.set_active_id(INCONSISTENT_ID);
  25. _stop_emit = false;
  26. }
  27. }
  28. }
  29. public bool is_inconsistent()
  30. {
  31. return _inconsistent;
  32. }
  33. public Value? generic_value()
  34. {
  35. return this.value;
  36. }
  37. public void set_generic_value(Value? val)
  38. {
  39. this.value = (string)val;
  40. }
  41. public string? value
  42. {
  43. get
  44. {
  45. return this.get_active_id();
  46. }
  47. set
  48. {
  49. _stop_emit = true;
  50. _filter.refilter();
  51. bool success = this.set_active_id((string)value);
  52. _stop_emit = false;
  53. set_inconsistent(!success);
  54. }
  55. }
  56. public bool filter_visible_func(Gtk.TreeModel model, Gtk.TreeIter iter)
  57. {
  58. Value id_val;
  59. model.get_value(iter, 0, out id_val);
  60. if (!_inconsistent && (string)id_val == INCONSISTENT_ID)
  61. return false;
  62. return true;
  63. }
  64. public ComboBoxMap(int default_id = 0, string[]? labels = null, string[]? ids = null)
  65. {
  66. // Data
  67. _stop_emit = false;
  68. _inconsistent = false;
  69. _store = new Gtk.ListStore(2
  70. , typeof(string) // ID
  71. , typeof(string) // Label
  72. );
  73. _filter = new Gtk.TreeModelFilter(_store, null);
  74. _filter.set_visible_func(filter_visible_func);
  75. this.model = _filter;
  76. this.id_column = 0;
  77. this.entry_text_column = 1;
  78. Gtk.CellRendererText renderer = new Gtk.CellRendererText();
  79. this.pack_start(renderer, true);
  80. this.add_attribute(renderer, "text", 1);
  81. insert_special_values();
  82. if (labels != null) {
  83. Gtk.TreeIter iter;
  84. for (int ii = 0; ii < ids.length; ++ii) {
  85. unowned string? id = ids != null ? ids[ii] : null;
  86. _store.insert_with_values(out iter, -1, 0, id, 1, labels[ii], -1);
  87. }
  88. if (ids != null && default_id < ids.length)
  89. this.value = ids[default_id];
  90. }
  91. // Widgets
  92. this.changed.connect(on_changed);
  93. this.scroll_event.connect(on_scroll);
  94. }
  95. public void append(string? id, string label)
  96. {
  97. Gtk.TreeIter iter;
  98. _store.insert_with_values(out iter, -1, 0, id, 1, label, -1);
  99. }
  100. public void clear()
  101. {
  102. _stop_emit = true;
  103. _store.clear();
  104. insert_special_values();
  105. _inconsistent = false;
  106. _stop_emit = false;
  107. }
  108. public string any_valid_id()
  109. {
  110. string some_id = INCONSISTENT_ID;
  111. if (_store.iter_n_children(null) > 1u) {
  112. _store.foreach((model, path, iter) => {
  113. Value id_val;
  114. model.get_value(iter, 0, out id_val);
  115. if ((string)id_val != INCONSISTENT_ID) {
  116. some_id = (string)id_val;
  117. return true;
  118. }
  119. return false;
  120. });
  121. }
  122. return some_id;
  123. }
  124. private void on_changed()
  125. {
  126. if (_inconsistent && this.get_active_id() == INCONSISTENT_ID)
  127. return;
  128. if (!_stop_emit) {
  129. if (_inconsistent) {
  130. _inconsistent = false;
  131. _filter.refilter();
  132. }
  133. value_changed();
  134. }
  135. }
  136. private bool on_scroll(Gdk.EventScroll ev)
  137. {
  138. GLib.Signal.stop_emission_by_name(this, "scroll-event");
  139. return Gdk.EVENT_PROPAGATE;
  140. }
  141. private void insert_special_values()
  142. {
  143. assert(_store.iter_n_children(null) == 0u);
  144. // Insert the "inconsistent" ID and label.
  145. Gtk.TreeIter iter;
  146. _store.insert_with_values(out iter, -1, 0, INCONSISTENT_ID, 1, INCONSISTENT_LABEL, -1);
  147. }
  148. }
  149. } /* namespace Crown */