View Javadoc
1 /* 2 * BasicParallelDisplayUI.java 3 * 4 * Created on 19. November 2001, 16:06 5 * 6 * Copyright 2001 Flo Ledermann flo@subnet.at 7 * 8 * Licensed under GNU General Public License (GPL). 9 * See http://www.gnu.org/copyleft/gpl.html 10 */ 11 12 package edu.psu.geovista.app.parvis.gui; 13 14 import edu.psu.geovista.app.parvis.model.*; 15 16 import java.awt.*; 17 import java.awt.image.*; 18 import java.awt.event.*; 19 import java.awt.geom.*; 20 import javax.swing.*; 21 import javax.swing.plaf.*; 22 import javax.swing.border.*; 23 24 import java.util.*; 25 26 /*** 27 * The UI Delegate, responsible for rendering the ParallelDisplay component. 28 * 29 * @author Flo Ledermann flo@subnet.at 30 * @version 0.1 31 */ 32 public class BasicParallelDisplayUI extends ParallelDisplayUI implements MouseListener, MouseMotionListener { 33 34 35 //GeneralPath[] rPaths; 36 int numDimensions; 37 int numRecords; 38 39 Color[] colors; 40 41 int[] conditioning; 42 43 int stepx; 44 45 int hoverAxis = -1; 46 int hoverRecord = -1; 47 48 float axisScale[]; 49 50 int borderH = 20; 51 int borderV = 40; 52 53 int width = 0, height = 0; 54 55 String metaText = null; 56 int metaX = 0, metaY = 0; 57 58 boolean dragAxis = false; 59 int dragX = 0; 60 61 BufferedImage bufferImg = null; 62 BufferedImage brushImg = null; 63 64 boolean needsDeepRepaint = true; 65 66 boolean renderQuality = false; 67 68 /*** Begin of area that has to be repainted. */ 69 //int repaintStartAxis = 0; 70 /*** End of area that has to be repainted. */ 71 //int repaintStopAxis = 0; 72 73 int brushHoverStart = 0; 74 int brushHoverEnd = 0; 75 int brushHoverX = 0; 76 boolean inBrush = false; 77 //ParallelDisplay comp; 78 79 /*** 80 * Default Constructor. Creates a new BasicParallelDisplayUI. 81 */ 82 public BasicParallelDisplayUI() { 83 } 84 85 /*** 86 * Swing method. Returns a new instance. 87 */ 88 public static ComponentUI createUI(JComponent c){ 89 return new BasicParallelDisplayUI(); 90 } 91 92 /*** 93 * Installs this instance as UI delegate for the given component. 94 * 95 * @param c The component, a ParallelDisplay in our case. 96 */ 97 public void installUI(JComponent c){ 98 ParallelDisplay pd = (ParallelDisplay)c; 99 100 pd.addMouseListener(this); 101 pd.addMouseMotionListener(this); 102 103 } 104 105 /*** 106 * Uninstalls this instance from its component. 107 * 108 * @param c The component, a ParallelDisplay in our case. 109 */ 110 public void uninstallUI(JComponent c){ 111 ParallelDisplay pd = (ParallelDisplay)c; 112 113 pd.removeMouseListener(this); 114 pd.removeMouseMotionListener(this); 115 116 numDimensions = 0; 117 numRecords = 0; 118 } 119 120 RenderThread renderThread = null; 121 RenderThread brushThread = null; 122 123 /*** 124 * Renders the component on the screen. 125 * 126 * @param g The graphics object to draw on. 127 * @param c The Component, our ParallelDisplay. 128 */ 129 public void paint(Graphics g, JComponent c){ 130 131 //start our renderThread 132 if (renderThread == null){ 133 renderThread = new RenderThread(this); 134 renderThread.setQuality(false, true); 135 renderThread.setStyle(new BasicStroke(.5f), new Color(0.0f, 0.0f, 0.0f, 0.7f)); 136 renderThread.start(); 137 } 138 139 if (brushThread == null){ 140 brushThread = new RenderThread(this); 141 brushThread.setQuality(false, true); 142 brushThread.setStyle(new BasicStroke(1.0f), new Color(0.0f, 0.0f, 0.0f, 0.8f)); 143 brushThread.setBrushMode(true); 144 brushThread.start(); 145 } 146 147 // set up the environment 148 Graphics2D g2 = (Graphics2D)g; 149 ParallelDisplay comp = (ParallelDisplay)c; 150 151 RenderingHints qualityHints = new RenderingHints(null); 152 153 qualityHints.put(RenderingHints.KEY_ANTIALIASING, 154 RenderingHints.VALUE_ANTIALIAS_ON); 155 156 qualityHints.put(RenderingHints.KEY_RENDERING, 157 RenderingHints.VALUE_RENDER_QUALITY); 158 159 g2.setRenderingHints(qualityHints); 160 161 //workaround flag for model change, resize,... 162 if (comp.deepRepaint){ 163 // throw away buffered image -> complete repaint 164 165 166 width = c.getWidth() - 2*borderH; 167 height = c.getHeight() - 2*borderV; 168 169 numDimensions = comp.getNumAxes(); 170 numRecords = comp.getNumRecords(); 171 172 if(this.conditioning == null){ 173 this.conditioning = new int[numRecords]; 174 } 175 176 //if (this.rPaths == null || this.rPaths.length != numRecords){ 177 //this.rPaths = new GeneralPath[numRecords]; 178 //} 179 //this.assembleAllPaths(comp); 180 181 stepx = width / (numDimensions - 1); 182 183 needsDeepRepaint = true; 184 185 bufferImg = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 186 Graphics2D ig = bufferImg.createGraphics(); 187 ig.setColor(c.getBackground()); 188 ig.fillRect(0,0,c.getWidth(),c.getHeight()); 189 190 renderThread.reset(); 191 brushThread.reset(); 192 renderThread.setCurrentComponent(comp); 193 brushThread.setCurrentComponent(comp); 194 195 if (comp.getBrushedCount() == 0) brushImg = null; 196 renderAll(); 197 198 comp.deepRepaint = false; 199 } 200 201 g2.setColor(c.getBackground()); 202 g2.fillRect(0, 0, comp.getWidth(), comp.getHeight()); 203 204 g2.translate(borderH, borderV); 205 206 // save rendered image in new buffer 207 if (renderThread.getRenderedImage() != null){ 208 // we cant do this becase the renderedImage is only a part of the whole 209 // bufferImg = (BufferedImage)renderThread.getRenderedImage(); 210 Graphics2D ig = bufferImg.createGraphics(); 211 ig.setColor(comp.getBackground()); 212 int startAxis = renderThread.getRenderedRegionStart(); 213 int stopAxis = renderThread.getRenderedRegionStop(); 214 215 //delete area that has been rendered 216 ig.fillRect( startAxis * stepx, 0, (stopAxis - startAxis) * stepx, comp.getHeight()); 217 //and paint it new 218 ig.drawImage(renderThread.getRenderedImage(), 0, 0, comp); 219 } 220 221 if (brushThread.getRenderedImage() != null){ 222 brushImg = brushThread.getRenderedImage(); 223 } 224 225 if (brushImg == null){ 226 synchronized (bufferImg){ 227 g2.drawImage(bufferImg, 0, 0, comp); 228 } 229 } 230 else { 231 Composite oldcomp = g2.getComposite(); 232 233 AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); 234 //previous line changed by FAH 29 july 02 from .2 to .5 235 g2.setComposite(ac); 236 237 g2.drawImage(bufferImg, 0, 0, comp); 238 239 g2.setComposite(oldcomp); 240 g2.drawImage(brushImg, 0, 0, comp); 241 } 242 243 // set up 244 g2.setColor(comp.getForeground()); 245 g2.setStroke(new BasicStroke(1.0f)); 246 247 //draw all the dynamic parts on the screen: 248 249 //axis labels 250 for (int i=0; i<numDimensions; i++){ 251 float curx = i*stepx; 252 253 254 //hovering over Axis 255 if (i==hoverAxis){ 256 g2.setStroke(new BasicStroke(2.5f)); 257 g2.draw(new Line2D.Float(curx, 0, curx, height)); 258 g2.setStroke(new BasicStroke(1.0f)); 259 } 260 else { 261 g2.draw(new Line2D.Float(curx, 0, curx, height)); 262 } 263 264 String label = comp.getAxisLabel(i); 265 if (label != null) { 266 g2.drawString(label, curx - 10, height + 30); 267 } 268 269 g2.drawString("" + comp.getAxisOffset(i), curx + 2, borderV / 2 - 22); 270 g2.drawString("" + (comp.getAxisOffset(i) + comp.getAxisScale(i)), curx + 2, height + borderV / 2 - 5); 271 272 drawArrow(g2, (int)curx, -20, 8, false, (comp.getAxisScale(i) < 0)); 273 } 274 275 //brush Hover 276 if (inBrush) { 277 g2.setColor(new Color(0.7f, 0.0f, 0.0f)); 278 //g2.setColor(Color.blue); 279 g2.setStroke(new BasicStroke(2.5f)); 280 g2.draw(new Line2D.Float(brushHoverX, brushHoverStart, brushHoverX, brushHoverEnd)); 281 } 282 283 //hovering over record 284 //added Frank Hardisty 19 July 2002 285 286 boolean paintHoverNative = false; 287 boolean paintHoverComp = false; 288 int paintHoverRecord = -1; 289 if (comp.indication > 0) { 290 paintHoverComp = true; 291 paintHoverRecord = comp.indication; 292 } 293 if (comp.indication < 0) { 294 paintHoverComp = false; 295 paintHoverRecord = -1; 296 } 297 298 if ((comp.getBoolPreference("hoverLine")) && ( hoverRecord != -1)) { 299 paintHoverNative = true; 300 paintHoverRecord = hoverRecord; 301 } 302 303 304 if (paintHoverNative || paintHoverComp){ 305 ////System.out.println("Painting record " + i); 306 307 Color col = new Color(1.0f, 1.0f, 0.8f); 308 Font oldfont = g2.getFont(); 309 Font newfont = new Font(oldfont.getName(), Font.PLAIN, oldfont.getSize() - 2); 310 g2.setFont(newfont); 311 312 GeneralPath rPath = this.assemblePath(paintHoverRecord,0,numDimensions-1,comp); 313 //float yval = getYValue(paintHoverRecord, 0, comp); 314 315 g2.setStroke(new BasicStroke(2.5f)); 316 g2.draw(rPath); 317 318 g2.setStroke(new BasicStroke(1.5f)); 319 g2.setColor(Color.red); 320 g2.draw(rPath); 321 322 g2.setFont(oldfont); 323 } 324 325 if ((comp.getBoolPreference("hoverText")) && ( paintHoverRecord != -1)){ 326 Color col = new Color(1.0f, 1.0f, 0.8f); 327 for (int j=0; j<numDimensions; j++){ 328 float yval = getYValue(paintHoverRecord, j, comp); 329 drawTooltip(g2,comp.getAxisLabel(j) + "=\n" + comp.getValue(paintHoverRecord, j), stepx * j, (int)yval, col); 330 } 331 } 332 333 //dragging axis 334 if (dragAxis) { 335 AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); 336 g2.setComposite(ac); 337 338 g2.setStroke(new BasicStroke(0.5f)); 339 g2.drawLine(dragX - borderH, 0, dragX - borderH, height); 340 } 341 342 //tooltips 343 if ((comp.getBoolPreference("hoverLine")) && (metaText != null)){ 344 drawTooltip(g2, metaText, metaX, metaY + 10, new Color(0.7f, 0.7f, 1.0f)); 345 } 346 347 g2.translate(-borderH, -borderV); 348 349 } 350 351 void renderRegion(int startAxis, int stopAxis){ 352 if (startAxis < 0) startAxis = 0; 353 if (stopAxis >= numDimensions) stopAxis = numDimensions-1; 354 355 renderThread.setRegion(startAxis, stopAxis); 356 renderThread.render(); 357 358 if (brushImg != null){ 359 //if we do this, we have to add another buffer img for the brush in paint() 360 //brushThread.setRegion(startAxis, stopAxis); 361 brushThread.render(); 362 } 363 } 364 365 void renderAll(){ 366 renderRegion(0, numDimensions - 1); 367 } 368 369 public void renderBrush(){ 370 if (brushThread == null){ 371 return; 372 } 373 brushThread.setRegion(0, numDimensions - 1); 374 brushThread.render(); 375 } 376 // when do we want to do this? upon 1. init 2. moved axis 3. resized axis 377 private void assembleAllPaths(ParallelDisplay comp){ 378 // for (int i = 0; i < this.rPaths.length; i++){ 379 // this.rPaths[i] = assemblePath(i,0,this.numDimensions-1,comp); 380 // } 381 } 382 private GeneralPath assemblePath(int num, int startAxis, int stopAxis, ParallelDisplay comp){ 383 GeneralPath rPath = new GeneralPath(); 384 float val = this.getYValue(num,startAxis,comp); 385 //System.out.println("PCPUI val = " + val); 386 boolean wasNaN = false; 387 if (!Float.isNaN(val)) { 388 rPath.moveTo(stepx * startAxis,val); 389 wasNaN = false; 390 } else { 391 wasNaN = true; 392 } 393 for (int j=startAxis+1; j<=stopAxis; j++){ 394 val = getYValue(num, j, comp); 395 396 //System.out.println("PCPUI val = " + val); 397 if (Float.isNaN(val)){//if this one is NaN 398 wasNaN = true; 399 } 400 else {//if this one is not NaN 401 if (wasNaN){//lastone was NaN, so moveTo 402 rPath.moveTo(stepx * j, val); 403 } else {//usual case, usual number following on usual number 404 rPath.lineTo(stepx * j, val); 405 } 406 wasNaN = false; 407 } 408 } 409 return rPath; 410 411 } 412 413 void drawRecord(Graphics2D g2, ParallelDisplay comp, int num, int startAxis, int stopAxis){ 414 if (this.conditioning.length != this.numRecords){ 415 this.conditioning = new int[numRecords]; 416 } 417 if (this.conditioning[num] < 0){ 418 return; 419 } 420 GeneralPath rPath = null; 421 // if (startAxis == 0 && stopAxis == this.numDimensions-1){ 422 // rPath = this.rPaths[num]; 423 // } else { 424 rPath = this.assemblePath(num,startAxis,stopAxis, comp); 425 // } 426 if (this.colors != null) { 427 g2.setColor(this.colors[num]); 428 } 429 if (inBrush){ 430 g2.setColor(Color.blue); 431 } 432 g2.draw(rPath); 433 } 434 void drawBrushedRecord(Graphics2D g2, ParallelDisplay comp, int num, int startAxis, int stopAxis){ 435 if (this.conditioning[num] < 0){ 436 return; 437 } 438 GeneralPath rPath = this.assemblePath(num,startAxis,stopAxis,comp); 439 //if (this.colors != null) { 440 g2.setColor(Color.darkGray); 441 //} 442 g2.draw(rPath); 443 } 444 public void setColors(Color[] colors){ 445 this.colors = colors; 446 } 447 public void setConditioning(int[] conditioning){ 448 this.conditioning = conditioning; 449 } 450 /*** 451 * Helper function to draw a "tooltip" on the given graphics object. 452 * 453 * @param g2 The Graphics2D Object to draw on. 454 * @param text The (multiline) text of the tooltip. 455 * @param x The x coordinate. 456 * @param y The y coordinate. 457 * @param col The background color. 458 */ 459 private void drawTooltip(Graphics2D g2, String text, int x, int y, Color col){ 460 int i; 461 int mheight, mwidth = 0; 462 int numLines, lineHeight; 463 464 StringTokenizer tok = new StringTokenizer(text,"\n"); 465 numLines = tok.countTokens(); 466 String lines[] = new String[numLines]; 467 468 for (i=0; i<numLines; i++){ 469 lines[i] = tok.nextToken(); 470 471 int tempwidth = g2.getFontMetrics().stringWidth(lines[i]) + 6; 472 if (tempwidth > mwidth) mwidth = tempwidth; 473 } 474 475 lineHeight = g2.getFontMetrics().getHeight(); 476 mheight = numLines * lineHeight + 2; 477 478 x += 10; 479 y += 10; 480 if (x + mwidth > width) x -= (mwidth + 20); 481 482 AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); 483 g2.setComposite(ac); 484 485 g2.setStroke(new BasicStroke(0.5f)); 486 g2.setColor(new Color(0.2f, 0.2f, 0.2f)); 487 g2.drawRect(x, y, mwidth, mheight); 488 g2.setColor(col); 489 g2.fillRect(x+1, y+1, mwidth-1, mheight-1); 490 491 g2.setColor(Color.black); 492 493 ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); 494 g2.setComposite(ac); 495 496 for (i=0; i<numLines; i++){ 497 g2.drawString(lines[i], x + 3, y + (i+1) * lineHeight - 4); 498 } 499 500 } 501 502 /*** 503 * Helper function to draw an arrow. 504 * 505 * @param g2 The Graphics2D Object to draw on. 506 * @param x The x coordinate. 507 * @param y The y coordinate. 508 * @param size The size in pixels. 509 * @param horizontal If true, the arrow is drawn horizontally, if false vertically. 510 * @param topright If true, the arrowhead is top/right, if false bottom/left. 511 */ 512 private void drawArrow(Graphics2D g2, int x, int y, int size, boolean horizontal, boolean topright){ 513 514 if (horizontal){ 515 516 g2.drawLine(x-size/2, y, x+size/2, y); 517 518 if (topright){ 519 g2.drawLine(x + size/4, y-size/4, x+size/2, y); 520 g2.drawLine(x + size/4, y+size/4, x+size/2, y); 521 } 522 else{ 523 g2.drawLine(x - size/4, y-size/4, x-size/2, y); 524 g2.drawLine(x - size/4, y+size/4, x-size/2, y); 525 } 526 } 527 else { 528 529 g2.drawLine(x, y-size/2, x, y+size/2); 530 531 if (topright){ 532 g2.drawLine(x + size/4, y-size/4, x, y-size/2); 533 g2.drawLine(x - size/4, y-size/4, x, y-size/2); 534 } 535 else{ 536 g2.drawLine(x + size/4, y+size/4, x, y+size/2); 537 g2.drawLine(x - size/4, y+size/4, x, y+size/2); 538 } 539 } 540 } 541 542 /*** 543 * Helper function, returns the y value (on screen) for a given record. Scale 544 * factors and translation is applied. 545 * 546 * @param record The recordnumber. 547 * @param axis The axis to calculate the y value for. 548 * @param comp our "parent" component. 549 */ 550 private float getYValue(int record, int axis, ParallelDisplay comp){ 551 float value = comp.getValue(record, axis); 552 553 value -= comp.getAxisOffset(axis); 554 value *= (comp.getHeight() - 2 * borderV) / comp.getAxisScale(axis); 555 556 return value; 557 } 558 559 // record old coordinates for dragging 560 int oldMouseX, oldMouseY; 561 int activeAxis = -1; 562 float oldScale, oldOffset; 563 564 //0.0 - 1.0 value of loacion of click on axis 565 float clickValue; 566 567 // actual value of point clicked on axis 568 float clickAxisValue; 569 570 int clickModifiers; 571 572 /*** 573 * Invoked when the mouse exits the component. 574 * 575 * @param e The mouse event. 576 */ 577 public void mouseExited(MouseEvent e) { 578 hoverRecord = -1; 579 } 580 581 /*** 582 * Invoked when a mouse button has been released on a component. Checks 583 * if something has been dragged and finishes the drag process. 584 * 585 * @param e The mouse event. 586 */ 587 public void mouseReleased(MouseEvent e) { 588 ParallelDisplay comp = (ParallelDisplay)e.getComponent(); 589 590 switch (comp.getEditMode()){ 591 case ParallelDisplay.REORDER: 592 dragAxis = false; 593 break; 594 case ParallelDisplay.BRUSH: 595 inBrush = false; 596 break; 597 } 598 } 599 600 /*** 601 * Invoked when a mouse button has been pressed on a component. 602 * Checks if the user starts dragging something. 603 * 604 * @param e The mouse event. 605 */ 606 public void mousePressed(MouseEvent e) { 607 ParallelDisplay comp = (ParallelDisplay)e.getComponent(); 608 609 oldMouseX = e.getX(); 610 oldMouseY = e.getY(); 611 612 activeAxis = hoverAxis; 613 614 clickModifiers = e.getModifiers(); 615 616 if (activeAxis != -1){ 617 618 oldScale = comp.getAxisScale(activeAxis); 619 oldOffset = comp.getAxisOffset(activeAxis); 620 621 clickValue = ((float)oldMouseY - borderV) / (comp.getHeight() - 2*borderV); 622 clickAxisValue = comp.getAxisOffset(activeAxis) + clickValue * comp.getAxisScale(activeAxis); 623 } 624 625 switch (comp.getEditMode()){ 626 case ParallelDisplay.REORDER: 627 dragAxis = true; 628 break; 629 case ParallelDisplay.BRUSH: 630 brushHoverStart = oldMouseY - borderV; 631 brushHoverEnd = oldMouseY - borderV; 632 brushHoverX = oldMouseX - borderH; 633 inBrush = true; 634 hoverRecord = -1; 635 this.createBrushImage(comp); 636 } 637 638 } 639 640 public void createBrushImage(ParallelDisplay comp) { 641 if (brushImg == null) { 642 //brushImg = (BufferedImage)comp.createImage(comp.getWidth(), comp.getHeight()); 643 brushImg = new BufferedImage(comp.getWidth(), comp.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); 644 Graphics2D ig = brushImg.createGraphics(); 645 //fill with transparent white 646 ig.setColor(new Color(1.0f, 1.0f, 1.0f, 0.0f)); 647 ig.fillRect(0,0,comp.getWidth(), comp.getHeight()); 648 } 649 } 650 651 /*** 652 * Invoked when a mouse button is pressed on a component and then 653 * dragged. Mouse drag events will continue to be delivered to 654 * the component where the first originated until the mouse button is 655 * released (regardless of whether the mouse position is within the 656 * bounds of the component). 657 * 658 * Depending on the current mode, this method performs scaling, translating 659 * or reordering of axes. 660 * 661 * @param e The mouse event. 662 */ 663 public void mouseDragged(MouseEvent e) { 664 ParallelDisplay comp = (ParallelDisplay)e.getComponent(); 665 666 int mouseX = e.getX(); 667 int mouseY = e.getY(); 668 669 setMetaInfo(null,0,0); 670 671 switch (comp.getEditMode()){ 672 case ParallelDisplay.SCALE: 673 if (activeAxis != -1){ 674 float way = ((float)(oldMouseY - mouseY)) / (comp.getHeight() - 2*borderV); 675 comp.setAxisScale(activeAxis, oldScale + (way * oldScale)) ; 676 float newValue = clickValue * (comp.getAxisScale(activeAxis) - oldScale); 677 comp.setAxisOffset(activeAxis, oldOffset - newValue); 678 679 renderRegion(activeAxis - 1, activeAxis + 1); 680 } 681 break; 682 case ParallelDisplay.TRANSLATE: 683 if (activeAxis != -1){ 684 float way = ((float)(oldMouseY - mouseY)) / (comp.getHeight() - 2*borderV); 685 way *= comp.getAxisScale(activeAxis); 686 comp.setAxisOffset(activeAxis, oldOffset + way); 687 688 renderRegion(activeAxis - 1, activeAxis + 1); 689 } 690 break; 691 case ParallelDisplay.REORDER: 692 if (activeAxis != -1){ 693 int deltaX = mouseX - oldMouseX; 694 int num = activeAxis + deltaX / stepx; 695 696 if (num < 0) num = 0; 697 if (num >= numDimensions) num = numDimensions-1; 698 699 dragX = mouseX; 700 701 if (activeAxis != num) { 702 comp.swapAxes(activeAxis, num); 703 704 ////System.out.println("setting repaint axes: " + (Math.min(num,activeAxis) - 1) + ", " + (Math.max(num,activeAxis) + 1)); 705 706 renderRegion(Math.min(num,activeAxis) - 1, Math.max(num,activeAxis) + 1); 707 708 activeAxis = num; 709 hoverAxis = num; 710 oldMouseX = stepx * num + borderH; 711 } 712 // to display hoverAxis 713 comp.repaint(); 714 } 715 break; 716 case ParallelDisplay.BRUSH: 717 if (activeAxis != -1){ 718 brushHoverEnd = mouseY - borderV; 719 float releaseValue = ((float)mouseY - borderV) / (comp.getHeight() - 2*borderV); 720 releaseValue = comp.getAxisOffset(activeAxis) + releaseValue * comp.getAxisScale(activeAxis); 721 float lowerBound = Math.min(clickAxisValue, releaseValue); 722 float upperBound = Math.max(clickAxisValue, releaseValue); 723 boolean doSoft = comp.getBoolPreference("softBrush"); 724 float radius = 0.0f; 725 int ids[]; 726 if (doSoft){ 727 radius = comp.getFloatPreference("brushRadius") * (upperBound - lowerBound); 728 if (radius == 0.0f) { 729 //System.out.println("radius is zero"); 730 doSoft = false; 731 } 732 ids = comp.getRecordsByValueRange(activeAxis, lowerBound - radius, upperBound + radius); 733 } 734 else { 735 ids = comp.getRecordsByValueRange(activeAxis, lowerBound, upperBound); 736 } 737 int id = 0; 738 for (int i=0; i<comp.getNumRecords(); i++){ 739 if ((ids.length > 0) && (i == ids[id])){ 740 //record is inside brush region 741 742 float brushVal = 1.0f; 743 744 if (doSoft){ 745 float val = comp.getValue(i, activeAxis); 746 if (val < lowerBound) { 747 brushVal = 1.0f - ( -val + lowerBound ) / radius; 748 } 749 if (val > upperBound) { 750 brushVal = 1.0f - ( val - upperBound ) / radius; 751 } 752 } 753 754 if (e.isShiftDown() && e.isAltDown()){ 755 // shift + alt pressed -> intersect mode 756 // we don't have anything to do 757 } 758 else if (e.isShiftDown()){ 759 // shift pressed -> expand mode 760 brushVal = brushVal + comp.getBrushValue(i); 761 if (brushVal > 1.0f) brushVal = 1.0f; 762 comp.setBrushValue(i, brushVal); 763 } 764 else if (e.isAltDown()){ 765 // alt pressed -> subtract mode 766 comp.setBrushValue(i, 1.0f - brushVal); 767 } 768 else { 769 // no modifiers -> normal mode 770 comp.setBrushValue(i, brushVal); 771 } 772 if (id < ids.length-1) id++; 773 } 774 else { 775 if (e.isShiftDown() && e.isAltDown()){ 776 // shift + alt pressed -> intersect mode 777 // clear all values outside our brush 778 if (comp.getBrushValue(i) > 0) 779 comp.setBrushValue(i, 0.0f); 780 } 781 else if (e.isShiftDown()){ 782 // shift pressed -> expand mode 783 // do nothing 784 } 785 else if (e.isAltDown()){ 786 // alt pressed -> subtract mode 787 // do nothing 788 } 789 else { 790 // no modifiers -> normal mode 791 comp.setBrushValue(i, 0.0f); 792 } 793 } 794 } 795 } 796 797 renderBrush(); 798 // to see brush line in realtime 799 comp.repaint(); 800 801 comp.fireSelectionChanged(); 802 break; 803 804 } 805 806 } 807 808 809 /*** 810 * Invoked when the mouse has been clicked on a component. 811 * 812 * Checks if the click hit an arrow and inverts the corresponding axis. 813 * 814 * @param e The mouse event. 815 */ 816 public void mouseClicked(MouseEvent e) { 817 ParallelDisplay comp = (ParallelDisplay)e.getComponent(); 818 819 //arrow clicked or invert mode 820 if ((comp.getEditMode() == ParallelDisplay.INVERT) || (e.getY() <= 25 && e.getY()>12)) { 821 if (hoverAxis != -1){ 822 comp.setAxisOffset(hoverAxis, comp.getAxisOffset(hoverAxis) + comp.getAxisScale(hoverAxis)); 823 comp.setAxisScale(hoverAxis, comp.getAxisScale(hoverAxis) * -1); 824 825 renderRegion(activeAxis - 1, activeAxis + 1); 826 827 } 828 } 829 830 831 } 832 833 /*** 834 * Invoked when the mouse enters a component. 835 */ 836 public void mouseEntered(MouseEvent e) { 837 } 838 /*** Added by Frank Hardisty 19 July 2002 839 * 840 * This method is called to create a hover record from outside the component 841 * 842 */ 843 844 public void setHoverRecord(int record, ParallelDisplay comp){ 845 if (record != hoverRecord) { 846 hoverRecord = record; 847 //if (hoverRecord != -1) { 848 // setMetaInfo(comp.getRecordLabel(hoverRecord), mousex, mousey); 849 //} 850 comp.repaint(); 851 } 852 853 } 854 855 /*** 856 * Invoked when the mouse button has been moved on a component 857 * (with no buttons no down). 858 * 859 * Displays tooltips if mouse is hovering over axes or records. 860 * 861 * @param e The mouse event. 862 */ 863 public void mouseMoved(MouseEvent e) { 864 865 if (! inBrush ){ 866 int mousex = e.getX() - borderH; 867 int mousey = e.getY() - borderV; 868 869 int oldAxis = hoverAxis; 870 int oldRecord = hoverRecord; 871 872 ParallelDisplay comp = (ParallelDisplay)e.getComponent(); 873 874 hoverAxis = -1; 875 876 for (int i=0; i<numDimensions; i++){ 877 if ((mousex > (i*stepx - 3)) && (mousex < (i*stepx + 3))) { 878 hoverAxis = i; 879 break; 880 } 881 } 882 883 hoverRecord = getRecordByCoordinates(mousex, mousey, comp); 884 885 //added frank Hardisty 19 july 2002 886 if (oldRecord != hoverRecord) { 887 comp.fireIndicationChanged(hoverRecord); 888 } 889 890 if ((oldAxis != hoverAxis) || (oldRecord != hoverRecord)){ 891 if (hoverAxis != -1){ 892 setMetaInfo(comp.getAxisLabel(hoverAxis), mousex, mousey); 893 894 switch (comp.getEditMode()){ 895 case ParallelDisplay.REORDER: 896 comp.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); 897 break; 898 case ParallelDisplay.SCALE: 899 comp.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); 900 break; 901 case ParallelDisplay.TRANSLATE: 902 comp.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); 903 break; 904 case ParallelDisplay.INVERT: 905 comp.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); 906 break; 907 case ParallelDisplay.BRUSH: 908 comp.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 909 break; 910 } 911 912 } 913 else { 914 setMetaInfo(null,0,0); 915 916 comp.resetCursor(); 917 } 918 919 if (hoverRecord != -1) { 920 setMetaInfo(comp.getRecordLabel(hoverRecord), mousex, mousey); 921 } 922 923 comp.repaint(); 924 } 925 } 926 927 } 928 929 /*** 930 * Helper method to display a tooltip on hover. 931 */ 932 private void setMetaInfo(String text, int x, int y){ 933 metaText = text; 934 metaX = x; 935 metaY = y; 936 } 937 938 /*** 939 * Returns the record that goes through the screen coordinates x,y. The first 940 * record that is found is returned. 941 * 942 * @param x The x screen coordinate. 943 * @param y The y screen coordinate. 944 * @param comp The "parent" component. 945 * 946 * @return The recordnumber of the first record found passing through the given point. 947 */ 948 public int getRecordByCoordinates(int x, int y, ParallelDisplay comp){ 949 for (int i=0; i<numDimensions - 1; i++){ 950 if ((x >= i*stepx) && (x < (i+1)*stepx)) { 951 float part = (x - i*stepx) / (float)stepx; 952 953 for (int j=0; j<numRecords; j++){ 954 float recVal = (1-part) * getYValue(j,i,comp) + part * getYValue(j,i+1,comp); 955 //System.out.println("getRecordByCoordinates" + recVal); 956 if (Math.abs(recVal - y) < 3.0) return j; 957 } 958 break; 959 } 960 } 961 962 return -1; 963 } 964 /*** 965 * Returns the record that goes through the screen coordinates x,y. The first 966 * record that is found is returned. 967 * 968 * @param x The x screen coordinate. 969 * @param y The y screen coordinate. 970 * @param comp The "parent" component. 971 * 972 * @return The recordnumber of the first record found passing through the given point. 973 */ 974 public int[] getAllRecordsByCoordinates(Rectangle2D hitBox, ParallelDisplay comp){ 975 int x = (int)hitBox.getX(); 976 int y = (int)hitBox.getY(); 977 int width = (int)hitBox.getWidth(); 978 int height = (int)hitBox.getHeight(); 979 Vector recs = new Vector(); 980 for (int i=0; i<numDimensions - 1; i++){ 981 if ((x >= i*stepx) && (x < (i+1)*stepx)) {//if x part matches 982 float part = (x - i*stepx) / (float)stepx; 983 //System.out.println(part); 984 for (int j=0; j<numRecords; j++){ 985 float recVal = (1-part) * getYValue(j,i,comp) + part * getYValue(j,i+1,comp); 986 987 if (Math.abs(recVal - y) < 3.0) { 988 recs.add(new Integer(j)); 989 } 990 991 } 992 993 } 994 } 995 996 return null; 997 } 998 999 }

This page was automatically generated by Maven