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 byte[] palRefs = dataset.getPaletteRefs(); 289 if ((palRefs != null) && (palRefs.length > 8)) 290 numberOfPalettes = palRefs.length / 8; 291 } 292 for (int i = 1; i < numberOfPalettes; i++) { 293 paletteName = dataset.getPaletteName(i); 294 choicePalette.add(paletteName); 295 } 296 choicePalette.add(PALETTE_GRAY); 297 choicePalette.add(PALETTE_GRAY_WAVE); 298 choicePalette.add(PALETTE_RAINBOW); 299 choicePalette.add(PALETTE_NATURE); 300 choicePalette.add(PALETTE_WAVE); 301 ArrayList<?> plist = (ArrayList<?>) ViewProperties.getPaletteList(); 302 int n = plist.size(); 303 for (int i = 0; i < n; i++) 304 choicePalette.add((String) plist.get(i)); 305 306 choicePalette.select(0); 307 308 Button showValueButton = new Button(paletteComposite, SWT.PUSH); 309 showValueButton.setFont(curFont); 310 showValueButton.setText("Show Values"); 311 showValueButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 312 showValueButton.addSelectionListener(new SelectionAdapter() { 313 @Override 314 public void widgetSelected(SelectionEvent e) { 315 if (paletteValueTable == null) 316 paletteValueTable = new PaletteValueTable(shell, SWT.NONE); 317 318 paletteValueTable.open(); 319 } 320 }); 321 322 // Add Ok/Cancel/Preview buttons 323 Composite buttonComposite = new Composite(tools, SWT.BORDER); 324 buttonComposite.setLayout(new RowLayout(SWT.HORIZONTAL)); 325 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 326 327 Button okButton = new Button(buttonComposite, SWT.PUSH); 328 okButton.setFont(curFont); 329 okButton.setText(" &OK "); 330 okButton.addSelectionListener(new SelectionAdapter() { 331 @Override 332 public void widgetSelected(SelectionEvent e) { 333 if (isPaletteChanged) { 334 updatePalette(); 335 isPaletteChanged = false; 336 imageView.setPalette(palette); 337 imageView.setImage(currentImage); 338 } 339 340 shell.dispose(); 341 } 342 }); 343 344 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 345 cancelButton.setFont(curFont); 346 cancelButton.setText(" &Cancel "); 347 cancelButton.addSelectionListener(new SelectionAdapter() { 348 @Override 349 public void widgetSelected(SelectionEvent e) { 350 imageView.setImage(originalImage); 351 shell.dispose(); 352 } 353 }); 354 355 Button previewButton = new Button(buttonComposite, SWT.PUSH); 356 previewButton.setFont(curFont); 357 previewButton.setText("&Preview"); 358 previewButton.addSelectionListener(new SelectionAdapter() { 359 @Override 360 public void widgetSelected(SelectionEvent e) { 361 updatePalette(); 362 imageView.setImage(currentImage); 363 } 364 }); 365 366 shell.pack(); 367 368 shell.addDisposeListener(new DisposeListener() { 369 @Override 370 public void widgetDisposed(DisposeEvent e) { 371 if (curFont != null) 372 curFont.dispose(); 373 } 374 }); 375 376 shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 377 378 Rectangle parentBounds = parent.getBounds(); 379 Point shellSize = shell.getSize(); 380 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 381 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 382 383 shell.open(); 384 } 385 386 /** @return the data object displayed in this data viewer */ 387 @Override 388 public HObject getDataObject() { 389 return dataset; 390 } 391 392 private void updatePalette() { 393 for (int i = 0; i < 256; i++) { 394 palette[0][i] = (byte) paletteData[0][i]; 395 palette[1][i] = (byte) paletteData[1][i]; 396 palette[2][i] = (byte) paletteData[2][i]; 397 } 398 399 IndexColorModel colorModel = new IndexColorModel( 400 8, // bits - the number of bits each pixel occupies 401 256, // size - the size of the color component arrays 402 palette[0], // r - the array of red color components 403 palette[1], // g - the array of green color components 404 palette[2]); // b - the array of blue color components 405 406 long w = dataset.getWidth(); 407 long h = dataset.getHeight(); 408 MemoryImageSource memoryImageSource = null; 409 410 try { 411 memoryImageSource = (MemoryImageSource) originalImage.getSource(); 412 } 413 catch (Exception err) { 414 memoryImageSource = null; 415 } 416 417 if (memoryImageSource == null) 418 memoryImageSource = new MemoryImageSource((int) w, (int) h, colorModel, imageView.getImageByteData(), 0, (int) w); 419 else 420 memoryImageSource.newPixels(imageView.getImageByteData(), colorModel, 0, (int) w); 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 { 428 // Value controlling gap between the sides of the canvas 429 // and the drawn elements 430 private final int gap = 20; 431 432 private int xgap = 0; 433 private int ygap = 0; 434 435 private int plotWidth = 0; 436 private int plotHeight = 0; 437 438 private final int LEGEND_LINE_WIDTH = 10; 439 private final int LEGEND_LINE_GAP = 30; 440 441 // Values controlling the dimensions of the legend, 442 // as well as the gap in between each 443 // element displayed in the legend 444 private int LEGEND_WIDTH = 60; 445 private final int LEGEND_HEIGHT = (5 * LEGEND_LINE_GAP); 446 447 private final int PALETTE_MAX = 255; 448 449 private int dragX0, dragY0; // starting point of mouse drag 450 451 public ChartCanvas(Composite parent, int style) { 452 super(parent, style); 453 454 this.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); 455 456 this.addPaintListener(new PaintListener() { 457 @Override 458 public void paintControl(PaintEvent e) { 459 // Get the graphics context for this paint event 460 GC g = e.gc; 461 462 g.setFont(curFont); 463 464 Rectangle canvasBounds = getClientArea(); 465 org.eclipse.swt.graphics.Color c = g.getForeground(); 466 467 // Make sure legend width scales with font size 468 for (int i = 0; i < lineLabels.length; i++) { 469 int width = g.stringExtent(lineLabels[i]).x; 470 if (width > (2 * LEGEND_WIDTH / 3) - 10) 471 LEGEND_WIDTH += width; 472 } 473 474 // Calculate maximum width needed to draw the y-axis labels 475 final int maxYLabelWidth = g.stringExtent(String.valueOf(PALETTE_MAX)).x; 476 477 // Calculate maximum height needed to draw the x-axis labels 478 final int maxXLabelHeight = g.stringExtent(String.valueOf(PALETTE_MAX)).y; 479 480 xgap = maxYLabelWidth + gap; 481 ygap = getSize().y - maxXLabelHeight - gap - 1; 482 plotHeight = ygap - gap; 483 plotWidth = canvasBounds.width - LEGEND_WIDTH - (2 * gap) - xgap; 484 485 // draw the X axis 486 g.drawLine(xgap, ygap, xgap + plotWidth, ygap); 487 488 // draw the Y axis 489 g.drawLine(xgap, ygap, xgap, gap); 490 491 // draw X and Y labels: 10 labels for x and y 492 int dh = plotHeight / 10; 493 int dw = plotWidth / 10; 494 int dx = 25; 495 double dy = 25; 496 int xp = 2 * gap; 497 int yp = 0; 498 int x = 0; 499 int x0; 500 int y0; 501 int x1; 502 int y1; 503 double y = 0; 504 505 // draw X and Y grid labels 506 String xVal = String.valueOf(x); 507 String yVal = String.valueOf((int) y); 508 Point xLabelSize = g.stringExtent(xVal); 509 Point yLabelSize = g.stringExtent(yVal); 510 g.drawString(yVal, 0, ygap - yLabelSize.y / 2); 511 g.drawString(xVal, xgap - xLabelSize.x / 2, canvasBounds.height - xLabelSize.y); 512 for (int i = 0; i < 10; i++) { 513 xp += dw; 514 yp += dh; 515 x += dx; 516 y += dy; 517 518 xVal = String.valueOf(x); 519 yVal = String.valueOf((int) y); 520 xLabelSize = g.stringExtent(xVal); 521 yLabelSize = g.stringExtent(yVal); 522 523 // Draw tick marks 524 g.drawLine(xp, ygap, xp, ygap - 5); 525 g.drawLine(xgap, ygap - yp, xgap + 5, ygap - yp); 526 527 g.drawString(xVal, xp - (xLabelSize.x / 2), canvasBounds.height - xLabelSize.y); 528 g.drawString(yVal, 0, ygap - yp - (yLabelSize.y / 2)); 529 } 530 531 for (int i = 0; i < 3; i++) { 532 g.setForeground(Display.getCurrent().getSystemColor(lineColors[i])); 533 534 // set up the line data for drawing one line a time 535 for (int j = 0; j < 255; j++) { 536 x0 = xgap + (plotWidth * j / 255); 537 y0 = ygap - (plotHeight * paletteData[i][j] / 255); 538 x1 = xgap + (plotWidth * (j + 1) / 255); 539 y1 = ygap - (plotHeight * (paletteData[i][j + 1]) / 255); 540 g.drawLine(x0, y0, x1, y1); 541 } 542 543 // Draw lines and labels in the legend 544 x0 = (canvasBounds.width - gap - LEGEND_WIDTH) + (LEGEND_WIDTH / 3); 545 y0 = gap + LEGEND_LINE_GAP * (i + 1); 546 g.drawLine(x0, y0, x0 + LEGEND_LINE_WIDTH, y0); 547 g.drawString(lineLabels[i], x0 + 10, y0 + 3); 548 } 549 550 // draw a box on the legend 551 g.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); 552 g.drawRectangle(canvasBounds.width - LEGEND_WIDTH - gap, gap, LEGEND_WIDTH, LEGEND_HEIGHT); 553 554 g.setForeground(c); // set the color back to its default 555 } 556 }); 557 558 //TODO: editing behavior not quite correct yet 559 this.addMouseMoveListener(new MouseMoveListener() { 560 @Override 561 public void mouseMove(MouseEvent e) { 562 if ((e.stateMask & SWT.BUTTON1) != 0) { 563 int x1 = e.x - 40; 564 if (x1 < 0) 565 x1 = 0; 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 else if (checkBlue.getSelection()) 576 lineIdx = 2; 577 578 int idx = 0; 579 double b = (double) (y1 - dragY0) / (double) (x1 - dragX0); 580 double a = dragY0 - b * dragX0; 581 int i0 = Math.min(dragX0, x1); 582 int i1 = Math.max(dragX0, x1); 583 for (int i = i0; i < i1; i++) { 584 idx = (int) (rx * i); 585 if (idx > 255) 586 continue; 587 double value = 255 - (a + b * i) * ry; 588 if (value < 0) 589 value = 0; 590 else if (value > 255) 591 value = 255; 592 593 paletteData[lineIdx][idx] = (int) value; 594 } 595 596 chartP.redraw(); 597 isPaletteChanged = true; 598 } 599 } 600 }); 601 602 this.addMouseListener(new MouseAdapter() { 603 @Override 604 public void mouseDown(MouseEvent e) { 605 // dragX0 = e.x - xgap; 606 // dragY0 = e.y + gap; 607 // 608 // (dragX0 < 0) 609 // dragX0 = 0; 610 // (dragX0 > xgap + plotWidth) 611 // dragX0 = xgap + plotWidth; 612 // (dragY0 < 0) 613 // dragY0 = 0; 614 // (dragY0 > plotHeight + gap) 615 // dragY0 = plotHeight + gap; 616 } 617 618 @Override 619 public void mouseUp(MouseEvent e) { 620 if (paletteValueTable != null) 621 paletteValueTable.refresh(); 622 } 623 }); 624 } 625 } 626 627 /** The dialog to show the palette values in spreadsheet. */ 628 private class PaletteValueTable extends Dialog 629 { 630 private Display display; 631 private Shell tableShell; 632 633 private Table valueTable; 634 635 private static final String RGBNAME = "Color"; 636 private static final String IDXNAME = "Index"; 637 638 public PaletteValueTable(Shell parent, int style) { 639 super(parent, style); 640 } 641 642 public void open() { 643 Shell parent = getParent(); 644 display = parent.getDisplay(); 645 646 tableShell = new Shell(parent, SWT.SHELL_TRIM); 647 tableShell.setFont(curFont); 648 tableShell.setText(""); 649 tableShell.setImage(ViewProperties.getHdfIcon()); 650 tableShell.setLayout(new GridLayout(1, true)); 651 652 Composite content = new Composite(tableShell, SWT.NONE); 653 content.setLayout(new GridLayout(1, true)); 654 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 655 656 GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 657 data.heightHint = 200; 658 content.setLayoutData(data); 659 660 String[] columnNames = { IDXNAME, "Red", "Green", "Blue", RGBNAME }; 661 662 valueTable = new Table(content, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.NO_SCROLL); 663 valueTable.setHeaderVisible(true); 664 valueTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 665 valueTable.setFont(curFont); 666 667 // Add cell editor for changing cell values in-place 668 valueTable.addListener(SWT.MouseDoubleClick, valueTableCellEditor); 669 670 valueTable.addListener(SWT.Resize, new Listener() { 671 @Override 672 public void handleEvent(Event e) { 673 int numColumns = valueTable.getColumnCount(); 674 675 for (int i = 0; i < numColumns; i++) 676 valueTable.getColumn(i).setWidth(valueTable.getClientArea().width / numColumns); 677 } 678 }); 679 680 valueTable.addPaintListener(new PaintListener() { 681 @Override 682 public void paintControl(PaintEvent e) { 683 for (int i = 0; i < valueTable.getItemCount(); i++) { 684 Color cellColor = new Color(display, paletteData[0][i], paletteData[1][i], paletteData[2][i]); 685 686 valueTable.getItem(i).setBackground(4, cellColor); 687 688 cellColor.dispose(); 689 } 690 } 691 }); 692 693 for (int i = 0; i < columnNames.length; i++) { 694 TableColumn column = new TableColumn(valueTable, SWT.NONE); 695 column.setText(columnNames[i]); 696 column.setMoveable(false); 697 column.pack(); 698 } 699 700 for (int i = 0; i < 256; i++) { 701 TableItem item = new TableItem(valueTable, SWT.NONE); 702 item.setFont(curFont); 703 704 item.setText(new String[] { 705 String.valueOf(i), 706 String.valueOf(paletteData[0][i]), 707 String.valueOf(paletteData[1][i]), 708 String.valueOf(paletteData[2][i]), null }); 709 710 item.setBackground(0, Display.getCurrent().getSystemColor(SWT.COLOR_GRAY)); 711 } 712 713 // set cell height for large fonts 714 // int cellRowHeight = Math.max(16, valueTable.getFontMetrics( 715 // valueTable.getFont()).getHeight()); 716 // valueTable.setRowHeight(cellRowHeight); 717 718 Button okButton = new Button(tableShell, SWT.PUSH); 719 okButton.setFont(curFont); 720 okButton.setText(" &OK "); 721 okButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false)); 722 okButton.addSelectionListener(new SelectionAdapter() { 723 @Override 724 public void widgetSelected(SelectionEvent e) { 725 tableShell.dispose(); 726 } 727 }); 728 729 tableShell.pack(); 730 731 int w = 300 + (ViewProperties.getFontSize() - 12) * 10; 732 int h = 600 + (ViewProperties.getFontSize() - 12) * 15; 733 734 tableShell.setSize(w, h); 735 736 Rectangle parentBounds = parent.getBounds(); 737 Point shellSize = tableShell.getSize(); 738 tableShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 739 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 740 741 tableShell.open(); 742 743 while (!tableShell.isDisposed()) { 744 if (!display.readAndDispatch()) 745 display.sleep(); 746 } 747 } 748 749 private void updatePaletteValue(String strValue, int row, int col) { 750 if (strValue == null) 751 return; 752 753 int value = 0; 754 755 try { 756 value = Integer.parseInt(strValue); 757 } 758 catch (Exception ex) { 759 return; 760 } 761 762 if (value < 0 || value > 255) { 763 Tools.showError(tableShell, "Update", "Value is out of range [0, 255]"); 764 return; 765 } 766 767 paletteData[col][row] = value; 768 chartP.redraw(); 769 isPaletteChanged = true; 770 } 771 772 public void refresh() { 773 if (valueTable != null && !valueTable.isDisposed()) 774 valueTable.redraw(); 775 } 776 777 private Listener valueTableCellEditor = new Listener() { 778 @Override 779 public void handleEvent(Event event) { 780 final TableEditor editor = new TableEditor(valueTable); 781 editor.horizontalAlignment = SWT.LEFT; 782 editor.grabHorizontal = true; 783 784 Rectangle clientArea = valueTable.getClientArea(); 785 Point pt = new Point(event.x, event.y); 786 int index = valueTable.getTopIndex(); 787 788 while (index < valueTable.getItemCount()) { 789 boolean visible = false; 790 final TableItem item = valueTable.getItem(index); 791 792 // Only allow editing of RGB values 793 for (int i = 1; i < valueTable.getColumnCount() - 1; i++) { 794 Rectangle rect = item.getBounds(i); 795 796 if (rect.contains(pt)) { 797 final int column = i; 798 final int row = index; 799 800 final Text text = new Text(valueTable, SWT.NONE); 801 text.setFont(curFont); 802 803 Listener textListener = new Listener() { 804 @Override 805 public void handleEvent(final Event e) { 806 switch (e.type) { 807 case SWT.FocusOut: 808 item.setText(column, text.getText()); 809 updatePaletteValue(item.getText(column), row, column - 1); 810 text.dispose(); 811 break; 812 case SWT.Traverse: 813 switch (e.detail) { 814 case SWT.TRAVERSE_RETURN: 815 item.setText(column, text.getText()); 816 updatePaletteValue(item.getText(column), row, column - 1); 817 break; 818 case SWT.TRAVERSE_ESCAPE: 819 text.dispose(); 820 e.doit = false; 821 break; 822 default: 823 break; 824 } 825 break; 826 default: 827 break; 828 } 829 } 830 }; 831 832 text.addListener(SWT.FocusOut, textListener); 833 text.addListener(SWT.Traverse, textListener); 834 editor.setEditor(text, item, i); 835 text.setText(item.getText(i)); 836 text.selectAll(); 837 text.setFocus(); 838 return; 839 } 840 841 if (!visible && rect.intersects(clientArea)) 842 visible = true; 843 } 844 845 if (!visible) 846 return; 847 848 index++; 849 } 850 } 851 }; 852 } 853}