99 *******************************************************************************/
1010package org .csstudio .opibuilder .widgets .editparts ;
1111
12- import static org .csstudio .opibuilder .model .AbstractWidgetModel .PROP_BORDER_STYLE ;
13- import static org .csstudio .opibuilder .model .AbstractWidgetModel .PROP_BORDER_WIDTH ;
14- import static org .csstudio .opibuilder .model .AbstractWidgetModel .PROP_FONT ;
15- import static org .csstudio .opibuilder .model .AbstractWidgetModel .PROP_HEIGHT ;
16- import static org .csstudio .opibuilder .model .AbstractWidgetModel .PROP_WIDTH ;
1712import static org .csstudio .opibuilder .model .IPVWidgetModel .PROP_PVNAME ;
1813import static org .csstudio .opibuilder .model .IPVWidgetModel .PROP_PVVALUE ;
1914import static org .csstudio .opibuilder .widgets .model .ComboModel .PROP_ITEMS ;
2015import static org .csstudio .opibuilder .widgets .model .ComboModel .PROP_ITEMS_FROM_PV ;
2116
17+ import java .util .ArrayList ;
2218import java .util .List ;
2319
2420import org .csstudio .opibuilder .editparts .AbstractPVWidgetEditPart ;
2521import org .csstudio .opibuilder .editparts .ExecutionMode ;
2622import org .csstudio .opibuilder .properties .IWidgetPropertyChangeHandler ;
2723import org .csstudio .opibuilder .widgets .figures .ComboFigure ;
2824import org .csstudio .opibuilder .widgets .model .ComboModel ;
25+ import org .csstudio .swt .widgets .util .GraphicsUtil ;
26+ import org .csstudio .ui .util .CustomMediaFactory ;
2927import org .eclipse .draw2d .IFigure ;
30- import org .eclipse .swt .events .SelectionAdapter ;
31- import org .eclipse .swt .events .SelectionEvent ;
32- import org .eclipse .swt .events .SelectionListener ;
33- import org .eclipse .swt .widgets .Combo ;
28+ import org .eclipse .draw2d .MouseEvent ;
29+ import org .eclipse .draw2d .MouseListener ;
30+ import org .eclipse .draw2d .MouseMotionListener ;
31+ import org .eclipse .draw2d .geometry .Point ;
32+ import org .eclipse .jface .action .Action ;
33+ import org .eclipse .jface .action .MenuManager ;
34+ import org .eclipse .swt .graphics .RGB ;
35+ import org .eclipse .swt .widgets .Display ;
36+ import org .eclipse .ui .PlatformUI ;
3437import org .yamcs .studio .data .IPV ;
3538import org .yamcs .studio .data .IPVListener ;
3639import org .yamcs .studio .data .VTypeHelper ;
@@ -42,46 +45,71 @@ public final class ComboEditPart extends AbstractPVWidgetEditPart {
4245
4346 private IPVListener loadItemsFromPVListener ;
4447
45- private Combo combo ;
46- private SelectionListener comboSelectionListener ;
48+ private List <String > items = new ArrayList <>();
4749
4850 @ Override
4951 protected IFigure doCreateFigure () {
5052 var model = getWidgetModel ();
5153 updatePropSheet (model .isItemsFromPV ());
52- var comboFigure = new ComboFigure (this );
53- combo = comboFigure .getSWTWidget ();
54+ var comboFigure = new ComboFigure ();
5455
5556 var items = getWidgetModel ().getItems ();
56-
5757 updateCombo (items );
5858
59- markAsControlPV (PROP_PVNAME , PROP_PVVALUE );
59+ if (getExecutionMode () == ExecutionMode .RUN_MODE ) {
60+ comboFigure .addMouseListener (new MouseListener () {
61+ @ Override
62+ public void mouseDoubleClicked (MouseEvent me ) {
63+ }
6064
61- return comboFigure ;
62- }
65+ @ Override
66+ public void mousePressed (MouseEvent me ) {
67+ if (me .button == 1 && comboFigure .containsPoint (me .getLocation ())) {
68+ me .consume ();
69+ }
70+ }
6371
64- private void updateCombo (List <String > items ) {
65- if (items != null && getExecutionMode () == ExecutionMode .RUN_MODE ) {
66- combo .removeAll ();
72+ @ Override
73+ public void mouseReleased (MouseEvent me ) {
74+ // Check location to ignore bogus mouse clicks,
75+ // see https://github.com/ControlSystemStudio/cs-studio/issues/1818
76+ if (me .button == 1 && getExecutionMode ().equals (ExecutionMode .RUN_MODE )
77+ && comboFigure .containsPoint (me .getLocation ())) {
78+ var cursorLocation = Display .getCurrent ().getCursorLocation ();
79+ showMenu (me .getLocation (), cursorLocation .x , cursorLocation .y );
80+ }
81+ }
6782
68- for (var item : items ) {
69- combo .add (item );
83+ });
84+ }
85+ comboFigure .addMouseMotionListener (new MouseMotionListener .Stub () {
86+ @ Override
87+ public void mouseEntered (MouseEvent me ) {
88+ if (getExecutionMode ().equals (ExecutionMode .RUN_MODE )) {
89+ var backColor = comboFigure .getBackgroundColor ();
90+ var darkColor = GraphicsUtil .mixColors (backColor .getRGB (), new RGB (0 , 0 , 0 ), 0.9 );
91+ comboFigure .setBackgroundColor (CustomMediaFactory .getInstance ().getColor (darkColor ));
92+ }
7093 }
7194
72- // write value to pv if pv name is not empty
73- if (getWidgetModel ().getPVName ().trim ().length () > 0 ) {
74- if (comboSelectionListener != null ) {
75- combo .removeSelectionListener (comboSelectionListener );
95+ @ Override
96+ public void mouseExited (MouseEvent me ) {
97+ if (getExecutionMode ().equals (ExecutionMode .RUN_MODE )) {
98+ comboFigure .setBackgroundColor (
99+ CustomMediaFactory .getInstance ().getColor (getWidgetModel ().getBackgroundColor ()));
76100 }
77- comboSelectionListener = new SelectionAdapter () {
78- @ Override
79- public void widgetSelected (SelectionEvent e ) {
80- setPVValue (PROP_PVNAME , combo .getText ());
81- }
82- };
83- combo .addSelectionListener (comboSelectionListener );
84101 }
102+ });
103+
104+ markAsControlPV (PROP_PVNAME , PROP_PVVALUE );
105+
106+ return comboFigure ;
107+ }
108+
109+ private void updateCombo (List <String > items ) {
110+ if (items != null && getExecutionMode () == ExecutionMode .RUN_MODE ) {
111+ this .items .clear ();
112+ this .items .addAll (items );
85113 }
86114 }
87115
@@ -90,6 +118,45 @@ public ComboModel getWidgetModel() {
90118 return (ComboModel ) getModel ();
91119 }
92120
121+ private ComboFigure getComboFigure () {
122+ return (ComboFigure ) getFigure ();
123+ }
124+
125+ /**
126+ * Show Menu
127+ *
128+ * @param point
129+ * the location of the mouse-event in the OPI display
130+ * @param absolutX
131+ * The x coordinate of the mouse on the monitor
132+ * @param absolutY
133+ * The y coordinate of the mouse on the monitor
134+ */
135+ private void showMenu (Point point , int absolutX , int absolutY ) {
136+ if (getExecutionMode ().equals (ExecutionMode .RUN_MODE )) {
137+ var shell = PlatformUI .getWorkbench ().getActiveWorkbenchWindow ().getShell ();
138+ var menuManager = new MenuManager ();
139+ for (var item : items ) {
140+ menuManager .add (new SelectItemAction (item ));
141+ }
142+ var menu = menuManager .createContextMenu (shell );
143+
144+ /*
145+ * We need to position the menu in absolute monitor coordinates.
146+ * First we calculate the coordinates of the display, then add the
147+ * widget coordinates to these so that the menu opens on the
148+ * bottom left of the widget.
149+ */
150+ var x = absolutX - point .x ;
151+ var y = absolutY - point .y ;
152+ x += getWidgetModel ().getLocation ().x ;
153+ y += getWidgetModel ().getLocation ().y + getWidgetModel ().getSize ().height ;
154+
155+ menu .setLocation (x , y );
156+ menu .setVisible (true );
157+ }
158+ }
159+
93160 @ Override
94161 protected void doActivate () {
95162 super .doActivate ();
@@ -129,7 +196,6 @@ protected void doDeActivate() {
129196 pv .removeListener (loadItemsFromPVListener );
130197 }
131198 }
132- // ((ComboFigure)getFigure()).dispose();
133199 }
134200
135201 @ Override
@@ -140,14 +206,12 @@ protected void registerPropertyChangeHandlers() {
140206 return false ;
141207 });
142208
143- autoSizeWidget ((ComboFigure ) getFigure ());
144-
145209 setPropertyChangeHandler (PROP_PVVALUE , (oldValue , newValue , refreshableFigure ) -> {
146210 if (newValue != null ) {
147211 var stringValue = VTypeHelper .getString ((VType ) newValue );
148212
149213 String matchingItem = null ;
150- for (var item : combo . getItems () ) {
214+ for (var item : items ) {
151215 if (item .equals (stringValue )) {
152216 matchingItem = item ;
153217 break ;
@@ -172,9 +236,9 @@ protected void registerPropertyChangeHandlers() {
172236 }
173237
174238 if (matchingItem != null ) {
175- combo .setText (matchingItem );
239+ getComboFigure () .setText (matchingItem );
176240 } else {
177- combo . deselectAll ( );
241+ getComboFigure (). setText ( null );
178242 }
179243 }
180244
@@ -185,7 +249,7 @@ protected void registerPropertyChangeHandlers() {
185249 if (newValue != null && newValue instanceof List ) {
186250 updateCombo ((List <String >) newValue );
187251 if (getWidgetModel ().isItemsFromPV ()) {
188- combo .setText (VTypeHelper .getString (getPVValue (PROP_PVNAME )));
252+ getComboFigure () .setText (VTypeHelper .getString (getPVValue (PROP_PVNAME )));
189253 }
190254 }
191255 return true ;
@@ -197,41 +261,49 @@ protected void registerPropertyChangeHandlers() {
197261 };
198262 getWidgetModel ().getProperty (PROP_ITEMS_FROM_PV ).addPropertyChangeListener (
199263 evt -> handler .handleChange (evt .getOldValue (), evt .getNewValue (), getFigure ()));
200-
201- // size change handlers--always apply the default height
202- IWidgetPropertyChangeHandler handle = (oldValue , newValue , figure ) -> {
203- autoSizeWidget ((ComboFigure ) figure );
204- return true ;
205- };
206- setPropertyChangeHandler (PROP_WIDTH , handle );
207- setPropertyChangeHandler (PROP_HEIGHT , handle );
208- setPropertyChangeHandler (PROP_BORDER_STYLE , handle );
209- setPropertyChangeHandler (PROP_BORDER_WIDTH , handle );
210- setPropertyChangeHandler (PROP_FONT , handle );
211264 }
212265
213266 private void updatePropSheet (boolean itemsFromPV ) {
214267 getWidgetModel ().setPropertyVisible (PROP_ITEMS , !itemsFromPV );
215268 }
216269
217- private void autoSizeWidget (ComboFigure comboFigure ) {
218- var d = comboFigure .getAutoSizeDimension ();
219- getWidgetModel ().setSize (getWidgetModel ().getWidth (), d .height );
220- }
221-
222270 @ Override
223271 public String getValue () {
224- return combo .getText ();
272+ return getComboFigure () .getText ();
225273 }
226274
227275 @ Override
228276 public void setValue (Object value ) {
229277 if (value instanceof String ) {
230- combo .setText ((String ) value );
278+ getComboFigure () .setText ((String ) value );
231279 } else if (value instanceof Number ) {
232- combo .select (((Number ) value ).intValue ());
280+ var idx = ((Number ) value ).intValue ();
281+ if (idx >= 0 && idx <= items .size () - 1 ) {
282+ var item = items .get (idx );
283+ getComboFigure ().setText (item );
284+ }
233285 } else {
234286 super .setValue (value );
235287 }
236288 }
289+
290+ private class SelectItemAction extends Action {
291+
292+ private String item ;
293+
294+ SelectItemAction (String item ) {
295+ this .item = item ;
296+ setText (item );
297+ }
298+
299+ @ Override
300+ public void run () {
301+ getComboFigure ().setText (item );
302+
303+ // Write value to pv if pv name is not empty
304+ if (getWidgetModel ().getPVName ().trim ().length () > 0 ) {
305+ setPVValue (PROP_PVNAME , item );
306+ }
307+ }
308+ }
237309}
0 commit comments