001package org.vishia.gral.swt; 002 003import org.eclipse.swt.SWT; 004import org.eclipse.swt.events.MouseEvent; 005import org.eclipse.swt.events.MouseListener; 006import org.eclipse.swt.events.MouseMoveListener; 007import org.eclipse.swt.graphics.Color; 008import org.eclipse.swt.graphics.Point; 009import org.eclipse.swt.widgets.Control; 010import org.eclipse.swt.widgets.Widget; 011import org.vishia.gral.base.GralWidget; 012import org.vishia.gral.base.GralMng; 013import org.vishia.gral.base.GralMouseWidgetAction_ifc; 014import org.vishia.gral.ifc.GralRectangle; 015import org.vishia.gral.ifc.GralUserAction; 016import org.vishia.gral.ifc.GralWidget_ifc; 017import org.vishia.util.Assert; 018import org.vishia.util.KeyCode; 019 020/**This class contains implementations of {@link MouseListener} for Gral adaption of SWT. 021 * The static inner classes implements the MouseListener 022 * @author Hartmut Schorrig 023 * 024 */ 025public final class SwtGralMouseListener 026{ 027 /**Version, History and copyright 028 * <ul> 029 * <li>2015-09-21 Hartmut chg: The capabilities of {@link MouseListenerNoAction} is contained in {@link MouseListenerGralAction} yet. 030 * Therefore it is possible to get a mouse action in any {@link GralWidget#setActionChange(GralUserAction)}. 031 * <li>2014-09-21 Hartmut chg: Using of {@link GralWidget#toString()} for double click info. 032 * <li>2013-05-13 Hartmut chg: All methods of {@link GralMouseWidgetAction_ifc} changed, parameter key, position. 033 * <li>2012-10-10 Hartmut the keycode for mouse pressed user actions contains pressing ctrl, alt, sh too. 034 * <li>2012-03-09 Hartmut The methods {@link GralMouseWidgetAction_ifc#mouse1Up()} etc. are not called 035 * if the cursor was removed from the widget. 036 * </ul> 037 * 038 * <b>Copyright/Copyleft</b>:<br> 039 * For this source the LGPL Lesser General Public License, 040 * published by the Free Software Foundation is valid. 041 * It means: 042 * <ol> 043 * <li> You can use this source without any restriction for any desired purpose. 044 * <li> You can redistribute copies of this source to everybody. 045 * <li> Every user of this source, also the user of redistribute copies 046 * with or without payment, must accept this license for further using. 047 * <li> But the LPGL is not appropriate for a whole software product, 048 * if this source is only a part of them. It means, the user 049 * must publish this part of source, 050 * but doesn't need to publish the whole source of the own product. 051 * <li> You can study and modify (improve) this source 052 * for own using or for redistribution, but you have to license the 053 * modified sources likewise under this LGPL Lesser General Public License. 054 * You mustn't delete this Copyright/Copyleft inscription in this source file. 055 * </ol> 056 * If you intent to use this source without publishing its usage, you can get 057 * a second license subscribing a special contract with the author. 058 * 059 * @author Hartmut Schorrig = hartmut.schorrig@vishia.de 060 */ 061 public static final int version = 20120309; 062 063 064 /**This class implements a MouseListener which does not call a user method. 065 * Only the information about the clicked widget are stored in the GralMng 066 * and the Gral designer is supported. 067 * 068 */ 069 private static class MouseListenerNoAction implements MouseListener 070 { 071 072 073 public MouseListenerNoAction() 074 { 075 } 076 077 int xDown, yDown; 078 079 /**The mouse doubleclick is left empty. It may be overridden by an derived class. */ 080 @Override public void mouseDoubleClick(MouseEvent arg0) 081 { 082 Widget widget = arg0.widget; 083 Object oInfo = widget.getData(); 084 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(oInfo); 085 if(widgg !=null){ 086 GralMng guiMng = widgg.gralMng(); 087 try{ 088 String widggInfo = widgg.toString(); 089 guiMng.log.sendMsg(0, "Info widget: %s", widggInfo); 090 //guiMng.log.sendMsg(0, "Info widget: %s / %s", widgg.name, widgg.getDataPath()); 091 } catch(Exception exc){ guiMng.writeLog(0, exc); } 092 093 } 094 095 } 096 097 /**The mouse-down action save some informations about the widget. 098 * It may be overridden by an derived class, then this method should be invoked within. 099 */ 100 @Override public void mouseDown(MouseEvent ev) 101 { 102 Widget widget = ev.widget; 103 Object oInfo = widget.getData(); 104 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(oInfo); 105 if(widgg !=null){ 106 GralMng guiMng = widgg.gralMng(); 107 try{ 108 String sDataPath = widgg.getDataPath(); 109 if( sDataPath !=null //no datapath given, write info! 110 && !sDataPath.equals("widgetInfo") //don't write info if it is a widgetInfo widget itself. 111 ){ 112 guiMng.setLastClickedWidget(widgg ); 113 } 114 if(guiMng.bDesignMode){ 115 GralRectangle rr = new GralRectangle(ev.x, ev.y, 0, 0); 116 if(ev.button == 1){ //left 117 xDown = ev.x; yDown = ev.y; 118 guiMng.pressedLeftMouseDownForDesign(widgg, rr); 119 } else if(ev.button == 3){ //right 120 //guiMng.pressedRightMouseDownForDesign(widgetInfo, rr); 121 } 122 } 123 } catch(Exception exc){ guiMng.writeLog(0, exc); } 124 125 } 126 127 } 128 129 /**The default behavior for mouse up is used for design mode. */ 130 @Override public void mouseUp(MouseEvent ev) 131 { Widget widget = ev.widget; 132 Object oInfo = widget.getData(); 133 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(oInfo); 134 if(widgg !=null){ 135 GralMng guiMng = widgg.gralMng(); 136 try{ 137 int dx = ev.x - xDown, dy = ev.y - yDown; 138 if(guiMng.bDesignMode && ev.button == 1){ 139 if((ev.stateMask & SWT.ALT)!=0){ 140 boolean bCopy = (ev.stateMask & org.eclipse.swt.SWT.CTRL) !=0; 141 GralRectangle rr = new GralRectangle(ev.x, ev.y, 0, 0); 142 guiMng.releaseLeftMouseForDesign(widgg, rr, bCopy); 143 } else { 144 guiMng.markWidgetForDesign(widgg); 145 } 146 } 147 //widgd.redraw(); 148 } catch(Exception exc){ guiMng.writeLog(0, exc); } 149 150 } 151 152 } 153 154 155 private final MouseMoveListener mouseMoveListenerDesignMode = new MouseMoveListener() 156 { 157 158 @Override public void mouseMove(MouseEvent e) 159 { 160 //xMouse = e.x; 161 //yMouse = e.y; 162 }//method mouseMove 163 }; 164 165 166 167 } 168 169 170 171 172 173 174 /**This class is the implementation of a SWT {@link MouseListener} and implements methods which invokes the 175 * {@link GralWidget#setActionMouse(GralMouseWidgetAction_ifc, int)} or the {@link GralWidget#setActionChange(GralUserAction)} 176 * on the determined mouse clicks. 177 * @author Hartmut Schorrig 178 * 179 */ 180 public static class MouseListenerGralAction extends MouseListenerNoAction 181 implements MouseListener 182 { 183 184 /**Positions saved on mouse press, to detect whether the mouse-release occurs in the pressed area. 185 * If the mouse-position is shifted outside the area of the widget, the mouse-release-user-action 186 * is not executed. 187 */ 188 private int xMousePress, yMousePress; 189 190 /**Used in the implementation level for the paint routine. Therefore it is package private. 191 */ 192 protected boolean isPressed; 193 194 195 196 /**Constructor. 197 * @param mouseWidgetAction Action invoked, maybe null 198 * @param mUser 0 or or-combinations of bits in {@link GralMouseWidgetAction_ifc#mUser1down} 199 * and all other mUser... If one of this bits is set, the {@link GralWidget#setActionChange(GralUserAction)} 200 * is invoked on the appropriate mouse action after and independent of the mouseWidgetAction. 201 */ 202 public MouseListenerGralAction() 203 { super(); 204 } 205 206 207 208 @Override 209 public void mouseDoubleClick(MouseEvent e) { 210 xMousePress = e.x; 211 yMousePress = e.y; 212 Control widget = (Control) e.widget; //a widget is a Control always. 213 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(widget.getData()); 214 try{ 215 String widggInfo = widgg.toString(); 216 GralMng.get().log.sendMsg(0, "Info widget: %s", widggInfo); 217 //guiMng.log.sendMsg(0, "Info widget: %s / %s", widgg.name, widgg.getDataPath()); 218 } catch(Exception exc){ GralMng.get().writeLog(0, exc); } 219 try{ 220 final int keyCode = SwtGralKey.convertMouseKey(e.button, SwtGralKey.MouseAction.doubleClick, e.stateMask); 221 Control widgetSwt = (Control) e.widget; //a widget is a Control always. 222 if(widgg.cfg.mouseWidgetAction !=null){ 223 Point size = widgetSwt.getSize(); 224 widgg.cfg.mouseWidgetAction.mouse1Double(keyCode, xMousePress, yMousePress, size.x, size.y, widgg); 225 } 226 boolean bStrict = (widgg.cfg.mMouseToActionChange & GralMouseWidgetAction_ifc.mUserDouble) ==0; //search strict if no special bit is given. 227 //then a strict mouse doube action wins. 228 GralWidget_ifc.ActionChange action = widgg.getActionChangeStrict(GralWidget_ifc.ActionChangeWhen.onMouse1Double, bStrict); 229 if(action !=null){ 230 Object[] args = action.args(); 231 if(args == null){ action.action().exec(KeyCode.mouse1Double, widgg, new Integer(e.x), new Integer(e.y)); } 232 else { 233 //additional 2 arguments: copy in one args2. 234 Object[] args2 = new Object[args.length +2]; 235 System.arraycopy(args, 0, args2, 0, args.length); 236 args2[args.length] = new Integer(e.x); 237 args2[args.length+1] = new Integer(e.y); 238 action.action().exec(KeyCode.mouse1Double, widgg, args2); 239 } 240 } 241 } catch(Exception exc){ System.err.printf("SwtGralMouseListener - any exception while mouse double; %s\n", exc.getMessage()); } 242 } 243 244 @Override public void mouseDown(MouseEvent ev) { 245 super.mouseDown(ev); 246 isPressed = true; 247 xMousePress = ev.x; 248 yMousePress = ev.y; 249 Control widget = (Control) ev.widget; //a widget is a Control always. 250 widget.addMouseMoveListener(mouseMoveListener); 251 Object owdgg = widget.getData(); 252 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(owdgg); 253 GralMng guiMng = widgg.gralMng(); 254 try{ 255 String sDataPath = widgg.getDataPath(); 256 if( sDataPath !=null //no datapath given, write info! 257 && !sDataPath.equals("widgetInfo") //don't write info if it is a widgetInfo widget itself. 258 ){ 259 guiMng.setLastClickedWidget(widgg ); 260 } 261 if(guiMng.bDesignMode){ 262 GralRectangle rr = new GralRectangle(ev.x, ev.y, 0, 0); 263 if(ev.button == 1){ //left 264 xDown = ev.x; yDown = ev.y; 265 guiMng.pressedLeftMouseDownForDesign(widgg, rr); 266 } else if(ev.button == 3){ //right 267 //guiMng.pressedRightMouseDownForDesign(widgetInfo, rr); 268 } 269 } 270 } catch(Exception exc){ guiMng.writeLog(0, exc); } 271 try{ 272 final int keyCode = SwtGralKey.convertMouseKey(ev.button, SwtGralKey.MouseAction.down, ev.stateMask); 273 GralWidget_ifc.ActionChangeWhen whenAction; 274 final int mUser1; 275 switch(ev.button){ 276 case 1: mUser1 = GralMouseWidgetAction_ifc.mUser1down; whenAction = GralWidget_ifc.ActionChangeWhen.onMouse1Dn; break; 277 case 3: mUser1 = GralMouseWidgetAction_ifc.mUser2down; whenAction = null; break; //the usual right button is 3 in SWT! 278 case 2: mUser1 = GralMouseWidgetAction_ifc.mUser3down; whenAction = null; break; //the usual middle button is 2 in SWT! 279 default: mUser1 = 0; whenAction = null; break; 280 }//switch: 281 if(widgg.cfg.mouseWidgetAction !=null){ 282 Point size = widget.getSize(); 283 switch(ev.button){ 284 case 1: 285 widgg.cfg.mouseWidgetAction.mouse1Down(keyCode, xMousePress, yMousePress, size.x, size.y, widgg); 286 break; 287 case 3: 288 widgg.cfg.mouseWidgetAction.mouse2Down(keyCode, xMousePress, yMousePress, size.x, size.y, widgg); 289 break; 290 } 291 } 292 GralWidget_ifc.ActionChange action = widgg.getActionChangeStrict(whenAction, true); 293 if(action !=null){ 294 Object[] args = action.args(); 295 if(args == null){ action.action().exec(keyCode, widgg, new Integer(ev.x), new Integer(ev.y)); } 296 else { 297 //additional 2 arguments: copy in one args2. 298 Object[] args2 = new Object[args.length +2]; 299 System.arraycopy(args, 0, args2, 0, args.length); 300 args2[args.length] = new Integer(ev.x); 301 args2[args.length+1] = new Integer(ev.y); 302 action.action().exec(keyCode, widgg, args2); 303 } 304 } 305 } catch(Exception exc){ System.err.printf("SwtGralMouseListener - any exception while mouse down; %s\n", exc.getMessage()); } 306 } 307 308 309 310 311 @Override public void mouseUp(MouseEvent ev) { 312 //set the background color to the originally value again if it was changed. 313 super.mouseUp(ev); 314 if(isPressed){ //prevent any action of mouse up if the mouse is not designated as pressed 315 //especially if the mouse was removed from the widget. 316 Control widget = (Control)ev.widget; 317 widget.removeMouseMoveListener(mouseMoveListener); 318 isPressed = false; 319 Point size = widget.getSize(); 320 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(widget.getData()); 321 final int mUser1; 322 GralWidget_ifc.ActionChangeWhen whenAction; 323 switch(ev.button){ 324 case 1: mUser1 = GralMouseWidgetAction_ifc.mUser1up; whenAction = GralWidget_ifc.ActionChangeWhen.onMouse1Up; break; 325 case 3: mUser1 = GralMouseWidgetAction_ifc.mUser2up; whenAction = GralWidget_ifc.ActionChangeWhen.onMouse2Up; break; //the usual right button is 3 in SWT! 326 case 2: mUser1 = GralMouseWidgetAction_ifc.mUser3up; whenAction = null; break; //the usual middle button is 2 in SWT! 327 default: mUser1 = 0; whenAction = null; break; 328 }//switch: 329 try{ 330 //int dx = e.x - xMousePress, dy = e.y - yMousePress; 331 boolean moved = ev.x < 0 || ev.x > size.x || ev.y < 0 || ev.y > size.y; 332 SwtGralKey.MouseAction mouseAction = moved ? SwtGralKey.MouseAction.upMovedOutside : SwtGralKey.MouseAction.up; 333 final int keyCode = SwtGralKey.convertMouseKey(ev.button, mouseAction, ev.stateMask); 334 GralMng guiMng = widgg.gralMng(); 335 int dx = ev.x - xDown, dy = ev.y - yDown; 336 if(guiMng.bDesignMode && ev.button == 1){ 337 if((ev.stateMask & SWT.ALT)!=0){ 338 boolean bCopy = (ev.stateMask & org.eclipse.swt.SWT.CTRL) !=0; 339 GralRectangle rr = new GralRectangle(ev.x, ev.y, 0, 0); 340 guiMng.releaseLeftMouseForDesign(widgg, rr, bCopy); 341 } else { 342 guiMng.markWidgetForDesign(widgg); 343 } 344 } 345 //widgd.redraw(); 346 347 if(widgg.cfg.mouseWidgetAction !=null){ 348 switch(ev.button){ 349 case 1: 350 widgg.cfg.mouseWidgetAction.mouse1Up(keyCode, ev.x, ev.y, size.x, size.y, widgg); 351 break; 352 case 3: 353 widgg.cfg.mouseWidgetAction.mouse2Up(keyCode, ev.x, ev.y, size.x, size.y, widgg); 354 break; 355 } 356 } 357 GralWidget_ifc.ActionChange action = widgg.getActionChangeStrict(whenAction, (widgg.cfg.mMouseToActionChange & mUser1) !=0); 358 if(action !=null){ 359 Object[] args = action.args(); 360 if(args == null){ action.action().exec(keyCode, widgg, new Integer(ev.x), new Integer(ev.y)); } 361 else { 362 //additional 2 arguments: copy in one args2. 363 Object[] args2 = new Object[args.length +2]; 364 System.arraycopy(args, 0, args2, 0, args.length); 365 args2[args.length] = new Integer(ev.x); 366 args2[args.length+1] = new Integer(ev.y); 367 action.action().exec(keyCode, widgg, args2); 368 } 369 } 370 } catch(Exception exc){ 371 CharSequence text = Assert.exceptionInfo("SwtGralMouseListener - any exception while mouse down;", exc, 0, 20); 372 //System.err.append(text).append('\n'); 373 System.err.printf(text.toString()); 374 } 375 } 376 } 377 378 379 380 381 /**TODO invoke user action if mouse releases the area 382 * 383 */ 384 protected MouseMoveListener mouseMoveListener = new MouseMoveListener() 385 { 386 387 @Override public void mouseMove(MouseEvent e) 388 { 389 if(e.widget instanceof Control){ 390 Control widget = (Control)e.widget; 391 GralWidget widgg = GralWidget.ImplAccess.gralWidgetFromImplData(widget.getData()); 392 Point size = widget.getSize(); 393 if(widgg.cfg.mouseWidgetAction !=null){ 394 if(!widgg.cfg.mouseWidgetAction.mouseMoved(e.x, e.y, size.x, size.y)){ 395 isPressed = false; 396 widget.removeMouseMoveListener(mouseMoveListener); 397 } 398 //mouseWidgetAction.removeMouseCursorFromWidgetWhilePressed(); 399 } 400 } 401 }//method mouseMove 402 }; 403 404 405 } 406 407 408 409 /**The only one instance can used for all widgets because the working data are given with the mouse action methods. 410 * The associated GralWidget data are accessed via the data field (the GralWidget is known in all Widget implementations). 411 */ 412 protected static MouseListener mouseActionStd = new MouseListenerGralAction(); 413 414}