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