Slick Forums

Discuss the Slick 2D Library
It is currently Wed Jun 19, 2013 6:21 am

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Mon May 21, 2007 11:33 pm 
Offline
User avatar

Joined: Fri May 04, 2007 5:58 pm
Posts: 72
Working a little in my project I'm trying to make my mini-engine (based in Scene, Actor, etc., a bit like Slickset but in another way) work with the Slick GUI components. For this I need the following code in BasicComponent:

Code:
   /**
    * Get the width of the component
    *
    * @return The width of the component
    */
   public abstract int getWidth();

   /**
    * Get the height of the component
    *
    * @return The height of the component
    */
   public abstract int getHeight();


This is absolutely needed for some basic layout (or complex, of course! ;)) and allows for another interesting effects (just imagine a rain effect splashing against a message box, for example 8)). And, if you look at it, the existing subclasses already have these methods or something alike. MouseOverArea works like it is now and TextField just needs this:

Code:
   /**
    * Get the width of the component
    *
    * @return The width of the component
    */
   public int getWidth() {
      return (int) area.getWidth();
   }

   /**
    * Get the height of the component
    *
    * @return The height of the component
    */
   public int getHeight() {
      return (int) area.getHeight();
   }


I haven't looked into SUI (downloaded some weeks ago and it didn't compile out of the box, something about the versions, I'm sure) but I don't think it would suppose difficult changes.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 22, 2007 12:29 am 
Offline
User avatar

Joined: Fri May 04, 2007 5:58 pm
Posts: 72
Spoken too early, obviously the location of the component is also needed (tried to override it with the location of my GUIActor but it was too messy, delegation is clearly better).

BasicComponent:

Code:
   /** The location in the X coordinate*/
   protected int x;
   /** The location in the Y coordinate*/
   protected int y;

   /**
    * Create a new component
    *
    * @param container The container displaying this component
    */
   public BasicComponent(GUIContext container) {
      this.container = container;
      
      input = container.getInput();
      input.addPrimaryListener(this);
      
      x = y = 0;
   }

   /**
    * Moves the component.
    *
    * @param x X coordinate
    * @param y Y coordinate
    */
   public void setLocation(int x, int y) {
      this.x = x;
      this.y = y;
      
   }
   
   /**
    * Returns the position in the X coordinate
    * @return x
    */
   public int getX() {
      return x;
   }

   /**
    * Returns the position in the Y coordinate
    * @return y
    */
   public int getY() {
      return y;
   }


TextField:

Code:
   /** The width of the field */
   private int width;
   /** The height of the field */
   private int height;

   public TextField(GUIContext container, Font font, int x, int y, int width, int height, ComponentListener listener) {
      super(container);
      
      this.listener = listener;
      this.font = font;
      
      setLocation(x, y);
      this.width = width;
      this.height = height;
   }


   /**
    * Get the width of the component
    *
    * @return The width of the component
    */
   public int getWidth() {
      return width;
   }

   /**
    * Get the height of the component
    *
    * @return The height of the component
    */
   public int getHeight() {
      return height;
   }

   /**
    * @see org.newdawn.slick.gui.BasicComponent#renderImpl(org.newdawn.slick.gui.GUIContext, org.newdawn.slick.Graphics)
    */
   public void renderImpl(GUIContext container, Graphics g) {
      g.setClip(x, y-1, width+1, height+1);
      if (background != null) {
         g.setColor(background);
         g.fillRect(x, y, width, height);
      }
      if (border != null) {
         g.setColor(border);
         g.drawRect(x, y, width, height);
      }
      g.setColor(text);
      Font temp = g.getFont();
      
      int cpos = font.getWidth(value.substring(0, cursorPos));
      int tx = 0;
      if (cpos > width) {
         tx = width - cpos - font.getWidth("_");
      }
      
      g.translate(tx+2,0);
      g.setFont(font);
      g.drawString(value, x+1, y+1);
      
      if ((focus) && (visibleCursor)) {
         g.drawString("_", x+1+cpos+2, y+1);
      }
      
      g.translate(-tx-2, 0);
      
      g.clearClip();
      

      if (focus) {
         // key repeat handling
         if (input.isKeyDown(Input.KEY_LEFT)) {
            if (container.getTime() - repeatLeft > REPEAT_TIMER) {
               repeatLeft = container.getTime();
               if (cursorPos > 0) {
                  cursorPos--;
               }
            }
         }
         if (input.isKeyDown(Input.KEY_RIGHT)) {
            if (container.getTime() - repeatRight > REPEAT_TIMER) {
               repeatRight = container.getTime();
               if (cursorPos < value.length()) {
                  cursorPos++;
               }
            }
         }
         if (input.isKeyDown(Input.KEY_BACK)) {
            if (container.getTime() - repeatBack > REPEAT_TIMER) {
               if ((cursorPos > 0) && (value.length() > 0)) {
                  if (cursorPos < value.length()) {
                     value = value.substring(0, cursorPos-1) + value.substring(cursorPos);
                  } else {
                     value = value.substring(0, cursorPos-1);
                  }
                  cursorPos--;
                  repeatBack = container.getTime();
               }
            }
         }
      }
   }

   /**
    * @see org.newdawn.slick.gui.BasicComponent#mouseReleased(int, int, int)
    */
   public void mouseReleased(int button, int x, int y) {
      setFocus((x >= this.x) && (y >= this.y) && (x <= this.x + width)
            && (y <= this.y + height));
   }


MouseOverArea:

Code:
   /** The width of the field */
   private int width;
   /** The height of the field */
   private int height;

   /**
    * Create a new mouse over area
    *
    * @param container The container displaying the mouse over area
    * @param image The normalImage to display
    * @param x The position of the area
    * @param y the position of the area
    * @param width The width of the area
    * @param height The height of the area
    * @param listener The listener to notify of events
    */
   public MouseOverArea(GUIContext container, Image image, int x, int y, int width, int height, ComponentListener listener) {
      super(container);
      
      normalImage = image;
      currentImage = image;
      mouseOverImage = image;
      mouseDownImage = image;
      
      currentColor = normalColor;
      
      this.listener = listener;
      
      setLocation(x, y);
      this.width = width;
      this.height = height;
   }

   /**
    * Get the width of the area
    *
    * @return The width of the area
    */
   public int getWidth() {
      return width;
   }

   /**
    * Get the height of the area
    *
    * @return The height of the area
    */
   public int getHeight() {
      return height;
   }

   /**
    * @see org.newdawn.slick.gui.BasicComponent#renderImpl(org.newdawn.slick.gui.GUIContext,
    *      org.newdawn.slick.Graphics)
    */
   public void renderImpl(GUIContext container, Graphics g) {
      mouseDown = input.isMouseButtonDown(0);
      int mX = input.getMouseX(), mY = input.getMouseY();
      updateImage((mX >= x) && (mY >= y) && (mX <= x + width)
            && (mY <= y + height));

      if (currentImage != null) {
         int xp = x + ((width - currentImage.getWidth()) / 2);
         int yp = y + ((height - currentImage.getHeight()) / 2);

         currentImage.draw(xp, yp, currentColor);
      } else {
         g.setColor(currentColor);
         g.fillRect(x, y, width, height);
      }
   }


(Erased rect in MouseOverArea and area in TextField, because they aren't needed anymore. Another alternative is making abstract setLocation, getX and getY and using the Rectangle in every subclass to store the location as well... just realized it. ^_^U Don't want to expose the area itself in BasicComponent because I'm adding a TextMenu where you set a Font and an array of Strings and the width and height adjust accordingly)

Nevertheless, with these changes we have complete control of the GUI elements and we can arrange them, move them, make composites, etc. in a really easy way.

Anyone with me? Please?

Pretty please covered in sugar? :D


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 22, 2007 2:03 am 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1477
The component's x and y positions should probably be in floats to be consistent with the rest of the library.

Also, in my opinion, since BasicComponent is an abstract class, it would be best for subclasses to declare the x/y variables itself. For example, a component that uses Rectangle bounds might wish to use the following:
Code:
public float getX() {
    return bounds.getX();
}


The additional x/y variables will cause overhead & confusion for components that don't need them.


Otherwise I agree with what you're saying. Getters for size/location is pretty important for most GUIs.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 22, 2007 8:49 am 
Offline
User avatar

Joined: Fri May 04, 2007 5:58 pm
Posts: 72
davedes wrote:
The component's x and y positions should probably be in floats to be consistent with the rest of the library.


Absolutely right, this is an issue that irks me (also happen in the Animation class, for instance) and I was going to request all the changes once I've worked with all the primitives I need.

davedes wrote:
Also, in my opinion, since BasicComponent is an abstract class, it would be best for subclasses to declare the x/y variables itself.


It was because (x, y) can be managed exactly the same in all the components I can think of (unlike width and height, that can be automatic or not) and didn't want to copy/paste much. But it's a matter of taste, I would be happy to use your way. :)

davedes wrote:
The additional x/y variables will cause overhead & confusion for components that don't need them.


Yeah, I'm strongly against that, but in this case, what component won't be using them? (Having coded SUI you've thought about this much more than me.)


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 22, 2007 8:19 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1477
Like I said, using Shape as bounds for your component might mean no need for x/y variables. Take a look at this example, which uses Rectangle (other components may choose to have Circle bounds or even Polygon bounds):

Code:
class SimpleRectangleButton extends BasicComponent {
    private Rectangle bounds;

    public SimpleRectangleButton(GUIContext context) {
        super(context);
        this.bounds = new Rectangle(0,0,0,0);
    }

    public void setX(float x) {
        return this.bounds.setX(x);
    }

    public void setY(float x) {
        return this.bounds.setY(x);
    }

    public float getX() {
        return this.bounds.getX();
    }

    public float getY() {
        return this.bounds.getY();
    }

    public Rectangle getBounds() {
        return bounds;
    }

    public void setBounds(Rectangle rect) {
        this.bounds = rect;
    }
}



Now let's say a class overrides SimpleRectangleButton. The protected x/y variables inherited from BasicComponent will be misleading and confusing because changing them won't do anything.

Just my two cents. :)


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 25, 2007 2:33 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Leaving this alone pending the refactor Serandel has volunteered for elsewhere.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 6:20 am 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
In SVN now.

Kev


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group