11from __future__ import annotations
22
3- from typing import TYPE_CHECKING , Any
3+ from typing import TYPE_CHECKING , Any , cast
44
55from cmap import Colormap
6- from qtpy .QtCore import QSortFilterProxyModel , QStringListModel , Qt , Signal
6+ from qtpy .QtCore import (
7+ QEvent ,
8+ QObject ,
9+ QSortFilterProxyModel ,
10+ QStringListModel ,
11+ Qt ,
12+ Signal ,
13+ )
714from qtpy .QtWidgets import (
815 QButtonGroup ,
916 QCheckBox ,
1017 QComboBox ,
1118 QCompleter ,
1219 QDialog ,
1320 QDialogButtonBox ,
21+ QMenu ,
1422 QSizePolicy ,
1523 QVBoxLayout ,
1624 QWidget ,
2735 from collections .abc import Sequence
2836
2937 from cmap ._colormap import ColorStopsLike
30- from qtpy .QtGui import QKeyEvent
38+ from qtpy .QtGui import QKeyEvent , QMouseEvent
3139
3240
3341CMAP_ROLE = Qt .ItemDataRole .UserRole + 1
@@ -109,6 +117,10 @@ def __init__(
109117 self .currentIndexChanged .connect (self ._on_index_changed )
110118 line_edit .editingFinished .connect (self ._on_editing_finished )
111119
120+ # Enable right-click "Remove" on dropdown items
121+ if (view := self .view ()) and (viewport := view .viewport ()):
122+ viewport .installEventFilter (self )
123+
112124 def userAdditionsAllowed (self ) -> bool :
113125 """Returns whether the user can add custom colors."""
114126 return self ._allow_user_colors
@@ -204,7 +216,20 @@ def setCurrentColormap(self, color: Any) -> None:
204216
205217 for idx in range (self .count ()):
206218 if (item := self .itemColormap (idx )) and item .name == cmap .name :
219+ # cmap_ is already here - just select it
207220 self .setCurrentIndex (idx )
221+ return
222+
223+ # cmap not in the combo box yet — add it, then select it
224+ self .addColormap (cmap )
225+ idx = self .findData (cmap , CMAP_ROLE )
226+ if idx >= 0 :
227+ old_idx = self .currentIndex ()
228+ self .setCurrentIndex (idx )
229+ if idx == old_idx :
230+ # setCurrentIndex won't emit if the index didn't actually change
231+ # (e.g. first item added at index 0 when current index is already 0)
232+ self ._on_index_changed (idx )
208233
209234 def _on_activated (self , index : int ) -> None :
210235 if self .itemText (index ) != self ._add_color_text :
@@ -217,8 +242,7 @@ def _on_activated(self, index: int) -> None:
217242 if (item := self .itemColormap (i )) and cmap .name == item .name :
218243 self .setCurrentIndex (i )
219244 return
220- self .addColormap (cmap )
221- self .currentIndexChanged .emit (self .currentIndex ())
245+ self .setCurrentColormap (cmap )
222246 elif self ._last_cmap is not None :
223247 # user canceled, restore previous color without emitting signal
224248 idx = self .findData (self ._last_cmap , CMAP_ROLE )
@@ -257,6 +281,34 @@ def _on_editing_finished(self) -> None:
257281 if self .findData (cmap , CMAP_ROLE ) < 0 :
258282 self .addColormap (cmap )
259283
284+ def eventFilter (self , obj : QObject | None , event : QEvent | None ) -> bool :
285+ if event and event .type () == QEvent .Type .MouseButtonRelease :
286+ mouse_event = cast ("QMouseEvent" , event )
287+ if mouse_event .button () == Qt .MouseButton .RightButton :
288+ view = self .view ()
289+ if view and obj is view .viewport ():
290+ index = view .indexAt (mouse_event .pos ())
291+ if index .isValid ():
292+ text = self .itemText (index .row ())
293+ if text != self ._add_color_text :
294+ self ._show_remove_menu (view , mouse_event .pos (), index .row ())
295+ return True # consume the right-click
296+ return super ().eventFilter (obj , event )
297+
298+ def _show_remove_menu (self , view : Any , pos : Any , row : int ) -> None :
299+ menu = QMenu (view )
300+ remove_action = menu .addAction ("Remove" )
301+ if menu .exec (view .viewport ().mapToGlobal (pos )) == remove_action :
302+ was_current = row == self .currentIndex ()
303+ self .removeItem (row )
304+ self ._update_completer_model ()
305+ if was_current :
306+ # select the first actual colormap, skipping "Add Colormap..."
307+ for i in range (self .count ()):
308+ if self .itemColormap (i ) is not None :
309+ self .setCurrentIndex (i )
310+ return
311+
260312 def keyPressEvent (self , e : QKeyEvent | None ) -> None :
261313 if e and e .key () in (Qt .Key .Key_Enter , Qt .Key .Key_Return ):
262314 # select the first completion when pressing enter if the popup is visible
0 commit comments