/** * ClickableMeter * * This file contains some extensions of ClickablePanel, namely * ClickableMeter - a horizontally or vertically oriented meter. * BarMeter - a horizontally or vertically oriented meter with a * bar graph like bar. * Thermometer - a vertically oriented thermometer complete with * bulb. * VertClickBar - (Deprecated) a vertically oriented item with ClickBar properties. * HoriClickBar - (Deprecated) a horizontally oriented item with ClickBar properties. * ClickBar - (Deprecated) used only by VertClickBar and HoriClickBar with common code. * and * ClickBarSketch - (Deprecated) It is an extension of Clickable that allows * vertical and horizontal scrolling of a sketch window. * * The deprecated ClickBar is similar to a ScrollBar except on just clicks the bar * instead dragging a scroll button. Scroll bars have a similar capabilities. * 2. Coding is simpler. * Copyright 2013-2014 by James Brink * Revised: Mar. 13, 2014 * Permission is given for noncommercial use of these classes * as long as the copyright notice is retained. *************************************************************/ /** * The ClickableMeter is a standard vertical or * horizontal meter. It is similar to a scrollbar except * that it response to clicks, not drags. */ class ClickableMeter extends ClickablePanel { float val; float minVal, maxVal, valRange; int barLoc; // x or y coordinate of bar boolean vertical; boolean hashShow, labelsShow, valueShow; float hashStart, labelsStart; float hashSpacing, labelsSpacing; float xHash, yHash; int xPixel, yPixel; float big; color barC; // used for bars on extended meters but not regular meters /** * Consructs a vertical meter given the upper, left corner, * the width and height, the label (not shown), standard color * and the overlay color, the min, current, max values. * Parameters: * leftX - x value of left side of ClickableMeter. * topY - y value of top of ClickableMeter. * theWidth - the width of the ClickableMeter. * theHeight - the height of the ClickableMeter. * theLabel - the label for the ClickableMeter (not normally shown). * stdColor - the normal color of the ClickableMeter. * overColor - the color used when mouise is over the ClickableMeter. * barColor - the color used for bars on the ClickableMeter. * minValue - the minimum value displayed on the ClickableMeter. * value - the initial value displayed on the ClickableMeter. * maxValue - the maximum value displayed on the ClickableMeter. */ ClickableMeter(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX, topY, theWidth, theHeight, theLabel, stdColor); minVal = minValue; maxVal = maxValue; valRange = maxValue - minValue; val = value; c[0] = stdColor; overC[0] = overColor; barC = barColor; over = false; vertical = h >= w; barLoc = calcLoc(val); // x or y coordinate of bar hashShow = false; labelsShow = false; valueShow = false; } // constructor ClickableMeter /** * Displays the ClickableMeter as a vertical or horizontal rectangle and * draws a line corresponding to the value. The background is in stdCol * while the bar is in the overCol. */ // ClickableMeter void display() { color col; float big; if (!visible) return; super.display(); stroke(barC); if (vertical) line(sX(x), sY(barLoc), sX(x + w), sY(barLoc)); else line(sX(barLoc), sY(y), sX(barLoc), sY(y) + h); // show hashmarks if requested big = max(maxVal, minVal); if (hashShow) { stroke(0); if (vertical) { for (yHash = hashStart; yHash <= big; yHash += hashSpacing) { yPixel = calcLoc(yHash); line(sX(x + w), sY(yPixel), sX(x + w) + 5, sY(yPixel)); } } else { for (xHash = hashStart; xHash <= big; xHash += hashSpacing) { xPixel = calcLoc(xHash); line(sX(xPixel), sY(y + h), sX(xPixel), sY(y + h) + 5); } } } // show labels if requested if (labelsShow) { stroke(0); fill(0); if (vertical) { for (yHash = labelsStart; yHash <= big; yHash += labelsSpacing) { yPixel = calcLoc(yHash); line(sX(x + w), sY(yPixel), sX(x + w) + 5, sY(yPixel)); text("" + round2_(yHash), sX(x + w) + 7, sY(yPixel) + 3); } } else { for (xHash = hashStart; xHash <= big; xHash += labelsSpacing) { xPixel = calcLoc(xHash); line(sX(xPixel), sY(y + h), sX(xPixel), sY(y + h) + 5); text("" + round2_(xHash), sX(xPixel) - 5, sY(y + h) + 17); } } } // show the ClickableMeter value if requested if (valueShow) { if (labelsShow) textLabel(val, false); else textLabel(val, true); } } // display /** * Returns true if the ClickableMeter has been clicked. Also * updates the current value. */ // ClickableMeter boolean checkForClick() { boolean b; int adjustedMouse; if (!visible || !enabled) return false; b = super.checkForClick(); if (b) { if (vertical) { if (scrollable) adjustedMouse = mouseY + soY_; else adjustedMouse = mouseY; barLoc = calcLoc(maxVal - valRange * (adjustedMouse - y) / h); } else { if (scrollable) adjustedMouse = mouseX + soX_; else adjustedMouse = mouseX; barLoc = calcLoc(minVal + valRange * (adjustedMouse - x) / w ); } calcVal(); } return b; } // checkForClick /** * Calculates and returns the x or y value corresponding to value * depending on whether the ClickableMeter is horizontal or vertical */ // ClickableMeter int calcLoc(float value) { if (minVal <=maxVal) value = min(max(value, minVal), maxVal); else value = min(max(value, maxVal), minVal); if (vertical) return y + h + (int)(h * (minVal - value)/valRange); else return x + (int)(w * (value - minVal)/valRange); } // calcLoc /** * Sets val and barLoc given the value. */ // ClickableMeter void setValue(float value) { val = value; barLoc = calcLoc(value); } // setValue /** * Calculates and stores val (the value) using barLoc. */ // ClickableMeter void calcVal() { if (vertical) val = maxVal - valRange * (barLoc - y) / h; else val = minVal + valRange * (barLoc - x) / w; } // calcVal /** * Adds labels showing the value to the left or bottom of the * ClickableMeter. First label is at start. Note: This version * is designed for situations where the minimal value is * a nice number. Should be called in setup. */ // ClickableMeter void showLabels(float spacing, float start) { labelsStart = start; labelsSpacing = spacing; labelsShow = true; } // 2 parameter showLabels /** * Adds labels showing the value to the left or bottom of the * ClickableMeter. First label is at start. Note: This version * is designed for situations where the minimal value is * a nice number. Should be called in setup. */ // ClickableMeter void showLabels(float spacing) { labelsStart = minVal; labelsSpacing = spacing; labelsShow = true; } // 1 parameter showLabels /** * Adds hashmarks to the left or bottom of the ClickableMeter. * First hash is at start. Note: This version * is designed for situations where the minimal value is * <> a nice number. Should be called in setup. */ // ClickableMeter void showHashmarks(float spacing, float start) { hashStart = start; hashSpacing = spacing; hashShow = true; } // 2 parameter showHashMarks /** * Adds hashmarks to the left or bottom of the ClickableMeter. * First hash is at start. Note: This version * is designed for situations where the minimal value is * a nice number. Should be called in setup. */ // ClickableMeter void showHashmarks(float spacing) { hashStart = minVal; hashSpacing = spacing; hashShow = true; } // 1 parameter showHashMarks /** * Add the value of the ClickableMeter at the appropriate location. * If showLabels is also used, the labels will appear on * the left or top of the ClickableMeter. This prevents the value * label from overlapping the other labels. If the show * labels is not used, the labels will appear on the right * or bottom of the meters. */ // ClickableMeter void showValue() { valueShow = true; } // showValue /** * Write a label with the given value beside the ClickableMeter. * If rightSide is true, then it is on the right side, if not * it is on the left side. The value is rounded to two * decimal places (but may appear 0 or 1 decimal places. */ // ClickableMeter void textLabel(float value, boolean rightSide) { int labelY, labelX; float labelVal; stroke(0); fill(0); if (vertical) { labelY = round(calcLoc(value)); labelVal = round2_(value); // Note: "" + labeVal is printed because without // the "" +, 3 decimal places are normally shown. if (rightSide) { text("" + labelVal, sX(x) + w + 7, sY(labelY) + 3); line(sX(x) + w, sY(labelY), sX(x) + w + 5, sY(labelY)); } else { // left side text(labelVal + "", sX(x) - 40, sY(labelY) + 3); line(sX(x) - 5, sY(labelY), sX(x), sY(labelY)); } } else { labelX= round(calcLoc(value)); labelVal = round2_(value); if (rightSide) { //bottom text("" + labelVal, sX(labelX) - 5, sY(y) + h + 17); line(sX(labelX), sY(y) + h, sX(labelX), sY(y) + h + 5); } else { // top text("" + labelVal, sX(labelX) - 5, sY(y - 7)); line(sX(labelX), sY(y) - 5, sX(labelX), sY(y)); } } } // textLabel /** * Returns the current value of the ClickableMeter. */ // ClickableMeter float getValue() { return val; } // getValue /** * Returns the max value of the ClickableMeter. */ // ClickableMeter float getMaxValue() { return maxVal; } // getMaxValue /** * Returns the max value of the ClickableMeter. */ // ClickableMeter float getMinValue() { return minVal; } // getMinValue } // class ClickableMeter // *************************************************************/ /** * Creates a bar meter. The meter up to the value is filled * with the overColor. The difference between a Meter and a * BarMeter is that a bar is drawn left of or below the bar * a regular meter. */ class BarMeter extends ClickableMeter { /** * Creates a bar meter given the upper left corner, the width * and height, a label (not shown), three colors, * and the minimum, current, and maximum values. * Parameters - see the parameters for the Meter constructor */ BarMeter(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX, topY, theWidth, theHeight, theLabel, stdColor, overColor, barColor, minValue, value, maxValue); barC = barColor; } // constructor BarMeter /** * Displays a bar graph lke meter. */ // BarMeter void display() { if (!visible) return; super.display(); if (enabled) fill(barC); else fill(DISABLED_COLOR); stroke(0); if (vertical) rect(sX(x), sY(barLoc), w, y + h - sY(barLoc)); else rect(sX(x), sY(y), barLoc - x, h); } // display } // class BarMeter // *************************************************************/ /** * Creates a thermometer looking meter with a bulb on the bottom. * The bulb and the meter up to the value are filled with the * barColor. The thermometer is about the same as a BarMeter * with the addition of the bulb. * Important: theWidth < theHeigth IS REQUIRED. */ class Thermometer extends ClickableMeter { int r; int bulbCenterX, bulbCenterY; /** * Creates a thermometer given the upper left corner, the width * and height, a label (not shown), three colors, * and the minimum, current, and maximum values. * Parameters - see the parameters for the Meter constructor */ Thermometer(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX, topY, theWidth, theHeight, theLabel, stdColor, overColor, barColor, minValue, value, maxValue); r = (int)(1.5 * w); bulbCenterY = y + h + (int)(r/2); bulbCenterX = x + (int)(w/2); barC = barColor; } // constructor Thermometer /** * Displays a thermometer type meter with a "bulb" on the * bottom. */ // Thermometer void display() { if (!visible) return; super.display(); if (enabled) fill(barC); else fill(DISABLED_COLOR); stroke(barC); rect(sX(x), sY(barLoc), w, bulbCenterY - barLoc); ellipse(sX(bulbCenterX), sY(bulbCenterY), r, r); } // display } // class Thermometer // *************************************************************/ /** * ** Deprecated ** * A vertical "ClickBar" control with up and down buttons and * horizontal bar the represents the current value. Clicking * the up and down buttons change the value by about 1/10 of its * range. Clicking the bar changes the value to the clicked * value. */ class VertClickBar extends ClickBar { /** * Creates a vertical "ClickBar" given the upper left corner, the width * and height, a label (not shown), the three colors, * and the minimum, current, and maximum values. * Parameters - see the parameters for the Meter constructor. */ VertClickBar(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX, topY+ITEM_HEIGHT+1, theWidth, theHeight-2*ITEM_HEIGHT-2, theLabel, stdColor, overColor, barColor, minValue, value, maxValue); topDownBtn = y + h + 1; upBtn = new Button(leftX, topY, theWidth, ITEM_HEIGHT, " ^", stdColor, overColor); downBtn = new Button(leftX, topDownBtn, theWidth, ITEM_HEIGHT, " v", stdColor, overColor); } // constructor VertClickBar } // class VertClickBar // *************************************************************/ /** * ** Deprecated ** * A horizontal "ClickBar" control with up and down buttons and * vertical bar the represents the current value. Clicking * the up and down buttons change the value by 1/10 of its * range. Clicking the bar changes the value to the clicked * value. Confusion factor: The left and right buttons are * named upBtn and downBtn to simplify the code. */ class HoriClickBar extends ClickBar { /** * Creates a horizontal "ClickBar" given the upper left corner, the * width and height, a label (not shown), the standard and fill * colors, and the minimum, current, and maximum values. * Parameters - see the parameters for the Meter constructor. */ HoriClickBar(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX+ITEM_HEIGHT+1, topY, theWidth-2*ITEM_HEIGHT-2, theHeight, theLabel, stdColor, overColor, barColor, minValue, value, maxValue); leftUpBtn = x + w + 1; upBtn = new Button(leftUpBtn, topY, ITEM_HEIGHT, theHeight, " >", stdColor, overColor); downBtn = new Button(leftX, topY, ITEM_HEIGHT, theHeight, " <", stdColor, overColor); } // constructor HoriClickBar } // class HoriClickBar // *************************************************************/ /** * ** Deprecated ** * This is an abstract class. It is implemented by VertClickBar * and HoriClickBar which declare the upBtn and downBtn buttons The only special code for a VertClickBar * and a HoriSlide in there constructors. In this constructor, * leftX, topY, theWidth, and theHeight represent the size of the * clickable panel. * * A "ClickBar" control has up and down (or left/right buttons) * anda bar the represents the current value. Clicking the up and * down buttons change the value by about 1/10 of its range. Clicking * the panel changes the value to the clicked value. * Parameters - see the parameters for the Meter constructor */ abstract class ClickBar extends ClickableMeter { static final int ITEM_HEIGHT = 20; Button downBtn, upBtn; int topDownBtn; // for vertical int leftUpBtn; // for horizontal /** * Note fields x, y, w, and h and leftX, topY, theWidth * and theHeight all refer to the panel, not * the total size including up and down buttons. Thus the * constructor parameters are a little different than the * VertClickBar and HoriClickBar constructors. * * Completes a vertical or horizontal "ClickBar" given the upper * left corner, the width and height, a label (not shown), the * three colors, and the minimum, current, and maximum values. */ ClickBar(int leftX, int topY, int theWidth, int theHeight, String theLabel, color stdColor, color overColor, color barColor, float minValue, float value, float maxValue) { super(leftX, topY, theWidth, theHeight, theLabel, stdColor, overColor, barColor, minValue, value, maxValue); } // constructor ClickBar /** * Sets the meter as being visible true or false. * SHOULD BE OVERRIDEN BY COMPOUND ITEMS. */ // ClickBar void setVisible(boolean b) { upBtn.setVisible(b); downBtn.setVisible(b); visible = b; } // setVisible /** * Sets the meter as being enabled true or false. * SHOULD BE OVERRIDEN BY COMPOUND ITEMS. */ // ClickBar void setEnabled(boolean b) { upBtn.setEnabled(b); downBtn.setEnabled(b); enabled = b; } // setVisible /** * Draws the complete ClickBar including the up and down buttons * the bar showing the value. The bar may be verical or horizontal. */ // ClickBar void display() { if (!visible) return; upBtn.display(); downBtn.display(); super.display(); if (upBtn.over || downBtn.over) { // use over color for body of scroll bar fill(c[0]); rect(sX(x), sY(y), w, h); } // draw bar on meter if (enabled) stroke(barC); else stroke(DISABLED_COLOR); strokeWeight(3); fill(barC); if (vertical) line(sX(x) + 1, sY(barLoc), sX(x) + w - 1, sY(barLoc)); else line(sX(barLoc), sY(y) + 1, sX(barLoc), sY(y) + h - 1); strokeWeight(1); } // display /** * Determines if any part of the ClickBar has been clicked * and returns true if so. Always returns false if stillSearching_ * is false. */ // ClickBar boolean isOver() { if (!visible || !enabled) return false; over = false; if (super.isOver()) { over = true; } if (upBtn.isOver()) { over = true; } if (downBtn.isOver()) over = true; if (over) stillSearching_ = false; return over; } // isOver /** * Checks to see if any part of the "ClickBar" has been * clicked. If so, it updates the current "value" and sets "clicked" * to true and then returns true. */ // ClickBar boolean checkForClick() { boolean b; if (!visible || !enabled) return false; b = false; if (vertical) { if (downBtn.over) { b = true; barLoc = min(y + h, (int)(barLoc + .1 * h)); } else if (upBtn.over) { b = true; barLoc = max(y, (int)(barLoc - .1 * h)); } else if (over) { if (mouseY >= sY(y) && mouseY <= sY(y) + h) super.checkForClick(); b = true; } } else { if (downBtn.over) { b = true; barLoc = max(x, (int)(barLoc - .1 * w)); } else if (upBtn.over) { b = true; barLoc = min(x + w, (int)(barLoc + .1 * w)); } else if (over) { if (mouseX >= sX(x) && mouseX <= sX(x) + w) super.checkForClick(); b = true; } } if (b) { calcVal(); } return b; } // checkForClick /** * Determine if the ClickBar has been clicked. If so, return true. * "clicked" is set to false. */ // ClickBar boolean hasBeenClicked() { boolean b; if (!visible || !enabled) return false; b = false; if (upBtn.hasBeenClicked()) { b = true; } else if(downBtn.hasBeenClicked()) { b = true; } else if(clicked) { b = true; } clicked = false; return b; } // hasBeenClicked /** * Used to specify if the ClickBar is scrollable. */ // ClickBar void setScrollable(boolean canScroll) { upBtn.setScrollable(false); downBtn.setScrollable(false); super.setScrollable(false); } // setScrollable } // class ClickBar // *************************************************************/ /** * ** Deprecated ** The ScrollSketch class includes this capabilities * Adds a vertical and horizontal ClickBars to the skets on the * right and bottom. The user can use these bars to scroll the * sketch. * * All the Clickable items have been adapted to scroll so normally * no extra coding is needed to allow them to scroll. However, * standard Processing items like text, lines and rectangles need * a little extra coding. All the x and y coordianates must be * addapted to use the the global sX_ and sY_ methods found in the * clickable package. For example, replace * text("Some text", 20, 40); * with * text("Some text", sX_(20), sY_(40)); * If you don't want a Clickable item to scroll, have it call its * setScrollable method. For example, * myButton.setScrollable(false); * For none Clickable like text, lines and rectangles, just don't * use the sX_ and sY_ methods. * The ClickBarSketch item must be set up carefully. It should be * the last item in the Clickable and it must be created in setup() * after the size of the sketch is specified. For example, * ... * ClickBarSketch sWindow; * Clickable[] clickItems = {... 6 Clickable items ..., sWindow}; * ClickableGroup clickGrp; * void setup() { * size(450, 500); * sWindow = new ClickBarSketch(#E0E0E0, #C0C0C0, #FF0000); * clickItems[6]= sWindow; * clickGrp = new ClickableGroup(clickItems); * ... * * In addition, in draw(), the ClickBarSketch should be the last thing * drawn. Normally this the clickable group should be the last thing * drawn. * * The Clickable.pde file contains global fields soX_ and soY_ which * contain the current scrolling offsets. The global methods sX_ and * sY_ are intended forn the user's program. Every clickable item * has the methods sX and sY methods that carry out similar operations excepts if the item has been marked as not * for Clickable items except these methods do not adjust the * coordiates if the scrollable field has been set false. */ class ClickBarSketch extends Clickable { final int BAR_SIZE = 20; int scrollW, scrollH; // max size of scrolled window int winWidth, winHeight; // size of displayed window including bars int winPaneWidth, winPaneHeight; // size of displaned pane less bars HoriClickBar hScroll; VertClickBar vScroll; /** * Scrolls the sketch window. Vertical and horizontal scroll * bars are used. The colors are the standard color, the * color used when cursor is over the ClickBar and the color * used for the bar in ClickBar. * * maxWidth and maxHeight are the maximum size of the scrolled * sketch of which only a portion is shown. * * Note: In Processing, width and height are undefined until * setup is run. Hence this SchollWindow, can't be created * until after the size is set. Then the new ScroolWindow * must be put in the clickable array and then the * ClicableGroup can be created. */ ClickBarSketch(int maxWidth, int maxHeight, color theColor, color theOverColor, color barColor) { super("Scroll Sketch"); winWidth = width; winHeight = height; winPaneWidth = winWidth - BAR_SIZE; winPaneHeight = winHeight - BAR_SIZE; scrollW = maxWidth; scrollH = maxHeight; soX_ = 0; soY_ = 0; hScroll = new HoriClickBar(0, winPaneHeight, winPaneWidth, BAR_SIZE, "WinHoriScroll", theColor, theOverColor, barColor, 0, soX_, scrollW - winPaneWidth); vScroll = new VertClickBar(winPaneWidth, 0, BAR_SIZE, winPaneHeight, "WinVertScroll", theColor, theOverColor, barColor, scrollH - winPaneHeight, soY_, 0); hScroll.setScrollable(false); vScroll.setScrollable(false); } // 5 parameter constructor ClickBarSketch /** * Scrolls the sketch window. Vertical and horizontal scroll * bars are used. The colors are the standard color, the * color used when cursor is over the ClickBar and the color * used for the bar in ClickBar. * * The width and height of the scrolled window is about twice * the size of the displayed window. * * Note: In Processing, width and height are undefined until * setup is run. Hence this SchollWindow, can't be created * until after the size is set. Then the new ScroolWindow * must be put in the clickable array and then the * ClicableGroup can be created. */ ClickBarSketch(color theColor, color theOverColor, color barColor) { this(2 * width, 2 * height, theColor, theOverColor, barColor); } // 3 parameter constructor ClickBarSketch /** * Displays the two ClickBars. */ void display() { if (!visible) return; if (enabled) fill(vScroll.c[0]); // use scroll bar color for square else fill(DISABLED_COLOR); rect(winPaneWidth, winPaneHeight, BAR_SIZE, BAR_SIZE); vScroll.display(); hScroll.display(); } // display /** * Sets the meter as being visible true or false. */ // ClickBarSketch void setVisible(boolean b) { vScroll.setVisible(b); hScroll.setVisible(b); visible = b; } // setVisible /** * Sets the meter as being enabled true or false. */ // ClickBarSketch void setEnabled(boolean b) { vScroll.setEnabled(b); hScroll.setEnabled(b); enabled = b; } // setEnabled /** * Determines if the cursor is over either of the ClickBars * and returns true if so. Always returns false if stillSearching_ * is false. */ // ClickBarSketch boolean isOver() { boolean b; b = false; if (visible && enabled) { if (vScroll.isOver()) b = true; if (hScroll.isOver()) b = true; if (!stillSearching_) b = false; } return b; } // isOver /** * Checks to see if any part of either ClickBar has been * clicked. If so, it updates the value of soX_ or soY_ * as appropriate. Returns true if either has been clicked. * Called directly or indirectly in the mouseReleased() method. */ // ClickBarSketch boolean checkForClick() { boolean b; b = false; if (visible && enabled) { if (vScroll.checkForClick()) { b = true; soY_ = (int)vScroll.getValue(); } else if (hScroll.checkForClick()){ b = true; soX_ = (int)hScroll.getValue(); } } return b; } // checkForClick /** * Determines if either ClickBar has been clicked. If so, return true. * true. "clicked" is set to false. Called directly or indirectly * in by the draw() method. */ // ClickBarSketch boolean hasBeenClicked(){ boolean b; b = vScroll.hasBeenClicked(); if (!b) b = hScroll.hasBeenClicked(); clicked = false; return b; } // hasBeenClicked /** * Returns the soX_ which is to be subtracted from * the x coordinate of scrolled things. */ // ClickBarSketch int getOffsetX() { return soX_; } // getOffsetX /** * Returns the sY_ which is to be subtracted from * the y coordinate of scrolled things */ // ClickBarSketch int getOffsetY() { return soY_; } // getOffsetY } // class ClickBarSketch