blob: 9870e1603c05dcd50edf67fd1d49a765238baef9 [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import org.eclipse.swt.internal.photon.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
public /*final*/ class Tracker extends Widget {
Composite parent;
Display display;
boolean tracking, stippled;
Rectangle [] rectangles = new Rectangle [0];
public Tracker (Display display, int style) {
if (display == null) display = Display.getCurrent ();
if (display == null) display = Display.getDefault ();
if (!display.isValidThread ()) {
error (SWT.ERROR_THREAD_INVALID_ACCESS);
}
this.style = style;
this.display = display;
}
public Tracker (Composite parent, int style) {
super (parent, style);
this.parent = parent;
this.display = parent.getDisplay ();
}
public void addControlListener(ControlListener listener) {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener (listener);
addListener (SWT.Move,typedListener);
}
public void close () {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
tracking = false;
}
void drawRectangles () {
if (parent != null) {
if (parent.isDisposed ()) return;
parent.getShell ().update ();
} else {
display.update ();
}
int rid = OS.Ph_DEV_RID;
if (parent != null) rid = OS.PtWidgetRid (parent.handle);
int phGC = OS.PgCreateGC (0);
if (phGC == 0) return;
int prevContext = OS.PgSetGC (phGC);
OS.PgSetRegion (rid);
OS.PgSetDrawMode (OS.Pg_DRAWMODE_XOR);
OS.PgSetFillColor (0xffffff);
int bandWidth = 0;
if (stippled) {
bandWidth = 2;
OS.PgSetFillTransPat (OS.Pg_PAT_HALF);
}
for (int i=0; i<rectangles.length; i++) {
Rectangle r = rectangles [i];
int x1 = r.x;
int y1 = r.y;
int x2 = r.x + r.width;
int y2 = r.y + r.height;
OS.PgDrawIRect(x1, y1, x2, y1 + bandWidth, OS.Pg_DRAW_FILL);
OS.PgDrawIRect(x1, y1 + bandWidth + 1, x1 + bandWidth, y2 - bandWidth - 1, OS.Pg_DRAW_FILL);
OS.PgDrawIRect(x2 - bandWidth, y1 + bandWidth + 1, x2, y2 - bandWidth - 1, OS.Pg_DRAW_FILL);
OS.PgDrawIRect(x1, y2 - bandWidth, x2, y2, OS.Pg_DRAW_FILL);
}
OS.PgSetGC (prevContext);
OS.PgDestroyGC (phGC);
}
public Display getDisplay () {
return display;
}
public Rectangle [] getRectangles () {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
return rectangles;
}
public boolean getStippled () {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
return stippled;
}
public boolean open () {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
int sense = OS.Ph_EV_DRAG | OS.Ph_EV_KEY | OS.Ph_EV_BUT_PRESS |
OS.Ph_EV_BUT_RELEASE | OS.Ph_EV_PTR_MOTION;
int [] args = {
OS.Pt_ARG_WIDTH, 0, 0,
OS.Pt_ARG_HEIGHT, 0, 0,
OS.Pt_ARG_REGION_OPAQUE, 0, ~0,
OS.Pt_ARG_REGION_SENSE, sense, ~0,
OS.Pt_ARG_FILL_COLOR, OS.Pg_TRANSPARENT, 0,
};
OS.PtSetParentWidget (0);
int handle = OS.PtCreateWidget (OS.PtRegion (), 0, args.length / 3, args);
OS.PtRealizeWidget (handle);
PhRect_t rect = new PhRect_t ();
int rid = OS.PtWidgetRid (handle);
int input_group = OS.PhInputGroup (0);
OS.PhInitDrag (rid, OS.Ph_DRAG_KEY_MOTION | OS.Ph_TRACK_DRAG, rect, null, input_group, null, null, null, null, null);
PhCursorInfo_t info = new PhCursorInfo_t ();
OS.PhQueryCursor ((short)input_group, info);
int oldX = info.pos_x;
int oldY = info.pos_y;
int size = PhEvent_t.sizeof + 1024;
int buffer = OS.malloc (size);
PhEvent_t event = new PhEvent_t ();
Event ev = new Event ();
drawRectangles ();
boolean tracking = true;
boolean cancelled = false;
while (tracking && !cancelled) {
if (parent != null && parent.isDisposed ()) break;
int result = OS.PhEventNext (buffer, size);
switch (result) {
case OS.Ph_EVENT_MSG: break;
case OS.Ph_RESIZE_MSG:
size = OS.PhGetMsgSize (buffer);
OS.free (buffer);
buffer = OS.malloc (size);
continue;
}
OS.memmove (event, buffer, PhEvent_t.sizeof);
if (event.type == OS.Ph_EV_DRAG) {
switch (event.subtype) {
case OS.Ph_EV_DRAG_MOTION_EVENT: {
int data = OS.PhGetData (buffer);
if (data == 0) break;
PhPointerEvent_t pe = new PhPointerEvent_t ();
OS.memmove (pe, data, PhPointerEvent_t.sizeof);
int newX = pe.pos_x;
int newY = pe.pos_y;
if (newX != oldX || newY != oldY) {
drawRectangles ();
for (int i=0; i<rectangles.length; i++) {
rectangles [i].x += newX - oldX;
rectangles [i].y += newY - oldY;
}
/*
* It is possible (but unlikely), that application
* code could have disposed the widget in the move
* event. If this happens, return false to indicate
* that the tracking has failed.
*/
sendEvent (SWT.Move, ev);
if (isDisposed ()) return false;
drawRectangles ();
oldX = newX;
oldY = newY;
}
break;
}
case OS.Ph_EV_DRAG_KEY_EVENT: {
int data = OS.PhGetData (buffer);
if (data == 0) break;
PhKeyEvent_t ke = new PhKeyEvent_t ();
OS.memmove (ke, data, PhKeyEvent_t.sizeof);
if ((ke.key_flags & OS.Pk_KF_Sym_Valid) != 0) {
cancelled = ke.key_sym == OS.Pk_Escape;
}
break;
}
case OS.Ph_EV_DRAG_COMPLETE: {
tracking = false;
break;
}
}
}
OS.PtEventHandler (buffer);
}
drawRectangles ();
tracking = false;
OS.PtDestroyWidget (handle);
return !cancelled;
}
void releaseWidget () {
super.releaseWidget ();
parent = null;
display = null;
rectangles = null;
}
public void removeControlListener (ControlListener listener) {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (SWT.Move, listener);
}
public void setRectangles (Rectangle [] rectangles) {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
if (rectangles == null) error (SWT.ERROR_NULL_ARGUMENT);
this.rectangles = rectangles;
}
public void setStippled (boolean stippled) {
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED);
this.stippled = stippled;
}
}