001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.view.PaletteView; 016 017import java.awt.Image; 018import java.awt.Toolkit; 019import java.awt.image.IndexColorModel; 020import java.awt.image.MemoryImageSource; 021import java.util.ArrayList; 022import java.util.Vector; 023 024import org.eclipse.swt.SWT; 025import org.eclipse.swt.custom.TableEditor; 026import org.eclipse.swt.events.DisposeEvent; 027import org.eclipse.swt.events.DisposeListener; 028import org.eclipse.swt.events.MouseAdapter; 029import org.eclipse.swt.events.MouseEvent; 030import org.eclipse.swt.events.MouseMoveListener; 031import org.eclipse.swt.events.PaintEvent; 032import org.eclipse.swt.events.PaintListener; 033import org.eclipse.swt.events.SelectionAdapter; 034import org.eclipse.swt.events.SelectionEvent; 035import org.eclipse.swt.graphics.Color; 036import org.eclipse.swt.graphics.Font; 037import org.eclipse.swt.graphics.GC; 038import org.eclipse.swt.graphics.Point; 039import org.eclipse.swt.graphics.Rectangle; 040import org.eclipse.swt.layout.GridData; 041import org.eclipse.swt.layout.GridLayout; 042import org.eclipse.swt.layout.RowLayout; 043import org.eclipse.swt.widgets.Button; 044import org.eclipse.swt.widgets.Canvas; 045import org.eclipse.swt.widgets.Combo; 046import org.eclipse.swt.widgets.Composite; 047import org.eclipse.swt.widgets.Dialog; 048import org.eclipse.swt.widgets.Display; 049import org.eclipse.swt.widgets.Event; 050import org.eclipse.swt.widgets.Listener; 051import org.eclipse.swt.widgets.Shell; 052import org.eclipse.swt.widgets.Table; 053import org.eclipse.swt.widgets.TableColumn; 054import org.eclipse.swt.widgets.TableItem; 055import org.eclipse.swt.widgets.Text; 056 057import hdf.object.FileFormat; 058import hdf.object.HObject; 059import hdf.object.ScalarDS; 060import hdf.view.Tools; 061import hdf.view.ViewProperties; 062import hdf.view.DataView.DataViewManager; 063import hdf.view.ImageView.ImageView; 064 065/** 066 * Displays a dialog for viewing and change palettes. 067 * 068 * @author Jordan T. Henderson 069 * @version 2.4 2/27/16 070 */ 071public class DefaultPaletteView extends Dialog implements PaletteView 072{ 073 private Shell shell; 074 075 private Font curFont; 076 077 private ScalarDS dataset; 078 079 /** Panel that draws plot of data values. */ 080 private ChartCanvas chartP; 081 private ImageView imageView; 082 private PaletteValueTable paletteValueTable; 083 084 private Button checkRed; 085 private Button checkGreen; 086 private Button checkBlue; 087 088 private Combo choicePalette; 089 090 private Image originalImage; 091 private Image currentImage; 092 093 private static final int[] lineColors = { SWT.COLOR_RED, SWT.COLOR_GREEN, SWT.COLOR_BLUE }; 094 private static final String[] lineLabels = { "Red", "Green", "Blue" }; 095 096 private static final String PALETTE_GRAY = "Gray"; 097 private static final String PALETTE_DEFAULT = "Default"; 098 private static final String PALETTE_REVERSE_GRAY = "Reverse Gray"; 099 private static final String PALETTE_GRAY_WAVE = "GrayWave"; 100 private static final String PALETTE_RAINBOW = "Rainbow"; 101 private static final String PALETTE_NATURE = "Nature"; 102 private static final String PALETTE_WAVE = "Wave"; 103 104 private byte[][] palette; 105 private int numberOfPalettes; 106 private int[][] paletteData; 107 108 private boolean isPaletteChanged = false; 109 private boolean isH5 = false; 110 111 /** 112 * Create a dialog for viewing and changing palettes. 113 * 114 * @param parent 115 * the parent component 116 * @param theImageView 117 * the associated ImageView 118 */ 119 public DefaultPaletteView(Shell parent, ImageView theImageView) { 120 this(parent, null, theImageView); 121 } 122 123 /** 124 * Create a dialog for viewing and change palettes. 125 * 126 * @param parent 127 * the parent component 128 * @param theViewer 129 * the data view manager 130 * @param theImageView 131 * the associated ImageView 132 */ 133 public DefaultPaletteView(Shell parent, DataViewManager theViewer, ImageView theImageView) { 134 super(parent, SWT.APPLICATION_MODAL); 135 136 try { 137 curFont = new Font( 138 Display.getCurrent(), 139 ViewProperties.getFontType(), 140 ViewProperties.getFontSize(), 141 SWT.NORMAL); 142 } 143 catch (Exception ex) { 144 curFont = null; 145 } 146 147 imageView = theImageView; 148 dataset = (ScalarDS) imageView.getDataObject(); 149 150 numberOfPalettes = 1; 151 152 paletteData = new int[3][256]; 153 byte[][] imagePalette = imageView.getPalette(); 154 155 int d = 0; 156 for (int i = 0; i < 3; i++) { 157 for (int j = 0; j < 256; j++) { 158 d = imagePalette[i][j]; 159 if (d < 0) 160 d += 256; 161 paletteData[i][j] = d; 162 } 163 } 164 165 originalImage = currentImage = imageView.getImage(); 166 palette = new byte[3][256]; 167 168 isH5 = dataset.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)); 169 170 createUI(); 171 } 172 173 /** Create the visual components */ 174 public void createUI() { 175 Shell parent = getParent(); 176 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 177 shell.setFont(curFont); 178 shell.setText("Image Palette for - " + dataset.getPath() + dataset.getName()); 179 shell.setImage(ViewProperties.getHdfIcon()); 180 shell.setLayout(new GridLayout(1, true)); 181 182 shell.setData(this); 183 184 chartP = new ChartCanvas(shell, SWT.DOUBLE_BUFFERED | SWT.BORDER); 185 GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 186 data.widthHint = 700 + (ViewProperties.getFontSize() - 12) * 15; 187 data.heightHint = 500 + (ViewProperties.getFontSize() - 12) * 10; 188 chartP.setLayoutData(data); 189 190 // Create the toolbar composite 191 Composite tools = new Composite(shell, SWT.NONE); 192 tools.setLayout(new GridLayout(3, false)); 193 tools.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 194 195 // Add buttons for changing line colors 196 Composite rgbComposite = new Composite(tools, SWT.BORDER); 197 rgbComposite.setLayout(new GridLayout(3, true)); 198 rgbComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 199 200 checkRed = new Button(rgbComposite, SWT.RADIO); 201 checkRed.setFont(curFont); 202 checkRed.setText("Red"); 203 checkRed.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); 204 checkRed.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); 205 206 checkGreen = new Button(rgbComposite, SWT.RADIO); 207 checkGreen.setFont(curFont); 208 checkGreen.setText("Green"); 209 checkGreen.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GREEN)); 210 checkGreen.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); 211 212 checkBlue = new Button(rgbComposite, SWT.RADIO); 213 checkBlue.setFont(curFont); 214 checkBlue.setText("Blue"); 215 checkBlue.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)); 216 checkBlue.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); 217 218 checkRed.setSelection(true); 219 checkGreen.setSelection(false); 220 checkBlue.setSelection(false); 221 222 // Add controls for selecting palettes and showing values 223 Composite paletteComposite = new Composite(tools, SWT.BORDER); 224 paletteComposite.setLayout(new GridLayout(2, false)); 225 paletteComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 226 227 choicePalette = new Combo(paletteComposite, SWT.SINGLE | SWT.READ_ONLY); 228 choicePalette.setFont(curFont); 229 choicePalette.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 230 choicePalette.addSelectionListener(new SelectionAdapter() { 231 @Override 232 public void widgetSelected(SelectionEvent e) { 233 int idx = choicePalette.getSelectionIndex(); 234 if (idx <= 0) 235 return; 236 237 byte[][] imagePalette = null; 238 Object item = choicePalette.getItem(idx); 239 240 if (item.equals(PALETTE_DEFAULT)) 241 imagePalette = dataset.getPalette(); 242 else if (item.equals(PALETTE_GRAY)) 243 imagePalette = Tools.createGrayPalette(); 244 else if (item.equals(PALETTE_REVERSE_GRAY)) 245 imagePalette = Tools.createReverseGrayPalette(); 246 else if (item.equals(PALETTE_GRAY_WAVE)) 247 imagePalette = Tools.createGrayWavePalette(); 248 else if (item.equals(PALETTE_RAINBOW)) 249 imagePalette = Tools.createRainbowPalette(); 250 else if (item.equals(PALETTE_NATURE)) 251 imagePalette = Tools.createNaturePalette(); 252 else if (item.equals(PALETTE_WAVE)) 253 imagePalette = Tools.createWavePalette(); 254 else if (idx > 0 && idx <= numberOfPalettes) 255 imagePalette = dataset.readPalette(idx - 1); 256 else 257 imagePalette = Tools.readPalette((String) item); 258 259 if (imagePalette == null) 260 return; 261 262 int d = 0; 263 for (int i = 0; i < 3; i++) { 264 for (int j = 0; j < 256; j++) { 265 d = imagePalette[i][j]; 266 if (d < 0) 267 d += 256; 268 paletteData[i][j] = d; 269 } 270 } 271 272 chartP.redraw(); 273 isPaletteChanged = true; 274 } 275 }); 276 277 choicePalette.add("Select palette"); 278 279 String paletteName = dataset.getPaletteName(0); 280 281 if (paletteName != null) 282 paletteName = paletteName.trim(); 283 284 if (paletteName != null && paletteName.length() > 0) 285 choicePalette.add(paletteName); 286 287 if (isH5 && (dataset instanceof ScalarDS)) 288 numberOfPalettes = dataset.getNumberOfPalettes(); 289 for (int i = 1; i < numberOfPalettes; i++) { 290 paletteName = dataset.getPaletteName(i); 291 choicePalette.add(paletteName); 292 } 293 choicePalette.add(PALETTE_GRAY); 294 choicePalette.add(PALETTE_GRAY_WAVE); 295 choicePalette.add(PALETTE_RAINBOW); 296 choicePalette.add(PALETTE_NATURE); 297 choicePalette.add(PALETTE_WAVE); 298 ArrayList<?> plist = (ArrayList<?>) ViewProperties.getPaletteList(); 299 int n = plist.size(); 300 for (int i = 0; i < n; i++) 301 choicePalette.add((String) plist.get(i)); 302 303 choicePalette.select(0); 304 305 Button showValueButton = new Button(paletteComposite, SWT.PUSH); 306 showValueButton.setFont(curFont); 307 showValueButton.setText("Show Values"); 308 showValueButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 309 showValueButton.addSelectionListener(new SelectionAdapter() { 310 @Override 311 public void widgetSelected(SelectionEvent e) { 312 if (paletteValueTable == null) 313 paletteValueTable = new PaletteValueTable(shell, SWT.NONE); 314 315 paletteValueTable.open(); 316 } 317 }); 318 319 // Add Ok/Cancel/Preview buttons 320 Composite buttonComposite = new Composite(tools, SWT.BORDER); 321 buttonComposite.setLayout(new RowLayout(SWT.HORIZONTAL)); 322 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 323 324 Button okButton = new Button(buttonComposite, SWT.PUSH); 325 okButton.setFont(curFont); 326 okButton.setText(" &OK "); 327 okButton.addSelectionListener(new SelectionAdapter() { 328 @Override 329 public void widgetSelected(SelectionEvent e) { 330 if (isPaletteChanged) { 331 updatePalette(); 332 isPaletteChanged = false; 333 imageView.setPalette(palette); 334 imageView.setImage(currentImage); 335 } 336 337 shell.dispose(); 338 } 339 }); 340 341 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 342 cancelButton.setFont(curFont); 343 cancelButton.setText(" &Cancel "); 344 cancelButton.addSelectionListener(new SelectionAdapter() { 345 @Override 346 public void widgetSelected(SelectionEvent e) { 347 imageView.setImage(originalImage); 348 shell.dispose(); 349 } 350 }); 351 352 Button previewButton = new Button(buttonComposite, SWT.PUSH); 353 previewButton.setFont(curFont); 354 previewButton.setText("&Preview"); 355 previewButton.addSelectionListener(new SelectionAdapter() { 356 @Override 357 public void widgetSelected(SelectionEvent e) { 358 updatePalette(); 359 imageView.setImage(currentImage); 360 } 361 }); 362 363 shell.pack(); 364 365 shell.addDisposeListener(new DisposeListener() { 366 @Override 367 public void widgetDisposed(DisposeEvent e) { 368 if (curFont != null) 369 curFont.dispose(); 370 } 371 }); 372 373 shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 374 375 Rectangle parentBounds = parent.getBounds(); 376 Point shellSize = shell.getSize(); 377 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 378 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 379 380 shell.open(); 381 } 382 383 /** @return the data object displayed in this data viewer */ 384 @Override 385 public HObject getDataObject() { 386 return dataset; 387 } 388 389 private void updatePalette() { 390 for (int i = 0; i < 256; i++) { 391 palette[0][i] = (byte) paletteData[0][i]; 392 palette[1][i] = (byte) paletteData[1][i]; 393 palette[2][i] = (byte) paletteData[2][i]; 394 } 395 396 IndexColorModel colorModel = new IndexColorModel( 397 8, // bits - the number of bits each pixel occupies 398 256, // size - the size of the color component arrays 399 palette[0], // r - the array of red color components 400 palette[1], // g - the array of green color components 401 palette[2]); // b - the array of blue color components 402 403 long w = dataset.getWidth(); 404 long h = dataset.getHeight(); 405 MemoryImageSource memoryImageSource = null; 406 407 try { 408 memoryImageSource = (MemoryImageSource) originalImage.getSource(); 409 } 410 catch (Exception err) { 411 memoryImageSource = null; 412 } 413 414 if (memoryImageSource == null) 415 memoryImageSource = new MemoryImageSource((int) w, (int) h, colorModel, imageView.getImageByteData(), 0, (int) w); 416 else 417 memoryImageSource.newPixels(imageView.getImageByteData(), colorModel, 0, (int) w); 418 419 currentImage = Tools.toBufferedImage(Toolkit.getDefaultToolkit().createImage(memoryImageSource)); 420 } 421 422 /** The canvas that paints the data lines. */ 423 private class ChartCanvas extends Canvas 424 { 425 // Value controlling gap between the sides of the canvas 426 // and the drawn elements 427 private final int gap = 20; 428 429 private int xgap = 0; 430 private int ygap = 0; 431 432 private int plotWidth = 0; 433 private int plotHeight = 0; 434 435 private final int LEGEND_LINE_WIDTH = 10; 436 private final int LEGEND_LINE_GAP = 30; 437 438 // Values controlling the dimensions of the legend, 439 // as well as the gap in between each 440 // element displayed in the legend 441 private int LEGEND_WIDTH = 60; 442 private final int LEGEND_HEIGHT = (5 * LEGEND_LINE_GAP); 443 444 private final int PALETTE_MAX = 255; 445 446 private int dragX0, dragY0; // starting point of mouse drag 447 448 public ChartCanvas(Composite parent, int style) { 449 super(parent, style); 450 451 this.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); 452 453 this.addPaintListener(new PaintListener() { 454 @Override 455 public void paintControl(PaintEvent e) { 456 // Get the graphics context for this paint event 457 GC g = e.gc; 458 459 g.setFont(curFont); 460 461 Rectangle canvasBounds = getClientArea(); 462 org.eclipse.swt.graphics.Color c = g.getForeground(); 463 464 // Make sure legend width scales with font size 465 for (int i = 0; i < lineLabels.length; i++) { 466 int width = g.stringExtent(lineLabels[i]).x; 467 if (width > (2 * LEGEND_WIDTH / 3) - 10) 468 LEGEND_WIDTH += width; 469 } 470 471 // Calculate maximum width needed to draw the y-axis labels 472 final int maxYLabelWidth = g.stringExtent(String.valueOf(PALETTE_MAX)).x; 473 474 // Calculate maximum height needed to draw the x-axis labels 475 final int maxXLabelHeight = g.stringExtent(String.valueOf(PALETTE_MAX)).y; 476 477 xgap = maxYLabelWidth + gap; 478 ygap = getSize().y - maxXLabelHeight - gap - 1; 479 plotHeight = ygap - gap; 480 plotWidth = canvasBounds.width - LEGEND_WIDTH - (2 * gap) - xgap; 481 482 // draw the X axis 483 g.drawLine(xgap, ygap, xgap + plotWidth, ygap); 484 485 // draw the Y axis 486 g.drawLine(xgap, ygap, xgap, gap); 487 488 // draw X and Y labels: 10 labels for x and y 489 int dh = plotHeight / 10; 490 int dw = plotWidth / 10; 491 int dx = 25; 492 double dy = 25; 493 int xp = 2 * gap; 494 int yp = 0; 495 int x = 0; 496 int x0; 497 int y0; 498 int x1; 499 int y1; 500 double y = 0; 501 502 // draw X and Y grid labels 503 String xVal = String.valueOf(x); 504 String yVal = String.valueOf((int) y); 505 Point xLabelSize = g.stringExtent(xVal); 506 Point yLabelSize = g.stringExtent(yVal); 507 g.drawString(yVal, 0, ygap - yLabelSize.y / 2); 508 g.drawString(xVal, xgap - xLabelSize.x / 2, canvasBounds.height - xLabelSize.y); 509 for (int i = 0; i < 10; i++) { 510 xp += dw; 511 yp += dh; 512 x += dx; 513 y += dy; 514 515 xVal = String.valueOf(x); 516 yVal = String.valueOf((int) y); 517 xLabelSize = g.stringExtent(xVal); 518 yLabelSize = g.stringExtent(yVal); 519 520 // Draw tick marks 521 g.drawLine(xp, ygap, xp, ygap - 5); 522 g.drawLine(xgap, ygap - yp, xgap + 5, ygap - yp); 523 524 g.drawString(xVal, xp - (xLabelSize.x / 2), canvasBounds.height - xLabelSize.y); 525 g.drawString(yVal, 0, ygap - yp - (yLabelSize.y / 2)); 526 } 527 528 for (int i = 0; i < 3; i++) { 529 g.setForeground(Display.getCurrent().getSystemColor(lineColors[i])); 530 531 // set up the line data for drawing one line a time 532 for (int j = 0; j < 255; j++) { 533 x0 = xgap + (plotWidth * j / 255); 534 y0 = ygap - (plotHeight * paletteData[i][j] / 255); 535 x1 = xgap + (plotWidth * (j + 1) / 255); 536 y1 = ygap - (plotHeight * (paletteData[i][j + 1]) / 255); 537 g.drawLine(x0, y0, x1, y1); 538 } 539 540 // Draw lines and labels in the legend 541 x0 = (canvasBounds.width - gap - LEGEND_WIDTH) + (LEGEND_WIDTH / 3); 542 y0 = gap + LEGEND_LINE_GAP * (i + 1); 543 g.drawLine(x0, y0, x0 + LEGEND_LINE_WIDTH, y0); 544 g.drawString(lineLabels[i], x0 + 10, y0 + 3); 545 } 546 547 // draw a box on the legend 548 g.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); 549 g.drawRectangle(canvasBounds.width - LEGEND_WIDTH - gap, gap, LEGEND_WIDTH, LEGEND_HEIGHT); 550 551 g.setForeground(c); // set the color back to its default 552 } 553 }); 554 555 //TODO: editing behavior not quite correct yet 556 this.addMouseMoveListener(new MouseMoveListener() { 557 @Override 558 public void mouseMove(MouseEvent e) { 559 if ((e.stateMask & SWT.BUTTON1) != 0) { 560 int x1 = e.x - 40; 561 if (x1 < 0) 562 x1 = 0; 563 int y1 = e.y + 20; 564 565 Point size = chartP.getSize(); 566 double ry = 255 / (double) size.y; 567 double rx = 255 / (double) size.x; 568 569 int lineIdx = 0; 570 if (checkGreen.getSelection()) 571 lineIdx = 1; 572 else if (checkBlue.getSelection()) 573 lineIdx = 2; 574 575 int idx = 0; 576 double b = (double) (y1 - dragY0) / (double) (x1 - dragX0); 577 double a = dragY0 - b * dragX0; 578 int i0 = Math.min(dragX0, x1); 579 int i1 = Math.max(dragX0, x1); 580 for (int i = i0; i < i1; i++) { 581 idx = (int) (rx * i); 582 if (idx > 255) 583 continue; 584 double value = 255 - (a + b * i) * ry; 585 if (value < 0) 586 value = 0; 587 else if (value > 255) 588 value = 255; 589 590 paletteData[lineIdx][idx] = (int) value; 591 } 592 593 chartP.redraw(); 594 isPaletteChanged = true; 595 } 596 } 597 }); 598 599 this.addMouseListener(new MouseAdapter() { 600 @Override 601 public void mouseDown(MouseEvent e) { 602 // dragX0 = e.x - xgap; 603 // dragY0 = e.y + gap; 604 // 605 // (dragX0 < 0) 606 // dragX0 = 0; 607 // (dragX0 > xgap + plotWidth) 608 // dragX0 = xgap + plotWidth; 609 // (dragY0 < 0) 610 // dragY0 = 0; 611 // (dragY0 > plotHeight + gap) 612 // dragY0 = plotHeight + gap; 613 } 614 615 @Override 616 public void mouseUp(MouseEvent e) { 617 if (paletteValueTable != null) 618 paletteValueTable.refresh(); 619 } 620 }); 621 } 622 } 623 624 /** The dialog to show the palette values in spreadsheet. */ 625 private class PaletteValueTable extends Dialog 626 { 627 private Display display; 628 private Shell tableShell; 629 630 private Table valueTable; 631 632 private static final String RGBNAME = "Color"; 633 private static final String IDXNAME = "Index"; 634 635 public PaletteValueTable(Shell parent, int style) { 636 super(parent, style); 637 } 638 639 public void open() { 640 Shell parent = getParent(); 641 display = parent.getDisplay(); 642 643 tableShell = new Shell(parent, SWT.SHELL_TRIM); 644 tableShell.setFont(curFont); 645 tableShell.setText(""); 646 tableShell.setImage(ViewProperties.getHdfIcon()); 647 tableShell.setLayout(new GridLayout(1, true)); 648 649 Composite content = new Composite(tableShell, SWT.NONE); 650 content.setLayout(new GridLayout(1, true)); 651 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 652 653 GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 654 data.heightHint = 200; 655 content.setLayoutData(data); 656 657 String[] columnNames = { IDXNAME, "Red", "Green", "Blue", RGBNAME }; 658 659 valueTable = new Table(content, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.NO_SCROLL); 660 valueTable.setHeaderVisible(true); 661 valueTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 662 valueTable.setFont(curFont); 663 664 // Add cell editor for changing cell values in-place 665 valueTable.addListener(SWT.MouseDoubleClick, valueTableCellEditor); 666 667 valueTable.addListener(SWT.Resize, new Listener() { 668 @Override 669 public void handleEvent(Event e) { 670 int numColumns = valueTable.getColumnCount(); 671 672 for (int i = 0; i < numColumns; i++) 673 valueTable.getColumn(i).setWidth(valueTable.getClientArea().width / numColumns); 674 } 675 }); 676 677 valueTable.addPaintListener(new PaintListener() { 678 @Override 679 public void paintControl(PaintEvent e) { 680 for (int i = 0; i < valueTable.getItemCount(); i++) { 681 Color cellColor = new Color(display, paletteData[0][i], paletteData[1][i], paletteData[2][i]); 682 683 valueTable.getItem(i).setBackground(4, cellColor); 684 685 cellColor.dispose(); 686 } 687 } 688 }); 689 690 for (int i = 0; i < columnNames.length; i++) { 691 TableColumn column = new TableColumn(valueTable, SWT.NONE); 692 column.setText(columnNames[i]); 693 column.setMoveable(false); 694 column.pack(); 695 } 696 697 for (int i = 0; i < 256; i++) { 698 TableItem item = new TableItem(valueTable, SWT.NONE); 699 item.setFont(curFont); 700 701 item.setText(new String[] { 702 String.valueOf(i), 703 String.valueOf(paletteData[0][i]), 704 String.valueOf(paletteData[1][i]), 705 String.valueOf(paletteData[2][i]), null }); 706 707 item.setBackground(0, Display.getCurrent().getSystemColor(SWT.COLOR_GRAY)); 708 } 709 710 // set cell height for large fonts 711 // int cellRowHeight = Math.max(16, valueTable.getFontMetrics( 712 // valueTable.getFont()).getHeight()); 713 // valueTable.setRowHeight(cellRowHeight); 714 715 Button okButton = new Button(tableShell, SWT.PUSH); 716 okButton.setFont(curFont); 717 okButton.setText(" &OK "); 718 okButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false)); 719 okButton.addSelectionListener(new SelectionAdapter() { 720 @Override 721 public void widgetSelected(SelectionEvent e) { 722 tableShell.dispose(); 723 } 724 }); 725 726 tableShell.pack(); 727 728 int w = 300 + (ViewProperties.getFontSize() - 12) * 10; 729 int h = 600 + (ViewProperties.getFontSize() - 12) * 15; 730 731 tableShell.setSize(w, h); 732 733 Rectangle parentBounds = parent.getBounds(); 734 Point shellSize = tableShell.getSize(); 735 tableShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 736 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 737 738 tableShell.open(); 739 740 while (!tableShell.isDisposed()) { 741 if (!display.readAndDispatch()) 742 display.sleep(); 743 } 744 } 745 746 private void updatePaletteValue(String strValue, int row, int col) { 747 if (strValue == null) 748 return; 749 750 int value = 0; 751 752 try { 753 value = Integer.parseInt(strValue); 754 } 755 catch (Exception ex) { 756 return; 757 } 758 759 if (value < 0 || value > 255) { 760 Tools.showError(tableShell, "Update", "Value is out of range [0, 255]"); 761 return; 762 } 763 764 paletteData[col][row] = value; 765 chartP.redraw(); 766 isPaletteChanged = true; 767 } 768 769 public void refresh() { 770 if (valueTable != null && !valueTable.isDisposed()) 771 valueTable.redraw(); 772 } 773 774 private Listener valueTableCellEditor = new Listener() { 775 @Override 776 public void handleEvent(Event event) { 777 final TableEditor editor = new TableEditor(valueTable); 778 editor.horizontalAlignment = SWT.LEFT; 779 editor.grabHorizontal = true; 780 781 Rectangle clientArea = valueTable.getClientArea(); 782 Point pt = new Point(event.x, event.y); 783 int index = valueTable.getTopIndex(); 784 785 while (index < valueTable.getItemCount()) { 786 boolean visible = false; 787 final TableItem item = valueTable.getItem(index); 788 789 // Only allow editing of RGB values 790 for (int i = 1; i < valueTable.getColumnCount() - 1; i++) { 791 Rectangle rect = item.getBounds(i); 792 793 if (rect.contains(pt)) { 794 final int column = i; 795 final int row = index; 796 797 final Text text = new Text(valueTable, SWT.NONE); 798 text.setFont(curFont); 799 800 Listener textListener = new Listener() { 801 @Override 802 public void handleEvent(final Event e) { 803 switch (e.type) { 804 case SWT.FocusOut: 805 item.setText(column, text.getText()); 806 updatePaletteValue(item.getText(column), row, column - 1); 807 text.dispose(); 808 break; 809 case SWT.Traverse: 810 switch (e.detail) { 811 case SWT.TRAVERSE_RETURN: 812 item.setText(column, text.getText()); 813 updatePaletteValue(item.getText(column), row, column - 1); 814 break; 815 case SWT.TRAVERSE_ESCAPE: 816 text.dispose(); 817 e.doit = false; 818 break; 819 default: 820 break; 821 } 822 break; 823 default: 824 break; 825 } 826 } 827 }; 828 829 text.addListener(SWT.FocusOut, textListener); 830 text.addListener(SWT.Traverse, textListener); 831 editor.setEditor(text, item, i); 832 text.setText(item.getText(i)); 833 text.selectAll(); 834 text.setFocus(); 835 return; 836 } 837 838 if (!visible && rect.intersects(clientArea)) 839 visible = true; 840 } 841 842 if (!visible) 843 return; 844 845 index++; 846 } 847 } 848 }; 849 } 850}