diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java index e59dc92c6..576011e20 100644 --- a/app/src/processing/app/EditorHeader.java +++ b/app/src/processing/app/EditorHeader.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2004-11 Ben Fry and Casey Reas + Copyright (c) 2004-13 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ package processing.app; import java.awt.*; import java.awt.event.*; +import java.awt.geom.GeneralPath; import java.util.Arrays; import javax.swing.*; @@ -34,8 +35,25 @@ import javax.swing.*; * Sketch tabs at the top of the editor window. */ public class EditorHeader extends JComponent { + // standard UI sizing (OS-specific, but generally consistent) + static final int SCROLLBAR_WIDTH = 16; + // amount of space on the left edge before the tabs start + static final int MARGIN_WIDTH = 6; + // distance from the righthand side of a tab to the drop-down arrow + static final int ARROW_GAP_WIDTH = 8; + // indent x/y for notch on the tab + static final int NOTCH = 4; + // how far to raise the tab from the bottom of this Component + static final int TAB_HEIGHT = 27; + // amount of margin on the left/right for the text on the tab + static final int TEXT_MARGIN = 5; + // width of the tab when no text visible + // (total tab width will be this plus TEXT_MARGIN*2) + static final int NO_TEXT_WIDTH = 10; + Color backgroundColor; Color textColor[] = new Color[2]; + Color tabColor[] = new Color[2]; Editor editor; @@ -68,8 +86,8 @@ public class EditorHeader extends JComponent { static final int PIECE_HEIGHT = 33; Image[][] pieces; - static final int ARROW_WIDTH = 6; - static final int ARROW_HEIGHT = 6; + static final int ARROW_WIDTH = 14; + static final int ARROW_HEIGHT = 14; Image tabArrow; // @@ -167,12 +185,15 @@ public class EditorHeader extends JComponent { } } - tabArrow = mode.loadImage("theme/tab-arrow"); + tabArrow = mode.loadImage("theme/tab-arrow" + suffix); backgroundColor = mode.getColor("header.bgcolor"); textColor[SELECTED] = mode.getColor("header.text.selected.color"); textColor[UNSELECTED] = mode.getColor("header.text.unselected.color"); font = mode.getFont("header.text.font"); + + tabColor[SELECTED] = mode.getColor("header.tab.selected.color"); + tabColor[UNSELECTED] = mode.getColor("header.tab.unselected.color"); } @@ -228,6 +249,15 @@ public class EditorHeader extends JComponent { // set the background for the offscreen g.setColor(backgroundColor); g.fillRect(0, 0, imageW, imageH); + +// EditorToolbar toolbar = editor.toolbar; +// if (toolbar != null && toolbar.backgroundImage != null) { +// g.drawImage(toolbar.backgroundImage, +// 0, -toolbar.getHeight(), +// EditorToolbar.BACKGROUND_WIDTH, +// EditorToolbar.BACKGROUND_HEIGHT, null); +// } + editor.getMode().drawBackground(g, EditorToolbar.BUTTON_HEIGHT); // int codeCount = sketch.getCodeCount(); // if ((tabLeft == null) || (tabLeft.length < codeCount)) { @@ -242,11 +272,10 @@ public class EditorHeader extends JComponent { visitOrder = new Tab[sketch.getCodeCount() - 1]; } - menuRight = sizeW - 16; +// menuRight = sizeW - 16; // menuLeft = menuRight - pieces[0][MENU].getWidth(this); - menuLeft = menuRight - 50; // FIXME!! - int tabLeft = 6; - int tabMax = menuLeft - tabLeft; +// menuLeft = menuRight - 50; // FIXME!! + int tabMax = menuLeft - (MARGIN_WIDTH + SCROLLBAR_WIDTH); // reset all tab positions for (Tab tab : tabs) { @@ -265,7 +294,7 @@ public class EditorHeader extends JComponent { } // make sure everything can fit - if (!placeTabs(tabLeft, tabMax, null)) { + if (!placeTabs(MARGIN_WIDTH, tabMax, null)) { //System.arraycopy(tabs, 0, visitOrder, 0, tabs.length); // always show the tab with the sketch's name // System.arraycopy(tabs, 1, visitOrder, 0, tabs.length - 1); @@ -280,18 +309,24 @@ public class EditorHeader extends JComponent { // } // System.out.println(); + // Keep shrinking the tabs one-by-one until things fit properly for (int i = 0; i < visitOrder.length; i++) { tabs[visitOrder[i].index].textVisible = false; - if (placeTabs(tabLeft, tabMax, null)) { + if (placeTabs(MARGIN_WIDTH, tabMax, null)) { break; } } } // now actually draw the tabs - placeTabs(tabLeft, tabMax, g); + placeTabs(MARGIN_WIDTH, tabMax, g2); // draw the dropdown menu target + menuLeft = tabs[tabs.length - 1].right + ARROW_GAP_WIDTH; + menuRight = menuLeft + ARROW_WIDTH; + int arrowY = (getHeight() - TAB_HEIGHT) + (TAB_HEIGHT - ARROW_HEIGHT)/2; + g.drawImage(tabArrow, menuLeft, arrowY, + ARROW_WIDTH, ARROW_HEIGHT, null); // g.drawImage(pieces[popup.isVisible() ? SELECTED : UNSELECTED][MENU], // menuLeft, 0, null); @@ -299,50 +334,78 @@ public class EditorHeader extends JComponent { } - private boolean placeTabs(int left, int right, Graphics g) { + private boolean placeTabs(int left, int right, Graphics2D g) { Sketch sketch = editor.getSketch(); int x = left; + final int bottom = getHeight(); + final int top = bottom - TAB_HEIGHT; + GeneralPath path = null; + for (int i = 0; i < sketch.getCodeCount(); i++) { SketchCode code = sketch.getCode(i); Tab tab = tabs[i]; - int pieceCount = 2 + (tab.textWidth / PIECE_WIDTH); - if (tab.textVisible == false) { - pieceCount = 4; - } - int pieceWidth = pieceCount * PIECE_WIDTH; +// int pieceCount = 2 + (tab.textWidth / PIECE_WIDTH); +// if (tab.textVisible == false) { +// pieceCount = 4; +// } +// int pieceWidth = pieceCount * PIECE_WIDTH; int state = (code == sketch.getCurrentCode()) ? SELECTED : UNSELECTED; if (g != null) { - g.drawImage(pieces[state][LEFT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); + //g.drawImage(pieces[state][LEFT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); + path = new GeneralPath(); + path.moveTo(x, bottom); + path.lineTo(x, top + NOTCH); + path.lineTo(x + NOTCH, top); } - x += PIECE_WIDTH; - - int contentLeft = x; tab.left = x; - for (int j = 0; j < pieceCount; j++) { - if (g != null) { - g.drawImage(pieces[state][MIDDLE], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); - } - x += PIECE_WIDTH; - } + x += TEXT_MARGIN; +// x += PIECE_WIDTH; + +// int contentLeft = x; +// for (int j = 0; j < pieceCount; j++) { +// if (g != null) { +// g.drawImage(pieces[state][MIDDLE], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); +// } +// x += PIECE_WIDTH; +// } +// if (g != null) { + int drawWidth = tab.textVisible ? tab.textWidth : NO_TEXT_WIDTH; + x += drawWidth + TEXT_MARGIN; +// path.moveTo(x, top); +// } tab.right = x; + if (g != null) { + path.lineTo(x - NOTCH, top); + path.lineTo(x, top + NOTCH); + path.lineTo(x, bottom); + path.closePath(); + g.setColor(tabColor[state]); + g.fill(path); + //g.drawImage(pieces[state][RIGHT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); + } + if (tab.textVisible) { - int textLeft = contentLeft + (pieceWidth - tab.textWidth) / 2; +// int textLeft = contentLeft + (pieceWidth - tab.textWidth) / 2; if (g != null) { + int textLeft = tab.left + ((tab.right - tab.left) - tab.textWidth) / 2; g.setColor(textColor[state]); - int baseline = (sizeH + fontAscent) / 2; +// int baseline = (int) Math.ceil((sizeH + fontAscent) / 2.0); + int baseline = bottom - (TAB_HEIGHT - fontAscent)/2 - 1; //g.drawString(sketch.code[i].name, textLeft, baseline); g.drawString(tab.text, textLeft, baseline); +// g.drawLine(tab.left, baseline-fontAscent, tab.right, baseline-fontAscent); } } - if (g != null) { - g.drawImage(pieces[state][RIGHT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); - } - x += PIECE_WIDTH - 1; // overlap by 1 pixel +// if (g != null) { +// g.drawImage(pieces[state][RIGHT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null); +// } +// x += PIECE_WIDTH - 1; // overlap by 1 pixel + x += 1; } return x <= right; } diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java index 715843841..e2a5a2633 100644 --- a/app/src/processing/app/EditorToolbar.java +++ b/app/src/processing/app/EditorToolbar.java @@ -70,7 +70,7 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList // int which[]; // mapping indices to implementation // int x1[], x2[]; - static final int TOP = 0; + static final int TOP = 2; static final int BOTTOM = BUTTON_HEIGHT; Font statusFont; @@ -94,8 +94,6 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList static final int ARROW_HEIGHT = 6; Image modeArrow; - protected Image backgroundImage; - public EditorToolbar(Editor editor, Base base) { //, JMenu menu) { this.editor = editor; @@ -168,6 +166,8 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList // Load the dropdown arrow, based on all the work done above modeArrow = mode.loadImage("theme/mode-arrow" + suffix); + // And the background image +// backgroundImage = mode.loadImage("theme/mode" + suffix); return buttonImages; } @@ -224,6 +224,10 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList g.setColor(bgcolor); //getBackground()); g.fillRect(0, 0, width, height); +// if (backgroundImage != null) { +// g.drawImage(backgroundImage, 0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, null); +// } + mode.drawBackground(g, 0); // for (int i = 0; i < buttonCount; i++) { // g.drawImage(stateImage[i], x1[i], y1, null); @@ -254,11 +258,11 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList FontMetrics metrics = g.getFontMetrics(); int modeTextHeight = metrics.getAscent(); int modeTextWidth = metrics.stringWidth(modeTitle); - final int modeGapWidth = 6; + final int modeGapWidth = 8; final int modeBoxHeight = 20; modeX2 = getWidth() - 16; modeX1 = modeX2 - (modeGapWidth + modeTextWidth + modeGapWidth + ARROW_WIDTH + modeGapWidth); - modeY1 = (getHeight() - modeBoxHeight) / 2; + modeY1 = 8; //(getHeight() - modeBoxHeight) / 2; modeY2 = modeY1 + modeBoxHeight; //modeY1 + modeH + modeGapV*2; g.setColor(modeButtonColor); g.drawRect(modeX1, modeY1, modeX2 - modeX1, modeY2 - modeY1); @@ -268,7 +272,7 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList g.drawImage(modeArrow, modeX2 - ARROW_WIDTH - modeGapWidth, modeY1 + (modeBoxHeight - ARROW_HEIGHT) / 2, - ARROW_WIDTH, ARROW_HEIGHT, this); + ARROW_WIDTH, ARROW_HEIGHT, null); screen.drawImage(offscreen, 0, 0, size.width, size.height, null); diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index f4b7077f8..478af6d6c 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -1,3 +1,26 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2010-13 Ben Fry and Casey Reas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + package processing.app; import java.awt.*; @@ -59,6 +82,10 @@ public abstract class Mode { */ protected ClassLoader classLoader; + static final int BACKGROUND_WIDTH = 580; + static final int BACKGROUND_HEIGHT = 250; + protected Image backgroundImage; + // public Mode(Base base, File folder) { // this(base, folder, base.getSketchbookLibrariesFolder()); @@ -149,11 +176,22 @@ public abstract class Mode { // other things that have to be set explicitly for the defaults theme.setColor("run.window.bgcolor", SystemColor.control); + String suffix = Toolkit.isRetina() ? "-2x.png" : ".png"; + backgroundImage = loadImage("theme/mode" + suffix); + } catch (IOException e) { Base.showError("Problem loading theme.txt", "Could not load theme.txt, please re-install Processing", e); } } + + + public void drawBackground(Graphics g, int offset) { + if (backgroundImage != null) { + g.drawImage(backgroundImage, 0, -offset, + BACKGROUND_WIDTH, BACKGROUND_HEIGHT, null); + } + } public File getContentFile(String path) { diff --git a/java/theme/theme.txt b/java/theme/theme.txt index 05c0943af..57f0f0c7f 100644 --- a/java/theme/theme.txt +++ b/java/theme/theme.txt @@ -11,11 +11,15 @@ status.font = SansSerif,plain,12 # GUI - TABS # settings for the tabs at the top # (tab images are stored in the lib/theme folder) -header.bgcolor = #818b95 -header.text.selected.color = #1a1a00 +#header.bgcolor = #818b95 +header.bgcolor = #000000 +#header.text.selected.color = #1a1a00 +header.text.selected.color = #000000 header.text.unselected.color = #ffffff -header.text.font = SansSerif,plain,12 +header.text.font = SansSerif,plain,11 #header.text.font.macosx = Helvetica,plain,12 +header.tab.selected.color = #a2afba +header.tab.unselected.color = #2a4159 # GUI - CONSOLE # font is handled by preferences, since size/etc is modifiable