package org.j4me.ui; import java.util.*; import javax.microedition.lcdui.*; import org.j4me.ui.components.*; import org.j4me.util.*; /** * The <code>Dialog</code> class is a base class for any screen that accepts user input * using standard components like the text box. It is similar to the MIDP <code>Form</code> class * except that it uses the J4ME control flow and has an OK and Cancel button built in. * <p> * Form classes can only have component objects, like the text box or label, placed on them. * The class handles layout, painting, and management of the components. * If you need direct control over the appearance of the screen use the <code>DeviceScreen</code> * class. * * @see javax.microedition.lcdui.Form */ public abstract class Dialog extends DeviceScreen { /** * The collection of all components on this form. Components are displayed * as ordered from top to bottom. */ private Vector components = new Vector(); /** * The index of <code>component</code> the user currently has highlighted. * If this is not an index of <code>component</code> nothing is highlighted. * Any component can be highlighted; it does not have to accept user input * (<code>Component.acceptsInput()</code>). It is up the component itself * to decide if it should be painted differently when highlighted. */ private int highlightedComponent = -1; /** * The number of pixels between the left and right of the screen and the * components. This also pads the top and bottom of the form; however, * scrolling can make the text appear at the very top and bottom of the * screen. */ private int margin = 5; /** * The number of pixels above and below components. */ private int spacing = margin; /** * The offset into the form that has been scrolled down. 0 indicates * the very top of the form is shown at the top of the screen. 100 * would indicate that the current top of the screen (i.e. y == 0) * shows the 100th pixel down in the form. If the first component * were 80 pixels tall and the second 40, 100 would mean the bottom * half of the second component would be at the top of the screen. */ private int topOfScreen = 0; /** * The number of pixels wide each component is. * <p> * When the form is painted for the first time this number will be * calculated. If the components on the form are changed, this will be * reset back to <code>null</code>. * <p> * The last element in this array is a dummy element. */ private int[] componentWidths = null; /** * The number of pixels high the entire form is with all the components * on it. If this number is greater than the height of the screen, a * vertical scrollbar will be added to the side. * <p> * When the form is painted for the first time this number will be * calculated. If the components on the form are changed, this will be * reset back to <code>null</code>. * <p> * The last element in this array is a dummy element. Its value helps * determine the bottom of the last component. */ private int[] absoluteHeights = null; /** * A flag indicating if the screens layout is no longer valid. It will * be calculated on the next <code>paint</code>. * <p> * This flag is an optimization. Many invalidations can happen between * paintings. Recalculating the layout is expensive so we just set this * flag to <code>true</code> many times instead. Then do just a single * layout calculation at the end. */ boolean invalidated; /** * Implicitly called by derived classes to setup a new J4ME form. */ public Dialog () { super(); // Set the default menu options. Theme theme = UIManager.getTheme(); String cancel = theme.getMenuTextForCancel(); String ok = theme.getMenuTextForOK(); setMenuText( cancel, ok ); } /** * Called immediately before this screen is replaced by another screen. * <p> * Notifies all the components they are hidden. Classes that override * this method should be sure to call <code>super.onDeselection</code>. * * @see DeviceScreen#hideNotify() */ public void hideNotify () { // Hide all the components on the screen. Enumeration e = components.elements(); while ( e.hasMoreElements() ) { Component c = (Component)e.nextElement(); c.visible( false ); } // Continue deselection. super.hideNotify(); } /** * Adds the <code>component</code> to the end of this form. * * @param component is the UI component to add to the bottom of the form. */ public void append (Component component) { invalidate(); components.addElement( component ); } /** * Inserts the <code>component</code> in this form at the specified <code>index</code>. * Each component on this form with an index greater or equal to the * specified <code>index</code> is shifted upward to have an index one greater * than the value it had previously. * * @param component is the UI component to insert. * @param index is where to insert <code>component</code> on the form. It must * greater than or equal to 0 and less than or equal to the number of * components already on the form. * @throws ArrayIndexOutOfBoundsException if the index was invalid. */ public void insert (Component component, int index) { invalidate(); components.insertElementAt( component, index ); } /** * Sets the <code>component</code> in this form at the specified <code>index</code>. * The previous component at that position is discarded. * * @param component is the UI component to set to. * @param index is where to set <code>component</code> on the form. It must * greater than or equal to 0 and less than the number of * components already on the form. * @throws ArrayIndexOutOfBoundsException if the index was invalid. */ public void set (Component component, int index) { invalidate(); components.setElementAt( component, index ); } /** * Removes the first occurrence of the <code>component</code> from this form. * If <code>component</code> is found on this form, each component on the form * with an index greater or equal to the <code>component</code>'s index is * shifted downward to have an index one smaller than the value it had * previously. * * @param component is the UI component to remove. */ public void delete (Component component) { int index = components.indexOf( component ); delete( index ); } /** * Deletes the <code>component</code> at the specified <code>index</code>. Each * component in this vector with an index greater or equal to the * specified index is shifted downward to have an index one smaller * than the value it had previously. * * @param index is the index of the component to remove. It must be * a value greater than or equal to 0 and less than the current * number of components on the form. * @throws ArrayIndexOutOfBoundsException if the index was invalid. */ public void delete (int index) { if ( index >= 0 ) { components.removeElementAt( index ); if ( highlightedComponent == index ) { highlightedComponent = -1; } else if ( highlightedComponent > index ) { highlightedComponent--; } invalidate(); } } /** * Removes all of the components from this form. */ public void deleteAll () { components.removeAllElements(); highlightedComponent = -1; invalidate(); } /** * Returns an enumeration of the components on this form. * * @return An enumeration of the components on this form. */ public Enumeration components () { return components.elements(); } /** * Returns the number of components on this form. * * @return The number of components on this form. */ public int size () { return components.size(); } /** * Returns the component at the specified index. * * @param index is the value into the component list to get. * @return The component at <code>index</code> or <code>null</code> if the * index is invalid. */ public Component get (int index) { Component c = null; if ( (index >= 0) && (index < components.size()) ) { c = (Component)components.elementAt( index ); } return c; } /** * Returns the index of the currently selected component. It is * the one the user can currently enter data into. * * @return The index of the component on the form that is currently * selected. */ public int getSelected () { if ( highlightedComponent < 0 ) { return 0; } else { return highlightedComponent; } } /** * Returns the index of the component that contains the given pixel. * If no component is at that location, for example it is in the * spacing between components, then <code>-1</code> is returned. * <p> * This method assumes that the click is relative to the form * area. It may not address the title bar, menu bar, or a * scroll bar. * * @param x is the X-coordinate of the pixel on the form. * @param y is the Y-coordinate of the pixel on the form. * @return The index of the component containing the pixel * (<code>x</code>, <code>y</code>) or <code>-1</code> if no component contains it. */ private int getAt (int x, int y) { int matched = -1; // Get the absolute position of y on the form. int absY = topOfScreen + y; // Walk the list of component positions until absY is found. for ( int i = 0; i < absoluteHeights.length - 1; i++ ) { // Get the dimensions of this component. int top = absoluteHeights[i]; int topOfNext = absoluteHeights[i + 1]; int bottom = topOfNext - spacing; int left = margin; int right = left + componentWidths[i]; // Does the point fall within this component? if ( (absY >= top) && (absY < bottom) && (x >= left) && (x < right) ) { // This is the component that (x, y) falls within. matched = i; } // Stop processing if point is above the top of the component. if ( absY < topOfNext ) { break; } } return matched; } /** * Sets the selected component. It is the one the user can input * data into and that the screen is scrolled to. * * @param index is the new selected component. */ public void setSelected (int index) { if ( (index < 0) || (index >= components.size()) ) { throw new IndexOutOfBoundsException( String.valueOf(index) ); } highlightedComponent = index; // Scroll screen to this component. if ( absoluteHeights == null ) { calculateLayout( UIManager.getTheme(), getWidth(), getHeight() ); } // Set the top of the screen. if ( index == 0 ) { // The top of the screen will be the very start. topOfScreen = 0; } else { // The top of the screen will be the top of the component. topOfScreen = absoluteHeights[index] - spacing; } // Adjust the top of the screen for scrolling. int maxScroll = absoluteHeights[absoluteHeights.length - 1] - getHeight(); if ( maxScroll <= 0 ) { // All the components fit on one form. topOfScreen = 0; } else if ( topOfScreen > maxScroll ) { // Scroll all the way to the bottom. The highlighted // component will be visible, but not at the top of the page. topOfScreen = maxScroll; } } /** * Sets the selected component. It is the one the user can input * data into and that the screen is scrolled to. * * @param component is the new selected component. If it is not * on the form this has no effect. */ public void setSelected (Component component) { int index = 0; // Walk the list of components until we find it. Enumeration e = components.elements(); while ( e.hasMoreElements() ) { Component c = (Component)e.nextElement(); if ( c == component ) { // This is the component. break; } index++; } // Set the component as the selected one. if ( index < size() ) { setSelected( index ); } } /** * Paints the form and its components. The layout is calculated from the * components and their order. * * @param g is the <code>Graphics</code> object to paint with. */ protected synchronized void paint (Graphics g) { // Have we determined the layout? if ( invalidated ) { layout(); invalidated = false; } // Get the height of the screen. Theme theme = UIManager.getTheme(); int height = getHeight(); // Add a vertical scrollbar? if ( hasVerticalScrollbar() ) { // Paint the scrollbar. int width = super.getWidth(); // Exclude the margins and scrollbar int heightOfAllComponents = absoluteHeights[absoluteHeights.length - 1]; paintVerticalScrollbar( g, 0, 0, width, height, topOfScreen, heightOfAllComponents ); } // Get the rest of the form dimensions. int formWidth = getWidth(); int bottomOfScreen = topOfScreen + height; // Walk the list of components and paint them. Enumeration list = components.elements(); for ( int i = 0; i < absoluteHeights.length - 1; i++ ) { Component c = (Component)list.nextElement(); int componentTop = absoluteHeights[i]; int componentBottom = absoluteHeights[i + 1] - spacing; // Is the component visible on the screen? if ( componentTop >= bottomOfScreen ) { // Skip drawing components below the screen. c.visible( false ); } else if ( componentBottom <= topOfScreen ) { // Skip drawing components above the screen. c.visible( false ); } else // visible { c.visible( true ); // Calculate the position of the component. int componentX = margin; int componentY = componentTop - topOfScreen; int componentWidth = formWidth; int componentHeight = componentBottom - componentTop; // Paint this component. if ( intersects(g, componentX, componentY, componentWidth, componentHeight) ) { boolean selected = (i == highlightedComponent); c.paint( g, theme, this, componentX, componentY, componentWidth, componentHeight, selected ); } } } } /** * Paints the vertical scrollbar. The scrollbar must go on the right * side of the form and span from the top to the bottom. Its width * is returned from this method and used to calculate the width of * the remaining form area to draw components in. * * @param g is the <code>Graphics</code> object to paint with. * @param x is the top-left X-coordinate pixel of the form area. * @param y is the top-left Y-coordinate pixel of the form area. * @param width is the width of the form area in pixels. * @param height is the height of the form area in pixels. * @param offset is the vertical scrolling position of the top pixel * to show on the form area. * @param formHeight is the total height of all the components on the * form. This is bigger than <code>height</code>. */ protected void paintVerticalScrollbar (Graphics g, int x, int y, int width, int height, int offset, int formHeight) { UIManager.getTheme().paintVerticalScrollbar( g, x, y, width, height, offset, formHeight ); } /** * Returns the margin for the left and right of the screen. This * also pads the top and bottom of the form; however, scrolling can * make the text appear at the very top and bottom of the screen. * * @return The number of pixels between components and the edges * of the screen. */ public int getMargin () { return margin; } /** * Sets the margin for the left and right of the screen. This * also pads the top and bottom of the form; however, scrolling can * make the text appear at the very top and bottom of the screen. * * @param margin is the number of pixels between components and * the edges of the screen. Values less than 0 are ignored. */ public void setMargin (int margin) { if ( (margin >= 0) && (this.margin != margin) ) { this.margin = margin; // Recalculate the layout with the new margins later. invalidate(); } } /** * Returns the vertical spacing between components. * * @return The number of pixels that vertically separate components. */ public int getSpacing () { return spacing; } /** * Sets the vertical spacing between components. * * @param spacing is the number of pixels that vertically separates * components. Values less than 0 are be ignored. */ public void setSpacing (int spacing) { if ( (spacing >= 0) && (this.spacing != spacing) ) { this.spacing = spacing; // Recalculate the layout with the new spacings later. invalidate(); } } /** * Returns the width of the usuable portion of this form. The usable * portion excludes the vertical scrollbar on the right of the screen * (if it exists). * * @return The number of pixels wide the usable portion of the form is. */ public int getWidth () { int canvasWidth = super.getWidth(); int formWidth = canvasWidth - 2 * margin; if ( hasVerticalScrollbar() ) { int scrollbarWidth = UIManager.getTheme().getVerticalScrollbarWidth(); formWidth -= scrollbarWidth; } return formWidth; } /** * Determines if the height of all the components is greater than the height * of the screen. If so a veritical scrollbar will be drawn on the form. * * @return <code>true</code> if the form has a vertical scrollbar and <code>false</code> * if it does not. */ public synchronized boolean hasVerticalScrollbar () { int screenHeight = getHeight(); int formWidth = super.getWidth() - 2 * margin; boolean layoutJustCalculated = false; Theme theme = UIManager.getTheme(); // Have we determined the layout? if ( invalidated || (absoluteHeights == null) ) { calculateLayout( theme, formWidth, screenHeight ); layoutJustCalculated = true; } // Are all the components taller than the screen? if ( absoluteHeights[absoluteHeights.length - 1] > screenHeight ) { if ( layoutJustCalculated ) { // Recalculate the layout now that we're adding a vertical scrollbar. formWidth -= theme.getVerticalScrollbarWidth(); calculateLayout( theme, formWidth, screenHeight ); } return true; } else { return false; } } /** * Forces the layout of all components to be recalculated. This should * be called whenever this screen is altered. */ public void invalidate () { // We must calculate the layout before the next paint. invalidated = true; } /** * Lays out the components on the screen. This also keeps the * scroll position so the user sees the same components after * being called. */ private synchronized void layout () { // Record the current screen position. int component = 0, delta = 0; if ( absoluteHeights != null ) { if ( highlightedComponent >= 0 ) { component = highlightedComponent; } delta = absoluteHeights[component] - topOfScreen; } // Remove all component location calculations. componentWidths = null; absoluteHeights = null; topOfScreen = 0; // Recalculate the position of all components. hasVerticalScrollbar(); // Reset the screen to its original position. if ( component != 0 ) { highlightedComponent = component; topOfScreen = absoluteHeights[component] - delta; } } /** * Goes through all of the components and determines their vertical * positioning. The form's overall height, the sum of all the * components, is set in the <code>height</code> member variable. * * @param theme is the application's current <code>Theme</code>. * @param widht is the number of pixels wide the screen is. * @param height is the number of pixels high the screen is. */ private synchronized void calculateLayout (Theme theme, int width, int height) { componentWidths = new int[components.size() + 1]; // Dummy element at bottom for end of components absoluteHeights = new int[componentWidths.length]; int componentY = margin; // First component is "margin" from the top // Scroll through the components determining the vertical position of each one. Enumeration list = components.elements(); for ( int i = 0; list.hasMoreElements(); i++ ) { absoluteHeights[i] = componentY; // Calculate the position of the next component. Component c = (Component)list.nextElement(); int[] dimensions = c.getPreferredSize( theme, width, height ); componentWidths[i] = dimensions[0]; componentY += dimensions[1] + spacing; } // Set the first component that can be highlighted. if ( highlightedComponent < 0 ) { highlightedComponent = 0; } // Add a dummy last element to record the bottom of all components. absoluteHeights[absoluteHeights.length - 1] = componentY; } /** * Returns the next component that <code>highlightedComponent</code> * should be set to. The way it is selected is: * <ol> * <li>If two adjacent components accept user input, then that next * component would be returned. * <li>If two components that accept user input are separated by ones * that do not, then we'd still skip to that next one that does. * <li>The exception is when there are enough components that accept * user input between the two that more than a screen's height * is between them. In that case we need to set one of the * intermediate components so the screen does not scroll too far. * </ol> * * @param down when <code>true</code> means the next component with a * higher index; when <code>false</code> means the next with a lower. * @param maxScroll is the maximum number of pixels that can be scrolled * to get to the next component. For example it may be 90% the height * of the screen. * @return The index of the next component to highlight. */ private int nextHighlightableComponent (boolean down, int maxScroll) { if ( down ) { // How far down can the component be? int maxBottom; if ( highlightedComponent < 0 ) { maxBottom = topOfScreen; } else { maxBottom = topOfScreen + getHeight(); } maxBottom += maxScroll; // Walk through the components until we find the next one to highlight. int components = size(); for ( int next = highlightedComponent + 1; next < components; next++ ) { // Otherwise have we walked off the end of the screen? int nextBottom = absoluteHeights[next + 1]; if ( nextBottom > maxBottom ) { if ( next - 1 == highlightedComponent ) { // Move at least to the next component, even if it cannot // be completely shown because it is bigger than the screen. return next; } else { // Show the one before next so it can be completely // shown on the screen. return next - 1; } } else { // If this component accepts input stop on it. Component c = get( next ); if ( c.acceptsInput() ) { return next; } } } // If we made it here highlight the last component. return components - 1; } else // up { if ( highlightedComponent > 0 ) { // How far up can the component be? int maxTop = topOfScreen - maxScroll; // Walk through the components until we find the next one to highlight. for ( int next = highlightedComponent - 1; next >= 0; next-- ) { // Otherwise have we walked off the end of the screen? int nextTop = absoluteHeights[next]; if ( nextTop < maxTop ) { if ( next + 1 == highlightedComponent ) { // Move at least to the next component, even if it cannot // be shown because it is bigger than the screen. return next; } else { // Show the one before next so it can be completely // shown on the screen. return next + 1; } } else { // If this component accepts input stop on it. Component c = get( next ); if ( c.acceptsInput() ) { return next; } } } } // If we made it here highlight the first component. return 0; } } /** * Moves the viewport of the form up or down and calls <code>repaint</code>. * <p> * The amount scrolled is dependent on the components shown. Typically * one scroll increment advances to the next component. However, if * components are taller than the screen they will be partially scrolled. * * @param down is <code>true</code> when the form should scroll down and * <code>false</code> when it should scroll up. */ private void scroll (boolean down) { // Safety checks. if ( absoluteHeights == null ) { // Calculated the layout. hasVerticalScrollbar(); } if ( components.size() == 0 ) { // Can't scroll with no components. return; } // Get the dimensions of the form. int topOfForm = 0; int screenHeight = getHeight(); int bottomOfForm = absoluteHeights[absoluteHeights.length - 1] - screenHeight; int bottomOfScreen = topOfScreen + screenHeight; // We scroll 90% of the screen unless there is another highlightable // component within that 90%. In which case we scroll only to the // highlightable component, not the full 90%. int max = screenHeight * 9 / 10; // Get the next component that can be highlighted. int current = highlightedComponent; highlightedComponent = nextHighlightableComponent( down, max ); // Scroll. if ( hasVerticalScrollbar() ) { // Calculate the number of pixels to scroll the form. int scroll; // Calculate how far to scroll to get to the next highlighted component. if ( down ) { int currentBottom = absoluteHeights[current + 1]; if ( currentBottom > bottomOfScreen ) { // The current component actually is clipped by the bottom of // the screen (because it is too big to show all at once). // Just scroll down we can see more of it. scroll = max; } else { // Get the screen position of the next highlightable component. int nextTop = absoluteHeights[highlightedComponent]; int nextBottom = absoluteHeights[highlightedComponent + 1]; if ( (nextTop > topOfScreen) && (nextBottom < bottomOfScreen) ) { // Don't scroll if the next highlighted component fits // completely on the screen already. scroll = 0; } else { scroll = nextBottom - currentBottom; } } } else // up { int currentTop = absoluteHeights[current]; if ( currentTop < topOfScreen ) { // The current component actually is clipped by the top of // the screen (because it is too big to show all at once). // Just scroll up we can see more of it. scroll = max; } else { if ( highlightedComponent == 0 ) { // Scroll to the very top of the dialog. scroll = topOfScreen; } else { // Get the bottom of the component above the next highlighted one. int previousBottom = absoluteHeights[highlightedComponent] - spacing; scroll = topOfScreen - previousBottom; // Don't scroll if the next highlighted component fits // completely on the screen already. if ( previousBottom >= topOfScreen ) { scroll = 0; } } } } // Set the position of the form. if ( scroll > max ) { scroll = max; } if ( down == false ) { // If scrolling up, set the scroll to a negative number. scroll *= -1; } topOfScreen += scroll; if ( topOfScreen < topOfForm ) { topOfScreen = topOfForm; } else if ( topOfScreen > bottomOfForm ) { topOfScreen = bottomOfForm; } } // Redraw the screen at the scrolled position. repaint(); } /** * Shows or hides the menu bar at the bottom of the screen. * * @param mode is <code>true</code> if the <code>DeviceScreen</code> is to be in full * screen mode, <code>false</code> otherwise. */ public void setFullScreenMode (boolean mode) { super.setFullScreenMode( mode ); invalidate(); } /** * Sets the menu bar text. * <p> * For the menu to be visible full screen mode must be off. * This can be done with the <code>setFullScreenMode</code> method. * * @param left is the text for the negative menu option or <code>null</code> * to remove the button. Negative menu options are things like canceling * a form and moving back to a previous screen. * @param right is the text for the positive menu option or <code>null</code> * to remove the button. Positive menu options are things like accepting * a form, advancing to the next screen, or displaying a menu. * @see #declineNotify() * @see #acceptNotify() */ public void setMenuText (String left, String right) { super.setMenuText( left, right ); invalidate(); } /** * Sets the title of this screen. The default is <code>null</code> meaning no * title. * <p> * For the title to be visible full screen mode must be off. * This can be done with the <code>setFullScreenMode</code> method. * * @param title is the new title for the screen. */ public void setTitle (String title) { super.setTitle( title ); invalidate(); } /** * Called when a key is pressed. It can be identified using the * constants defined in this class. * * @param keyCode is the key code of the key that was pressed. */ protected void keyPressed (int keyCode) { // Forward the event to the current component. Component c = get( highlightedComponent ); if ( c != null ) { c.keyPressed( keyCode ); } // Scrolling vertically? if ( keyCode == UP ) { scroll( false ); } else if ( keyCode == DOWN ) { scroll( true ); } // Continue processing the event. super.keyPressed( keyCode ); } /** * Called when a key is repeated (held down). It can be identified using the * constants defined in this class. * * @param keyCode is the key code of the key that was held down. */ protected void keyRepeated (int keyCode) { // Forward the event to the current component. Component c = get( highlightedComponent ); if ( c != null ) { c.keyRepeated( keyCode ); } // Continue processing the event. super.keyRepeated( keyCode ); } /** * Called when a key is released. It can be identified using the * constants defined in this class. * * @param keyCode is the key code of the key that was released. */ protected void keyReleased (int keyCode) { // Forward the event to the current component. Component c = get( highlightedComponent ); if ( c != null ) { c.keyReleased( keyCode ); } // Continue processing the event. super.keyReleased( keyCode ); } /** * Called when the pointer is pressed. * * @param x is the horizontal location where the pointer was pressed. * @param y is the vertical location where the pointer was pressed. */ protected void pointerPressed (int x, int y) { // Is this event moving the scrollbar? boolean movedScrollbar = false; if ( hasVerticalScrollbar() ) { // Was the click over the scrollbar? int screenWidth = getScreenWidth(); int scrollbarWidth = UIManager.getTheme().getVerticalScrollbarWidth(); int scrollbarX = screenWidth - scrollbarWidth; if ( x >= scrollbarX ) { // The user clicked on the scrollbar. movedScrollbar = true; // Calculate the height of the trackbar. int height = getHeight(); int formHeight = absoluteHeights[absoluteHeights.length - 1]; int scrollableHeight = formHeight - height; double trackbarPercentage = (double)height / (double)formHeight; int trackbarHeight = (int)MathFunc.round( height * trackbarPercentage ); trackbarHeight = Math.max( trackbarHeight, 2 * scrollbarWidth ); // Calculate the range and location of the trackbar. // The scrollbar doesn't actually go from 0% to 100%. The top // is actually 1/2 the height of the trackbar from the top of // the screen. The bottom is 1/2 the height from the bottom. int rangeStart = trackbarHeight / 2; int range = height - 2 * rangeStart; double offsetPercentage = (double)topOfScreen / (double)scrollableHeight; int center = rangeStart + (int)MathFunc.round( offsetPercentage * range ); if ( y < center ) { // Move the scrollbar up one component. scroll( false ); } else { // Move the scrollbar down one component. scroll( true ); } } } // Forward the event to the component clicked on. if ( movedScrollbar == false ) { // Highlight the component. highlightedComponent = getAt( x, y ); // Forward the event to the component for processing. Component c = get( highlightedComponent ); if ( c != null ) { // Adjust the click position relative to the component. int px = x - c.getX(); int py = y - c.getY(); c.pointerPressed( px, py ); } } // Continue processing the event. super.pointerPressed( x, y ); } /** * Called when the pointer is dragged. * * @param x is the horizontal location where the pointer was dragged. * @param y is the vertical location where the pointer was dragged. */ protected void pointerDragged (int x, int y) { // Forward the event to the current component. Component c = get( highlightedComponent ); if ( c != null ) { c.pointerDragged( x, y ); } // Continue processing the event. super.pointerDragged( x, y ); } /** * Called when the pointer is released. * * @param x is the horizontal location where the pointer was released. * @param y is the vertical location where the pointer was released. */ protected void pointerReleased (int x, int y) { // Forward the event to the current component. Component c = get( highlightedComponent ); if ( c != null ) { c.pointerReleased( x, y ); } // Continue processing the event. super.pointerReleased( x, y ); } }