1. /*
  2. * @(#)MetalTabbedPaneUI.java 1.24 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.metal;
  11. import javax.swing.*;
  12. import javax.swing.event.*;
  13. import java.awt.*;
  14. import java.awt.event.*;
  15. import javax.swing.plaf.*;
  16. import java.io.Serializable;
  17. import javax.swing.plaf.basic.BasicTabbedPaneUI;
  18. /**
  19. * The Metal subclass of BasicTabbedPaneUI.
  20. * <p>
  21. * <strong>Warning:</strong>
  22. * Serialized objects of this class will not be compatible with
  23. * future Swing releases. The current serialization support is appropriate
  24. * for short term storage or RMI between applications running the same
  25. * version of Swing. A future release of Swing will provide support for
  26. * long term persistence.
  27. *
  28. * @version 1.19 08/28/98
  29. * @author Tom Santos
  30. */
  31. public class MetalTabbedPaneUI extends BasicTabbedPaneUI {
  32. protected int minTabWidth = 40;
  33. protected Color tabAreaBackground;
  34. protected Color selectColor;
  35. protected Color selectHighlight;
  36. public static ComponentUI createUI( JComponent x ) {
  37. return new MetalTabbedPaneUI();
  38. }
  39. protected LayoutManager createLayoutManager() {
  40. return new TabbedPaneLayout();
  41. }
  42. protected void installDefaults() {
  43. super.installDefaults();
  44. tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground");
  45. selectColor = UIManager.getColor("TabbedPane.selected");
  46. selectHighlight = UIManager.getColor("TabbedPane.selectHighlight");
  47. }
  48. protected void paintTabBorder( Graphics g, int tabPlacement,
  49. int tabIndex, int x, int y, int w, int h,
  50. boolean isSelected) {
  51. int bottom = y + (h-1);
  52. int right = x + (w-1);
  53. switch ( tabPlacement ) {
  54. case LEFT:
  55. paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
  56. break;
  57. case BOTTOM:
  58. paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
  59. break;
  60. case RIGHT:
  61. paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
  62. break;
  63. case TOP:
  64. default:
  65. paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
  66. }
  67. }
  68. protected void paintTopTabBorder( int tabIndex, Graphics g,
  69. int x, int y, int w, int h,
  70. int btm, int rght,
  71. boolean isSelected ) {
  72. int currentRun = getRunForTab( tabPane.getTabCount(), tabIndex );
  73. int lastIndex = lastTabInRun( tabPane.getTabCount(), currentRun );
  74. int firstIndex = tabRuns[ currentRun ];
  75. boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
  76. int bottom = h - 1;
  77. int right = w - 1;
  78. //
  79. // Paint Gap
  80. //
  81. if ( shouldFillGap( currentRun, tabIndex, x, y ) ) {
  82. g.translate( x, y );
  83. if ( leftToRight ) {
  84. g.setColor( getColorForGap( currentRun, x, y + 1 ) );
  85. g.fillRect( 1, 0, 5, 3 );
  86. g.fillRect( 1, 3, 2, 2 );
  87. } else {
  88. g.setColor( getColorForGap( currentRun, x + w - 1, y + 1 ) );
  89. g.fillRect( right - 5, 0, 5, 3 );
  90. g.fillRect( right - 2, 3, 2, 2 );
  91. }
  92. g.translate( -x, -y );
  93. }
  94. g.translate( x, y );
  95. //
  96. // Paint Border
  97. //
  98. g.setColor( darkShadow );
  99. if ( leftToRight ) {
  100. // Paint slant
  101. g.drawLine( 1, 5, 6, 0 );
  102. // Paint top
  103. g.drawLine( 6, 0, right, 0 );
  104. // Paint right
  105. if ( tabIndex==lastIndex ) {
  106. // last tab in run
  107. g.drawLine( right, 1, right, bottom );
  108. }
  109. // Paint left
  110. if ( tabIndex != tabRuns[ runCount - 1 ] ) {
  111. // not the first tab in the last run
  112. g.drawLine( 0, 0, 0, bottom );
  113. } else {
  114. // the first tab in the last run
  115. g.drawLine( 0, 6, 0, bottom );
  116. }
  117. } else {
  118. // Paint slant
  119. g.drawLine( right - 1, 5, right - 6, 0 );
  120. // Paint top
  121. g.drawLine( right - 6, 0, 0, 0 );
  122. // Paint right
  123. if ( tabIndex != tabRuns[ runCount - 1 ] ) {
  124. // not the first tab in the last run
  125. g.drawLine( right, 0, right, bottom );
  126. } else {
  127. // the first tab in the last run
  128. g.drawLine( right, 6, right, bottom );
  129. }
  130. // Paint left
  131. if ( tabIndex==lastIndex ) {
  132. // last tab in run
  133. g.drawLine( 0, 1, 0, bottom );
  134. }
  135. }
  136. //
  137. // Paint Highlight
  138. //
  139. g.setColor( isSelected ? selectHighlight : highlight );
  140. if ( leftToRight ) {
  141. // Paint slant
  142. g.drawLine( 1, 6, 6, 1 );
  143. // Paint top
  144. g.drawLine( 6, 1, right, 1 );
  145. // Paint left
  146. g.drawLine( 1, 6, 1, bottom );
  147. // paint highlight in the gap on tab behind this one
  148. // on the left end (where they all line up)
  149. if ( tabIndex==firstIndex && tabIndex!=tabRuns[runCount - 1] ) {
  150. // first tab in run but not first tab in last run
  151. if (tabPane.getSelectedIndex()==tabRuns[currentRun+1]) {
  152. // tab in front of selected tab
  153. g.setColor( selectHighlight );
  154. }
  155. else {
  156. // tab in front of normal tab
  157. g.setColor( highlight );
  158. }
  159. g.drawLine( 1, 0, 1, 4 );
  160. }
  161. } else {
  162. // Paint slant
  163. g.drawLine( right - 1, 6, right - 6, 1 );
  164. // Paint top
  165. g.drawLine( right - 6, 1, 1, 1 );
  166. // Paint left
  167. if ( tabIndex==lastIndex ) {
  168. // last tab in run
  169. g.drawLine( 1, 1, 1, bottom );
  170. } else {
  171. g.drawLine( 0, 1, 0, bottom );
  172. }
  173. }
  174. g.translate( -x, -y );
  175. }
  176. protected boolean shouldFillGap( int currentRun, int tabIndex, int x, int y ) {
  177. boolean result = false;
  178. if ( currentRun == runCount - 2 ) { // If it's the second to last row.
  179. Rectangle lastTabBounds = getTabBounds( tabPane, tabPane.getTabCount() - 1 );
  180. Rectangle tabBounds = getTabBounds( tabPane, tabIndex );
  181. if (MetalUtils.isLeftToRight(tabPane)) {
  182. int lastTabRight = lastTabBounds.x + lastTabBounds.width - 1;
  183. // is the right edge of the last tab to the right
  184. // of the left edge of the current tab?
  185. if ( lastTabRight > tabBounds.x + 2 ) {
  186. return true;
  187. }
  188. } else {
  189. int lastTabLeft = lastTabBounds.x;
  190. int currentTabRight = tabBounds.x + tabBounds.width - 1;
  191. // is the left edge of the last tab to the left
  192. // of the right edge of the current tab?
  193. if ( lastTabLeft < currentTabRight - 2 ) {
  194. return true;
  195. }
  196. }
  197. } else {
  198. // fill in gap for all other rows except last row
  199. result = currentRun != runCount - 1;
  200. }
  201. return result;
  202. }
  203. protected Color getColorForGap( int currentRun, int x, int y ) {
  204. final int shadowWidth = 4;
  205. int selectedIndex = tabPane.getSelectedIndex();
  206. int startIndex = tabRuns[ currentRun + 1 ];
  207. int endIndex = lastTabInRun( tabPane.getTabCount(), currentRun + 1 );
  208. int tabOverGap = -1;
  209. // Check each tab in the row that is 'on top' of this row
  210. for ( int i = startIndex; i <= endIndex; ++i ) {
  211. Rectangle tabBounds = getTabBounds( tabPane, i );
  212. int tabLeft = tabBounds.x;
  213. int tabRight = (tabBounds.x + tabBounds.width) - 1;
  214. // Check to see if this tab is over the gap
  215. if ( MetalUtils.isLeftToRight(tabPane) ) {
  216. if ( tabLeft <= x && tabRight - shadowWidth > x ) {
  217. return selectedIndex == i ? selectColor : tabPane.getBackgroundAt( i );
  218. }
  219. }
  220. else {
  221. if ( tabLeft + shadowWidth < x && tabRight >= x ) {
  222. return selectedIndex == i ? selectColor : tabPane.getBackgroundAt( i );
  223. }
  224. }
  225. }
  226. return tabPane.getBackground();
  227. }
  228. protected void paintLeftTabBorder( int tabIndex, Graphics g,
  229. int x, int y, int w, int h,
  230. int btm, int rght,
  231. boolean isSelected ) {
  232. int tabCount = tabPane.getTabCount();
  233. int currentRun = getRunForTab( tabCount, tabIndex );
  234. int lastIndex = lastTabInRun( tabCount, currentRun );
  235. int firstIndex = tabRuns[ currentRun ];
  236. g.translate( x, y );
  237. int bottom = h - 1;
  238. int right = w - 1;
  239. //
  240. // Paint part of the tab above
  241. //
  242. if ( tabIndex != firstIndex ) {
  243. g.setColor( tabPane.getSelectedIndex() == tabIndex - 1 ?
  244. selectColor :
  245. tabPane.getBackgroundAt( tabIndex - 1 ) );
  246. g.fillRect( 2, 0, 4, 3 );
  247. g.drawLine( 2, 3, 2, 3 );
  248. }
  249. //
  250. // Paint Highlight
  251. //
  252. g.setColor( isSelected ? selectHighlight : highlight );
  253. // Paint slant
  254. g.drawLine( 1, 6, 6, 1 );
  255. // Paint top
  256. g.drawLine( 6, 1, right, 1 );
  257. // Paint left
  258. g.drawLine( 1, 6, 1, bottom );
  259. if ( tabIndex != firstIndex ) {
  260. g.setColor( tabPane.getSelectedIndex() == tabIndex - 1 ?
  261. selectHighlight :
  262. highlight );
  263. g.drawLine( 1, 0, 1, 4 );
  264. }
  265. //
  266. // Paint Border
  267. //
  268. g.setColor( darkShadow );
  269. // Paint slant
  270. g.drawLine( 1, 5, 6, 0 );
  271. // Paint top
  272. g.drawLine( 6, 0, right, 0 );
  273. // Paint left
  274. if ( tabIndex != firstIndex ) {
  275. g.drawLine( 0, 0, 0, bottom );
  276. } else {
  277. g.drawLine( 0, 6, 0, bottom );
  278. }
  279. // Paint bottom
  280. if ( tabIndex == lastIndex ) {
  281. g.drawLine( 0, bottom, right, bottom );
  282. }
  283. g.translate( -x, -y );
  284. }
  285. protected void paintBottomTabBorder( int tabIndex, Graphics g,
  286. int x, int y, int w, int h,
  287. int btm, int rght,
  288. boolean isSelected ) {
  289. int tabCount = tabPane.getTabCount();
  290. int currentRun = getRunForTab( tabCount, tabIndex );
  291. int lastIndex = lastTabInRun( tabCount, currentRun );
  292. int firstIndex = tabRuns[ currentRun ];
  293. boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
  294. int bottom = h - 1;
  295. int right = w - 1;
  296. //
  297. // Paint Gap
  298. //
  299. if ( shouldFillGap( currentRun, tabIndex, x, y ) ) {
  300. g.translate( x, y );
  301. if ( leftToRight ) {
  302. g.setColor( getColorForGap( currentRun, x, y ) );
  303. g.fillRect( 1, bottom - 4, 3, 5 );
  304. g.fillRect( 4, bottom - 1, 2, 2 );
  305. } else {
  306. g.setColor( getColorForGap( currentRun, x + w - 1, y ) );
  307. g.fillRect( right - 3, bottom - 3, 3, 4 );
  308. g.fillRect( right - 5, bottom - 1, 2, 2 );
  309. g.drawLine( right - 1, bottom - 4, right - 1, bottom - 4 );
  310. }
  311. g.translate( -x, -y );
  312. }
  313. g.translate( x, y );
  314. //
  315. // Paint Border
  316. //
  317. g.setColor( darkShadow );
  318. if ( leftToRight ) {
  319. // Paint slant
  320. g.drawLine( 1, bottom - 5, 6, bottom );
  321. // Paint bottom
  322. g.drawLine( 6, bottom, right, bottom );
  323. // Paint right
  324. if ( tabIndex == lastIndex ) {
  325. g.drawLine( right, 0, right, bottom );
  326. }
  327. // Paint left
  328. if ( tabIndex != tabRuns[ runCount - 1 ] ) {
  329. g.drawLine( 0, 0, 0, bottom );
  330. } else {
  331. g.drawLine( 0, 0, 0, bottom - 6 );
  332. }
  333. } else {
  334. // Paint slant
  335. g.drawLine( right - 1, bottom - 5, right - 6, bottom );
  336. // Paint bottom
  337. g.drawLine( right - 6, bottom, 0, bottom );
  338. // Paint right
  339. if ( tabIndex != tabRuns[ runCount - 1 ] ) {
  340. // not the first tab in the last run
  341. g.drawLine( right, 0, right, bottom );
  342. } else {
  343. // the first tab in the last run
  344. g.drawLine( right, 0, right, bottom - 6 );
  345. }
  346. // Paint left
  347. if ( tabIndex==lastIndex ) {
  348. // last tab in run
  349. g.drawLine( 0, 0, 0, bottom );
  350. }
  351. }
  352. //
  353. // Paint Highlight
  354. //
  355. g.setColor( isSelected ? selectHighlight : highlight );
  356. if ( leftToRight ) {
  357. // Paint slant
  358. g.drawLine( 1, bottom - 6, 6, bottom - 1 );
  359. // Paint left
  360. g.drawLine( 1, 0, 1, bottom - 6 );
  361. // paint highlight in the gap on tab behind this one
  362. // on the left end (where they all line up)
  363. if ( tabIndex==firstIndex && tabIndex!=tabRuns[runCount - 1] ) {
  364. // first tab in run but not first tab in last run
  365. if (tabPane.getSelectedIndex()==tabRuns[currentRun+1]) {
  366. // tab in front of selected tab
  367. g.setColor( selectHighlight );
  368. }
  369. else {
  370. // tab in front of normal tab
  371. g.setColor( highlight );
  372. }
  373. g.drawLine( 1, bottom - 4, 1, bottom );
  374. }
  375. } else {
  376. // Paint left
  377. if ( tabIndex==lastIndex ) {
  378. // last tab in run
  379. g.drawLine( 1, 0, 1, bottom - 1 );
  380. } else {
  381. g.drawLine( 0, 0, 0, bottom - 1 );
  382. }
  383. }
  384. g.translate( -x, -y );
  385. }
  386. protected void paintRightTabBorder( int tabIndex, Graphics g,
  387. int x, int y, int w, int h,
  388. int btm, int rght,
  389. boolean isSelected ) {
  390. int tabCount = tabPane.getTabCount();
  391. int currentRun = getRunForTab( tabCount, tabIndex );
  392. int lastIndex = lastTabInRun( tabCount, currentRun );
  393. int firstIndex = tabRuns[ currentRun ];
  394. g.translate( x, y );
  395. int bottom = h - 1;
  396. int right = w - 1;
  397. //
  398. // Paint part of the tab above
  399. //
  400. if ( tabIndex != firstIndex ) {
  401. g.setColor( tabPane.getSelectedIndex() == tabIndex - 1 ?
  402. tabAreaBackground :
  403. tabPane.getBackgroundAt( tabIndex - 1 ) );
  404. g.fillRect( right - 5, 0, 5, 3 );
  405. g.fillRect( right - 2, 3, 2, 2 );
  406. }
  407. //
  408. // Paint Highlight
  409. //
  410. g.setColor( isSelected ? selectHighlight : highlight );
  411. // Paint slant
  412. g.drawLine( right - 6, 1, right - 1, 6 );
  413. // Paint top
  414. g.drawLine( 0, 1, right - 6, 1 );
  415. // Paint left
  416. if ( !isSelected ) {
  417. g.drawLine( 0, 1, 0, bottom );
  418. }
  419. //
  420. // Paint Border
  421. //
  422. g.setColor( darkShadow );
  423. // Paint slant
  424. g.drawLine( right - 6, 0, right, 6 );
  425. // Paint top
  426. g.drawLine( 0, 0, right - 6, 0 );
  427. // Paint right
  428. if ( tabIndex != firstIndex ) {
  429. g.drawLine( right, 0, right, bottom );
  430. } else {
  431. g.drawLine( right, 6, right, bottom );
  432. }
  433. // Paint bottom
  434. if ( tabIndex == lastIndex ) {
  435. g.drawLine( 0, bottom, right, bottom );
  436. }
  437. g.translate( -x, -y );
  438. }
  439. public void update( Graphics g, JComponent c ) {
  440. if ( c.isOpaque() ) {
  441. g.setColor( tabAreaBackground );
  442. g.fillRect( 0, 0, c.getWidth(),c.getHeight() );
  443. }
  444. paint( g, c );
  445. }
  446. protected void paintTabBackground( Graphics g, int tabPlacement,
  447. int tabIndex, int x, int y, int w, int h, boolean isSelected ) {
  448. int slantWidth = h / 2;
  449. if ( isSelected ) {
  450. g.setColor( selectColor );
  451. } else {
  452. g.setColor( tabPane.getBackgroundAt( tabIndex ) );
  453. }
  454. if (MetalUtils.isLeftToRight(tabPane)) {
  455. switch ( tabPlacement ) {
  456. case LEFT:
  457. g.fillRect( x + 5, y + 1, w - 5, h - 1);
  458. g.fillRect( x + 2, y + 4, 3, h - 4 );
  459. break;
  460. case BOTTOM:
  461. g.fillRect( x + 2, y, w - 2, h - 4 );
  462. g.fillRect( x + 5, y + (h - 1) - 3, w - 5, 3 );
  463. break;
  464. case RIGHT:
  465. g.fillRect( x + 1, y + 1, w - 5, h - 1);
  466. g.fillRect( x + (w - 1) - 3, y + 5, 3, h - 5 );
  467. break;
  468. case TOP:
  469. default:
  470. g.fillRect( x + 4, y + 2, (w - 1) - 3, (h - 1) - 1 );
  471. g.fillRect( x + 2, y + 5, 2, h - 5 );
  472. }
  473. } else {
  474. switch ( tabPlacement ) {
  475. case LEFT:
  476. g.fillRect( x + 5, y + 1, w - 5, h - 1);
  477. g.fillRect( x + 2, y + 4, 3, h - 4 );
  478. break;
  479. case BOTTOM:
  480. g.fillRect( x, y, w - 5, h - 1 );
  481. g.fillRect( x + (w - 1) - 4, y, 4, h - 5);
  482. g.fillRect( x + (w - 1) - 4, y + (h - 1) - 4, 2, 2);
  483. break;
  484. case RIGHT:
  485. g.fillRect( x + 1, y + 1, w - 5, h - 1);
  486. g.fillRect( x + (w - 1) - 3, y + 5, 3, h - 5 );
  487. break;
  488. case TOP:
  489. default:
  490. g.fillRect( x, y + 2, (w - 1) - 3, (h - 1) - 1 );
  491. g.fillRect( x + (w - 1) - 3, y + 4, 3, h - 4 );
  492. }
  493. }
  494. }
  495. /**
  496. * Overidden to do nothing for the Java L&F.
  497. */
  498. protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) {
  499. return 0;
  500. }
  501. /**
  502. * Overidden to do nothing for the Java L&F.
  503. */
  504. protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) {
  505. return 0;
  506. }
  507. public void paint( Graphics g, JComponent c ) {
  508. int tabPlacement = tabPane.getTabPlacement();
  509. Insets insets = c.getInsets(); Dimension size = c.getSize();
  510. // Paint the background for the tab area
  511. if ( tabPane.isOpaque() ) {
  512. g.setColor( c.getBackground() );
  513. switch ( tabPlacement ) {
  514. case LEFT:
  515. g.fillRect( insets.left, insets.top,
  516. calculateTabAreaWidth( tabPlacement, runCount, maxTabWidth ),
  517. size.height - insets.bottom - insets.top );
  518. break;
  519. case BOTTOM:
  520. int totalTabHeight = calculateTabAreaHeight( tabPlacement, runCount, maxTabHeight );
  521. g.fillRect( insets.left, size.height - insets.bottom - totalTabHeight,
  522. size.width - insets.left - insets.right,
  523. totalTabHeight );
  524. break;
  525. case RIGHT:
  526. int totalTabWidth = calculateTabAreaWidth( tabPlacement, runCount, maxTabWidth );
  527. g.fillRect( size.width - insets.right - totalTabWidth,
  528. insets.top, totalTabWidth,
  529. size.height - insets.top - insets.bottom );
  530. break;
  531. case TOP:
  532. default:
  533. g.fillRect( insets.left, insets.top,
  534. size.width - insets.right - insets.left,
  535. calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) );
  536. paintHighlightBelowTab();
  537. }
  538. }
  539. super.paint( g, c );
  540. }
  541. protected void paintHighlightBelowTab( ) {
  542. }
  543. protected void paintFocusIndicator(Graphics g, int tabPlacement,
  544. Rectangle[] rects, int tabIndex,
  545. Rectangle iconRect, Rectangle textRect,
  546. boolean isSelected) {
  547. if ( tabPane.hasFocus() && isSelected ) {
  548. Rectangle tabRect = rects[tabIndex];
  549. boolean lastInRun = isLastInRun( tabIndex );
  550. g.setColor( focus );
  551. g.translate( tabRect.x, tabRect.y );
  552. int right = tabRect.width - 1;
  553. int bottom = tabRect.height - 1;
  554. boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
  555. switch ( tabPlacement ) {
  556. case RIGHT:
  557. g.drawLine( right - 6,2 , right - 2,6 ); // slant
  558. g.drawLine( 1,2 , right - 6,2 ); // top
  559. g.drawLine( right - 2,6 , right - 2,bottom ); // right
  560. g.drawLine( 1,2 , 1,bottom ); // left
  561. g.drawLine( 1,bottom , right - 2,bottom ); // bottom
  562. break;
  563. case BOTTOM:
  564. if ( leftToRight ) {
  565. g.drawLine( 2, bottom - 6, 6, bottom - 2 ); // slant
  566. g.drawLine( 6, bottom - 2,
  567. right, bottom - 2 ); // bottom
  568. g.drawLine( 2, 0, 2, bottom - 6 ); // left
  569. g.drawLine( 2, 0, right, 0 ); // top
  570. g.drawLine( right, 0, right, bottom - 2 ); // right
  571. } else {
  572. g.drawLine( right - 2, bottom - 6,
  573. right - 6, bottom - 2 ); // slant
  574. g.drawLine( right - 2, 0,
  575. right - 2, bottom - 6 ); // right
  576. if ( lastInRun ) {
  577. // last tab in run
  578. g.drawLine( 2, bottom - 2,
  579. right - 6, bottom - 2 ); // bottom
  580. g.drawLine( 2, 0, right - 2, 0 ); // top
  581. g.drawLine( 2, 0, 2, bottom - 2 ); // left
  582. } else {
  583. g.drawLine( 1, bottom - 2,
  584. right - 6, bottom - 2 ); // bottom
  585. g.drawLine( 1, 0, right - 2, 0 ); // top
  586. g.drawLine( 1, 0, 1, bottom - 2 ); // left
  587. }
  588. }
  589. break;
  590. case LEFT:
  591. g.drawLine( 2, 6, 6, 2 ); // slant
  592. g.drawLine( 2, 6, 2, bottom - 1); // left
  593. g.drawLine( 6, 2, right, 2 ); // top
  594. g.drawLine( right, 2, right, bottom - 1 ); // right
  595. g.drawLine( 2, bottom - 1,
  596. right, bottom - 1 ); // bottom
  597. break;
  598. case TOP:
  599. default:
  600. if ( leftToRight ) {
  601. g.drawLine( 2, 6, 6, 2 ); // slant
  602. g.drawLine( 2, 6, 2, bottom - 1); // left
  603. g.drawLine( 6, 2, right, 2 ); // top
  604. g.drawLine( right, 2, right, bottom - 1 ); // right
  605. g.drawLine( 2, bottom - 1,
  606. right, bottom - 1 ); // bottom
  607. }
  608. else {
  609. g.drawLine( right - 2, 6, right - 6, 2 ); // slant
  610. g.drawLine( right - 2, 6,
  611. right - 2, bottom - 1); // right
  612. if ( lastInRun ) {
  613. // last tab in run
  614. g.drawLine( right - 6, 2, 2, 2 ); // top
  615. g.drawLine( 2, 2, 2, bottom - 1 ); // left
  616. g.drawLine( right - 2, bottom - 1,
  617. 2, bottom - 1 ); // bottom
  618. }
  619. else {
  620. g.drawLine( right - 6, 2, 1, 2 ); // top
  621. g.drawLine( 1, 2, 1, bottom - 1 ); // left
  622. g.drawLine( right - 2, bottom - 1,
  623. 1, bottom - 1 ); // bottom
  624. }
  625. }
  626. }
  627. g.translate( -tabRect.x, -tabRect.y );
  628. }
  629. }
  630. protected void paintContentBorderTopEdge( Graphics g, int tabPlacement,
  631. int selectedIndex,
  632. int x, int y, int w, int h ) {
  633. boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
  634. int right = x + w - 1;
  635. g.setColor(selectHighlight);
  636. if (tabPlacement != TOP || selectedIndex < 0 ||
  637. (rects[selectedIndex].y + rects[selectedIndex].height + 1 < y)) {
  638. g.drawLine(x, y, x+w-2, y);
  639. } else {
  640. Rectangle selRect = rects[selectedIndex];
  641. boolean lastInRun = isLastInRun(selectedIndex);
  642. if ( leftToRight || lastInRun ) {
  643. g.drawLine(x, y, selRect.x + 1, y);
  644. } else {
  645. g.drawLine(x, y, selRect.x, y);
  646. }
  647. if (selRect.x + selRect.width < right - 1) {
  648. if ( leftToRight && !lastInRun ) {
  649. g.drawLine(selRect.x + selRect.width, y, right - 1, y);
  650. } else {
  651. g.drawLine(selRect.x + selRect.width - 1, y, right - 1, y);
  652. }
  653. } else {
  654. g.setColor(shadow);
  655. g.drawLine(x+w-2, y, x+w-2, y);
  656. }
  657. }
  658. }
  659. protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
  660. int selectedIndex,
  661. int x, int y, int w, int h) {
  662. boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
  663. int bottom = y + h - 1;
  664. int right = x + w - 1;
  665. g.setColor(shadow);
  666. if (tabPlacement != BOTTOM || selectedIndex < 0 ||
  667. (rects[selectedIndex].y - 1 > h)) {
  668. g.setColor(darkShadow);
  669. g.drawLine(x, y+h-1, x+w-1, y+h-1);
  670. } else {
  671. Rectangle selRect = rects[selectedIndex];
  672. boolean lastInRun = isLastInRun(selectedIndex);
  673. g.setColor(darkShadow);
  674. if ( leftToRight || lastInRun ) {
  675. g.drawLine(x, bottom, selRect.x, bottom);
  676. } else {
  677. g.drawLine(x, bottom, selRect.x - 1, bottom);
  678. }
  679. if (selRect.x + selRect.width < x + w - 2) {
  680. if ( leftToRight && !lastInRun ) {
  681. g.drawLine(selRect.x + selRect.width, bottom,
  682. right, bottom);
  683. } else {
  684. g.drawLine(selRect.x + selRect.width - 1, bottom,
  685. right, bottom);
  686. }
  687. }
  688. }
  689. }
  690. protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
  691. int selectedIndex,
  692. int x, int y, int w, int h) {
  693. g.setColor(selectHighlight);
  694. if (tabPlacement != LEFT || selectedIndex < 0 ||
  695. (rects[selectedIndex].x + rects[selectedIndex].width + 1< x)) {
  696. g.drawLine(x, y, x, y+h-2);
  697. } else {
  698. Rectangle selRect = rects[selectedIndex];
  699. g.drawLine(x, y, x, selRect.y + 1);
  700. if (selRect.y + selRect.height < y + h - 2) {
  701. g.drawLine(x, selRect.y + selRect.height + 1,
  702. x, y+h+2);
  703. }
  704. }
  705. }
  706. protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
  707. int selectedIndex,
  708. int x, int y, int w, int h) {
  709. g.setColor(shadow);
  710. if (tabPlacement != RIGHT || selectedIndex < 0 ||
  711. rects[selectedIndex].x - 1 > w) {
  712. g.setColor(darkShadow);
  713. g.drawLine(x+w-1, y, x+w-1, y+h-1);
  714. } else {
  715. Rectangle selRect = rects[selectedIndex];
  716. g.setColor(darkShadow);
  717. g.drawLine(x+w-1, y, x+w-1, selRect.y);
  718. if (selRect.y + selRect.height < y + h - 2) {
  719. g.setColor(darkShadow);
  720. g.drawLine(x+w-1, selRect.y + selRect.height,
  721. x+w-1, y+h-2);
  722. }
  723. }
  724. }
  725. protected int calculateMaxTabHeight( int tabPlacement ) {
  726. FontMetrics metrics = getFontMetrics();
  727. int height = metrics.getHeight();
  728. boolean tallerIcons = false;
  729. for ( int i = 0; i < tabPane.getTabCount(); ++i ) {
  730. Icon icon = tabPane.getIconAt( i );
  731. if ( icon != null ) {
  732. if ( icon.getIconHeight() > height ) {
  733. tallerIcons = true;
  734. break;
  735. }
  736. }
  737. }
  738. return super.calculateMaxTabHeight( tabPlacement ) -
  739. (tallerIcons ? (tabInsets.top + tabInsets.bottom) : 0);
  740. }
  741. protected int getTabRunOverlay( int tabPlacement ) {
  742. // Tab runs layed out vertically should overlap
  743. // at least as much as the largest slant
  744. if ( tabPlacement == LEFT || tabPlacement == RIGHT ) {
  745. int maxTabHeight = calculateMaxTabHeight(tabPlacement);
  746. return maxTabHeight / 2;
  747. }
  748. return 0;
  749. }
  750. // Don't rotate runs!
  751. protected boolean shouldRotateTabRuns( int tabPlacement, int selectedRun ) {
  752. return false;
  753. }
  754. // Don't pad last run
  755. protected boolean shouldPadTabRun( int tabPlacement, int run ) {
  756. return runCount > 1 && run < runCount - 1;
  757. }
  758. private boolean isLastInRun( int tabIndex ) {
  759. int run = getRunForTab( tabPane.getTabCount(), tabIndex );
  760. int lastIndex = lastTabInRun( tabPane.getTabCount(), run );
  761. return tabIndex == lastIndex;
  762. }
  763. /**
  764. * This inner class is marked "public" due to a compiler bug.
  765. * This class should be treated as a "protected" inner class.
  766. * Instantiate it only within subclasses of MetalTabbedPaneUI.
  767. */
  768. public class TabbedPaneLayout extends BasicTabbedPaneUI.TabbedPaneLayout {
  769. protected void normalizeTabRuns( int tabPlacement, int tabCount,
  770. int start, int max ) {
  771. // Only normalize the runs for top & bottom; normalizing
  772. // doesn't look right for Metal's vertical tabs
  773. // because the last run isn't padded and it looks odd to have
  774. // fat tabs in the first vertical runs, but slimmer ones in the
  775. // last (this effect isn't noticable for horizontal tabs).
  776. if ( tabPlacement == TOP || tabPlacement == BOTTOM ) {
  777. super.normalizeTabRuns( tabPlacement, tabCount, start, max );
  778. }
  779. }
  780. // Don't rotate runs!
  781. protected void rotateTabRuns( int tabPlacement, int selectedRun ) {
  782. }
  783. // Don't pad selected tab
  784. protected void padSelectedTab( int tabPlacement, int selectedIndex ) {
  785. }
  786. }
  787. }