Bug 577878 - [GTK] Table/Tree with SWT.PaintItem don't show rows when
dragging them
In first version of the patch, I overlooked the case where a column
contains multiple renderers. For example, when '.setImage()' was used.
Change-Id: I50c7171811737057e5d1b70b8a2a0b7ce229c998
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/192203
Tested-by: Andrey Loskutov <loskutov@gmx.de>
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
index 35a1834..0f41e63 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
@@ -2962,8 +2962,28 @@
}
}
- GdkRectangle backround_area_rect = new GdkRectangle ();
- OS.memmove (backround_area_rect, background_area, GdkRectangle.sizeof);
+ GdkRectangle rendererRect = new GdkRectangle ();
+ GdkRectangle columnRect = new GdkRectangle ();
+ {
+ /*
+ * SWT creates multiple renderers (kind of sub-columns) per column.
+ * For example: one for checkbox, one for image, one for text.
+ * 'background_area' argument in this function is area of currently
+ * painted renderer. However, for SWT.EraseItem and SWT.PaintItem,
+ * SWT wants entire column's area along with the event. There's api
+ * 'gtk_tree_view_get_background_area()' but it calculates item's
+ * rect in control, which will be have wrong Y if item is rendered
+ * separately (for example, for drag image).
+ * The workaround is to take X range from api and Y range from argument.
+ */
+ OS.memmove (rendererRect, background_area, GdkRectangle.sizeof);
+
+ long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
+ GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, columnRect);
+ GTK.gtk_tree_path_free (path);
+
+ columnRect.y = rendererRect.y;
+ }
if (item != null) {
if (GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell) || (columnIndex != 0 || (style & SWT.CHECK) == 0)) {
@@ -2984,7 +3004,7 @@
if ((flags & GTK.GTK_CELL_RENDERER_FOCUSED) != 0) drawState |= SWT.FOCUSED;
}
- Rectangle rect = backround_area_rect.toRectangle ();
+ Rectangle rect = columnRect.toRectangle ();
if ((drawState & SWT.SELECTED) == 0) {
if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
Control control = findBackgroundControl ();
@@ -3075,7 +3095,7 @@
if ((drawState & SWT.BACKGROUND) != 0 && (drawState & SWT.SELECTED) == 0) {
GC gc = getGC(cr);
gc.setBackground (item.getBackground (columnIndex));
- gc.fillRectangle (DPIUtil.autoScaleDown (backround_area_rect.toRectangle ()));
+ gc.fillRectangle (DPIUtil.autoScaleDown (rendererRect.toRectangle ()));
gc.dispose ();
}
if ((drawState & SWT.FOREGROUND) != 0 || GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell)) {
@@ -3101,7 +3121,7 @@
if (GTK.GTK_IS_CELL_RENDERER_TEXT (cell)) {
if (hooks (SWT.PaintItem)) {
if (wasSelected) drawState |= SWT.SELECTED;
- Rectangle rect = backround_area_rect.toRectangle ();
+ Rectangle rect = columnRect.toRectangle ();
ignoreSize = true;
int [] contentX = new int [1], contentWidth = new int [1];
gtk_cell_renderer_get_preferred_size (cell, handle, contentWidth, null);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
index a5fda90..215f2ee 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
@@ -3169,8 +3169,28 @@
}
}
- GdkRectangle backround_area_rect = new GdkRectangle ();
- OS.memmove (backround_area_rect, background_area, GdkRectangle.sizeof);
+ GdkRectangle rendererRect = new GdkRectangle ();
+ GdkRectangle columnRect = new GdkRectangle ();
+ {
+ /*
+ * SWT creates multiple renderers (kind of sub-columns) per column.
+ * For example: one for checkbox, one for image, one for text.
+ * 'background_area' argument in this function is area of currently
+ * painted renderer. However, for SWT.EraseItem and SWT.PaintItem,
+ * SWT wants entire column's area along with the event. There's api
+ * 'gtk_tree_view_get_background_area()' but it calculates item's
+ * rect in control, which will be have wrong Y if item is rendered
+ * separately (for example, for drag image).
+ * The workaround is to take X range from api and Y range from argument.
+ */
+ OS.memmove (rendererRect, background_area, GdkRectangle.sizeof);
+
+ long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
+ GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, columnRect);
+ GTK.gtk_tree_path_free (path);
+
+ columnRect.y = rendererRect.y;
+ }
if (item != null) {
if (GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell) || ( columnIndex != 0 || (style & SWT.CHECK) == 0)) {
@@ -3191,7 +3211,7 @@
if ((flags & GTK.GTK_CELL_RENDERER_FOCUSED) != 0) drawState |= SWT.FOCUSED;
}
- Rectangle rect = backround_area_rect.toRectangle ();
+ Rectangle rect = columnRect.toRectangle ();
// Use the x and width information from the Cairo context. See bug 535124.
if (cr != 0) {
GdkRectangle r2 = new GdkRectangle ();
@@ -3278,7 +3298,7 @@
if ((drawState & SWT.BACKGROUND) != 0 && (drawState & SWT.SELECTED) == 0) {
GC gc = getGC(cr);
gc.setBackground (item.getBackground (columnIndex));
- gc.fillRectangle (DPIUtil.autoScaleDown (backround_area_rect.toRectangle ()));
+ gc.fillRectangle (DPIUtil.autoScaleDown (rendererRect.toRectangle ()));
gc.dispose ();
}
if ((drawState & SWT.FOREGROUND) != 0 || GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell)) {
@@ -3304,7 +3324,7 @@
if (GTK.GTK_IS_CELL_RENDERER_TEXT (cell)) {
if (hooks (SWT.PaintItem)) {
if (wasSelected) drawState |= SWT.SELECTED;
- Rectangle rect = backround_area_rect.toRectangle ();
+ Rectangle rect = columnRect.toRectangle ();
ignoreSize = true;
int [] contentX = new int [1], contentWidth = new int [1];
gtk_cell_renderer_get_preferred_size (cell, handle, contentWidth, null);
diff --git a/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577878_GTK_TreeTable_NoDragImageWithPaintItem.java b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577878_GTK_TreeTable_NoDragImageWithPaintItem.java
index 2d65286..028e5c5 100644
--- a/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577878_GTK_TreeTable_NoDragImageWithPaintItem.java
+++ b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577878_GTK_TreeTable_NoDragImageWithPaintItem.java
@@ -16,23 +16,56 @@
import org.eclipse.swt.*;
import org.eclipse.swt.dnd.*;
+import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public final class Bug577878_GTK_TreeTable_NoDragImageWithPaintItem {
static final int NUM_ROWS = 100;
- static final int NUM_COLS = 3;
+ static final int NUM_COLS = 2;
+ static final int IMG_CX = 22;
+ static final int IMG_CY = 16;
static String makeItemText(int iRow, int iCol) {
return "Item#" + iRow + ":" + iCol;
}
- static void createTable(Composite parent, boolean isCustomPaint) {
- Table control = new Table (parent, SWT.BORDER | SWT.V_SCROLL);
+ static Image makeItemImage(Device device, int iRow) {
+ Image image = new Image(device, IMG_CX, IMG_CY);
+ GC gc = new GC(image);
+ gc.setBackground(new Color(100,255,100));
+ gc.fillRectangle(0, 0, IMG_CX-1, IMG_CY-1);
+ gc.drawRectangle(0, 0, IMG_CX-1, IMG_CY-1);
+
+ String text = Integer.toString(iRow);
+ Point textSize = gc.stringExtent(text);
+ gc.drawText(text, (IMG_CX - textSize.x) / 2, (IMG_CY - textSize.y) / 2);
+
+ gc.dispose();
+ return image;
+ }
+
+ static void paintItem(Event event, Image image, int iRow) {
+ if (image != null) {
+ event.x += 2;
+ int y = event.y + (event.height - image.getBounds().height) / 2;
+ event.gc.drawImage(image, event.x, y);
+ event.x += image.getBounds().width;
+ }
+
+ event.x += 2;
+ String text = makeItemText(iRow, event.index);
+ Point textSize = event.gc.stringExtent(text);
+ int y = event.y + (event.height - textSize.y) / 2;
+ event.gc.drawString (text, event.x, y, true);
+ }
+
+ static void createTable(Composite parent, boolean isCustomPaint, boolean isImages) {
+ Table control = new Table (parent, SWT.BORDER | SWT.V_SCROLL | SWT.MULTI);
control.setLayoutData (new GridData (SWT.FILL, SWT.FILL, true, true));
control.setHeaderVisible (true);
- for (int iColumn = 0; iColumn < 3; iColumn++) {
+ for (int iColumn = 0; iColumn < NUM_COLS; iColumn++) {
TableColumn column = new TableColumn (control, 0);
column.setText ("Col#" + iColumn);
column.setWidth (120);
@@ -40,17 +73,26 @@
control.setItemCount (NUM_ROWS);
+ if (isImages) {
+ for (int iItem = 0; iItem < NUM_ROWS; iItem++) {
+ control.getItem(iItem).setImage(makeItemImage(parent.getDisplay(), iItem));
+ }
+ }
+
if (isCustomPaint) {
control.addListener (SWT.MeasureItem, e -> {
e.width = 120;
e.height = 20;
});
+ control.addListener (SWT.EraseItem, e -> {
+ e.detail &= ~SWT.FOREGROUND;
+ });
+
control.addListener (SWT.PaintItem, e -> {
TableItem item = (TableItem) e.item;
int iRow = item.getParent ().indexOf (item);
- String text = makeItemText(iRow, e.index);
- e.gc.drawString (text, e.x, e.y, true);
+ paintItem(e, item.getImage(), iRow);
});
} else {
for (int iRow = 0; iRow < NUM_ROWS; iRow++) {
@@ -65,12 +107,12 @@
dragSource.addDragListener (new DragSourceAdapter ());
}
- static void createTree(Composite parent, boolean isCustomPaint) {
- Tree control = new Tree (parent, SWT.BORDER | SWT.V_SCROLL);
+ static void createTree(Composite parent, boolean isCustomPaint, boolean isImages) {
+ Tree control = new Tree (parent, SWT.BORDER | SWT.V_SCROLL | SWT.MULTI);
control.setLayoutData (new GridData (SWT.FILL, SWT.FILL, true, true));
control.setHeaderVisible (true);
- for (int iColumn = 0; iColumn < 3; iColumn++) {
+ for (int iColumn = 0; iColumn < NUM_COLS; iColumn++) {
TreeColumn column = new TreeColumn (control, 0);
column.setText ("Col#" + iColumn);
column.setWidth (120);
@@ -78,18 +120,27 @@
control.setItemCount (NUM_ROWS);
+ if (isImages) {
+ for (int iItem = 0; iItem < NUM_ROWS; iItem++) {
+ control.getItem(iItem).setImage(makeItemImage(parent.getDisplay(), iItem));
+ }
+ }
+
if (isCustomPaint) {
control.addListener (SWT.MeasureItem, e -> {
e.width = 120;
e.height = 20;
});
+ control.addListener (SWT.EraseItem, e -> {
+ e.detail &= ~SWT.FOREGROUND;
+ });
+
control.addListener (SWT.PaintItem, e -> {
TreeItem item = (TreeItem) e.item;
TreeItem parentItem = item.getParentItem ();
int iRow = (parentItem != null) ? parentItem.indexOf (item) : item.getParent ().indexOf (item);
- String text = makeItemText(iRow, e.index);
- e.gc.drawString (text, e.x, e.y, true);
+ paintItem(e, item.getImage(), iRow);
});
} else {
for (int iRow = 0; iRow < NUM_ROWS; iRow++) {
@@ -120,24 +171,38 @@
hint.setText (
"1) Run on GTK\n" +
"2) Drag rows from regular Table/Tree - there will be a drag image\n" +
- "3) Bug 577878: Table/Tree with SWT.PaintItem do not have drag image\n"
+ "3) Bug 577878: Table/Tree with SWT.PaintItem do not have drag image\n" +
+ "\n" +
+ "Patch v2:\n" +
+ "4) Bug 577878 v2: Tree/Table with image should not have empty space\n" +
+ " to the left of the item\n" +
+ "5) Bug 579395: Tree with images and PaintItem overpaints expanders\n" +
+ " Old bug, not fixed in this patch."
);
Composite composite = new Composite (shell, 0);
composite.setLayoutData (new GridData (SWT.FILL, SWT.FILL, true, true));
- composite.setLayout (new GridLayout (2, true));
+ composite.setLayout (new GridLayout (4, true));
new Label(composite, 0).setText ("Table");
+ new Label(composite, 0).setText ("Table+Images");
new Label(composite, 0).setText ("Table+PaintItem");
- createTable(composite, false);
- createTable(composite, true);
+ new Label(composite, 0).setText ("Table+PaintItem+Images");
+ createTable(composite, false, false);
+ createTable(composite, false, true);
+ createTable(composite, true, false);
+ createTable(composite, true, true);
new Label(composite, 0).setText ("Tree");
+ new Label(composite, 0).setText ("Tree+Images");
new Label(composite, 0).setText ("Tree+PaintItem");
- createTree(composite, false);
- createTree(composite, true);
+ new Label(composite, 0).setText ("Tree+PaintItem+Images");
+ createTree(composite, false, false);
+ createTree(composite, false, true);
+ createTree(composite, true, false);
+ createTree(composite, true, true);
- shell.setSize (800, 800);
+ shell.setSize (900, 600);
shell.open();
while (!shell.isDisposed()) {