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