/* * File : BasicSkin.java * Created : 10-oct-2001 18:19 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2005 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * 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 (see the LICENSE file). */ package edu.xtec.jclic.skins; import edu.xtec.jclic.*; import edu.xtec.jclic.boxes.*; import edu.xtec.jclic.fileSystem.FileSystem; import edu.xtec.jclic.misc.*; import edu.xtec.util.*; import java.awt.*; import java.awt.image.*; import javax.swing.*; import javax.swing.border.*; /** * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.08.28 */ public class BasicSkin extends Skin { BufferedImage img; Color fillColor; int initiated; Rectangle frame; int leftSlicer, rightSlicer, topSlicer, bottomSlicer; Rectangle playerRect; Rectangle msgRect; Rectangle [] msgAreaRect = new Rectangle[NUM_MSG_AREAS]; Color textColor; Rectangle [] buttonsRect = new Rectangle[Constants.NUM_ACTIONS]; Rectangle [][] countersRect = new Rectangle[Constants.NUM_COUNTERS][]; ActiveBox[] countersLabel = new ActiveBox[Constants.NUM_COUNTERS]; AbstractBox[] boxes = new AbstractBox[NUM_BOXES]; JProgressBar progressBar; Rectangle progressBarRect; Rectangle progressAnimationRect; AnimatedActiveBox progressAnimation; boolean hideProgressBar, hideProgressAnim; static final int NUM_BOXES=2*Constants.NUM_COUNTERS+5; /** Creates new BasicSkin */ protected BasicSkin() { super(); for(int i=0; i<Constants.NUM_COUNTERS; i++) countersRect[i]=new Rectangle[2]; progressBar=null; progressAnimation=null; hideProgressBar=true; hideProgressAnim=true; initiated=0; } public static final String IMAGE="image", PREFERRED_SIZE="preferredSize", FRAME="frame", PLAYER="player", FILL="fill", SLICER="slicer", MESSAGES="messages", STATUS_BAR="statusBar", SETTINGS="settings", STYLE="style", FOREGROUND="foreground", BACKGROUND="background", MSG_AREA="msgArea", BORDER="border", BUTTONS="buttons", BUTTON="button", ACTIVE="active", OVER="over", DISABLED="disabled", POS="pos", SOURCE="source", COUNTERS="counters", COUNTER="counter", LABEL="label", DIGITS="digits", TOGGLE="toggle", PROGRESS_BAR="progressBar", AUTO_HIDE="autoHide", SHOW_PERCENT="showPercent", PROGRESS_ANIMATION="progressAnimation", FRAMES="frames", DELAY="delay", STEP="step"; protected void setProperties(org.jdom.Element e, FileSystem fs) throws Exception{ org.jdom.Element child, child2, child3, child4; BoxBase bb; setPreferredSize(JDomUtility.getDimension(e, PREFERRED_SIZE, new Dimension(640, 480))); fillColor=JDomUtility.getColorByPoint(e, FILL, img, Color.white); String imageFile=JDomUtility.getStringAttr(e, IMAGE, null, true); if(imageFile==null || imageFile.length()==0) throw new Exception("BasicSkin properties without image name!"); if(fs==null){ //ImageIcon imgIcon=new ImageIcon(getClass().getResource(imageFile)); ImageIcon imgIcon=ResourceManager.getImageIcon(RESOURCE_FOLDER+"/"+imageFile); img=Utils.toBufferedImage(imgIcon.getImage(), fillColor, this); } else{ ImageIcon imgi=new ImageIcon(fs.getBytes(imageFile)); img=Utils.toBufferedImage(imgi.getImage(), fillColor, this); } // re-check color (may be specified by point) fillColor=JDomUtility.getColorByPoint(e, FILL, img, Color.gray); setBackground(fillColor); frame=JDomUtility.getRectangle(e, FRAME, null); setMinimumSize(frame.getSize()); child=e.getChild(SLICER); leftSlicer=JDomUtility.getIntAttr(child, JDomUtility.LEFT, 0); rightSlicer=JDomUtility.getIntAttr(child, JDomUtility.RIGHT, 0); topSlicer=JDomUtility.getIntAttr(child, JDomUtility.TOP, 0); bottomSlicer=JDomUtility.getIntAttr(child, JDomUtility.BOTTOM, 0); playerRect=JDomUtility.getRectangle(e, PLAYER, null); msgRect=JDomUtility.getRectangle(e, MESSAGES, null); bb=new BoxBase(); bb.transparent=true; msgBox=new ActiveBox(null, this, 0, msgRect, bb); if((child=e.getChild(PROGRESS_BAR))!=null){ hideProgressBar=JDomUtility.getBoolAttr(child, AUTO_HIDE, true); BoxBase bbProgres=getBoxBase(child, null); progressBarRect=JDomUtility.getRectangle(child, null, null); if(progressBarRect!=null){ progressBar=new JProgressBar(); BoxBase bbProgress=getBoxBase(child, null); progressBar.setBackground(bbProgress.backColor); progressBar.setForeground(bbProgress.textColor); progressBar.setFont(bbProgress.getFont()); //progressBar.setBorderPainted(JDomUtility.getBoolAttr(child, BORDER, true)); progressBar.setStringPainted(JDomUtility.getBoolAttr(child, SHOW_PERCENT, true)); progressBar.setOpaque(false); progressBar.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); add(progressBar); progressBar.setVisible(!hideProgressBar); hasProgress=true; } } if((child=e.getChild(PROGRESS_ANIMATION))!=null){ Dimension d=JDomUtility.getDimension(child, null, null); Point source=JDomUtility.getPoint(child, SOURCE, null); Point pos=JDomUtility.getPoint(child, POS, null); int frames=JDomUtility.getIntAttr(child, FRAMES, 0); int delay=JDomUtility.getIntAttr(child, DELAY, 0); int direction=JDomUtility.getDirection(child, JDomUtility.DIRECTION_DOWN); hideProgressAnim=JDomUtility.getBoolAttr(child, AUTO_HIDE, true); if(d!=null && source!=null && frames>0 && delay>=AnimatedActiveBox.MIN_DELAY){ int dx, dy; switch(direction){ case JDomUtility.DIRECTION_RIGHT: dx=1; dy=0; break; case JDomUtility.DIRECTION_LEFT: dx=-1; dy=0; break; case JDomUtility.DIRECTION_UP: dx=0; dy=-1; break; default: dx=0; dy=1; } int sx=JDomUtility.getIntAttr(child, STEP, d.width); int sy=JDomUtility.getIntAttr(child, STEP, d.height); progressAnimationRect=new Rectangle(pos, d); progressAnimation=new AnimatedActiveBox(null, this, 0, progressAnimationRect, getBoxBase(child, null)); progressAnimation.setDelay(delay); ActiveBagContent abc=new ActiveBagContent(1, frames); for(int i=0; i<frames; i++){ ActiveBoxContent ab=new ActiveBoxContent(); ab.setImgContent(img, new Rectangle(source.x+(dx*i*sx), source.y+(dy*i*sy), d.width, d.height)); abc.addActiveBoxContent(ab); } progressAnimation.setContent(abc); progressAnimation.setVisible(!hideProgressAnim); } } if((child=e.getChild(STATUS_BAR))!=null){ BoxBase bbMsgDef=getBoxBase(child, null); textColor=bbMsgDef.textColor; for(int i=0; i<NUM_MSG_AREAS; i++) if((child2=JDomUtility.getChildWithId(child, MSG_AREA, msgAreaNames[i]))!=null){ msgAreaRect[i]=JDomUtility.getRectangle(child2, null, null); bb=getBoxBase(child2, bbMsgDef); bb.textMargin=0; msgArea[i]=new ActiveBox(null, this, 0, msgAreaRect[i], bb); ActiveBoxContent abc=new ActiveBoxContent(); abc.setBoxBase(bb); abc.setTxtAlign(JDomUtility.getAlignment(child2, null, null)); msgArea[i].setContent(abc); } } if((child=e.getChild(BUTTONS))!=null){ child2=child.getChild(SETTINGS); Dimension dDef=JDomUtility.getDimension(child2, null, new Dimension()); Point activeDef=JDomUtility.getOffset(child2, ACTIVE, null); Point overDef=JDomUtility.getOffset(child2, OVER, null); Point disabledDef=JDomUtility.getOffset(child2, DISABLED, null); for(int i=0; i<Constants.NUM_ACTIONS; i++) if((child2=JDomUtility.getChildWithId(child, BUTTON, Constants.ACTION_NAME[i]))!=null){ Point pos=JDomUtility.getPoint(child2, POS, null); boolean toggle=JDomUtility.getBoolAttr(child2, TOGGLE, false); if(pos!=null){ child3=child2.getChild(SETTINGS); Dimension d=JDomUtility.getDimension(child3, null, dDef); buttonsRect[i]=new Rectangle(pos, d); Point source=JDomUtility.getPoint(child2, SOURCE, null); Point active=JDomUtility.getOffset(child3, ACTIVE, activeDef); Point over=JDomUtility.getOffset(child3, OVER, overDef); Point disabled=JDomUtility.getOffset(child3, DISABLED, disabledDef); buttons[i]=createButton(i, d, source, active, over, disabled, toggle); } } } if((child=e.getChild(COUNTERS))!=null){ child2=child.getChild(SETTINGS); Dimension dCounterDef=JDomUtility.getDimension(child2, COUNTER, new Dimension()); Dimension dLabelDef=JDomUtility.getDimension(child2, LABEL, new Dimension()); //int[] dCounterAlign=JDomUtility.getAlignment(child2, COUNTER, null); int[] dLabelAlign=JDomUtility.getAlignment(child2, LABEL, null); BoxBase bbCountersDef=getBoxBase(child, null); child2=child.getChild(DIGITS); Dimension dSizeDef=JDomUtility.getDimension(child2, null, null); Point dOriginDef=JDomUtility.getPoint(child2, SOURCE, null); for(int i=0; i<Constants.NUM_COUNTERS; i++) if((child2=JDomUtility.getChildWithId(child, COUNTER, Constants.counterNames[i]))!=null){ child3=child.getChild(SETTINGS); bb=getBoxBase(child2, bbCountersDef); bb.textMargin=0; Point counterPos=JDomUtility.getPoint(child2, COUNTER, null); if(counterPos!=null){ Dimension dCounter=JDomUtility.getDimension(child3, COUNTER, dCounterDef); countersRect[i][0]=new Rectangle(counterPos, dCounter); child4=child2.getChild(DIGITS); Dimension dSize=JDomUtility.getDimension(child4, null, dSizeDef); Point dOrigin=JDomUtility.getPoint(child4, SOURCE, dOriginDef); counters[i]=new Counter(null, this, countersRect[i][0], bb); counters[i].setSource(img, dOrigin, dSize); } Point labelPos=JDomUtility.getPoint(child2, LABEL, null); if(labelPos!=null){ Dimension dLabel=JDomUtility.getDimension(child3, LABEL, dLabelDef); countersRect[i][1]=new Rectangle(labelPos, dLabel); countersLabel[i]=new ActiveBox(null, this, 0, countersRect[i][1], bb); ActiveBoxContent abc=new ActiveBoxContent(); abc.setBoxBase(bb); abc.setTxtAlign(JDomUtility.getAlignment(child2, LABEL, dLabelAlign)); abc.setTextContent(ps.getMsg("label_"+Constants.counterNames[i])); countersLabel[i].setContent(abc); } } } int c, l, k=0; for(c=0; c<Constants.NUM_COUNTERS; c++){ boxes[k++]=counters[c]; boxes[k++]=countersLabel[c]; } for(l=0; l<NUM_MSG_AREAS; l++){ boxes[k++]=msgArea[l]; } boxes[k++]=msgBox; boxes[k++]=progressAnimation; initiated=1; } protected BoxBase getBoxBase(org.jdom.Element e, BoxBase defaultValue) throws Exception{ org.jdom.Element child; if(e==null || (child=e.getChild(STYLE))==null) return defaultValue; BoxBase bb= defaultValue==null ? new BoxBase() : BoxBase.getBoxBase(defaultValue.getJDomElement()); org.jdom.Element child2=child.getChild(JDomUtility.FONT); if(child2!=null) bb.setFont(JDomUtility.elementToFont(child2)); bb.textColor=JDomUtility.getColorByPoint(child, FOREGROUND, img, bb.textColor); bb.backColor=JDomUtility.getColorByPoint(child, BACKGROUND, img, bb.backColor); if(bb.backColor==BoxBase.DEFAULT_BACK_COLOR) bb.transparent=true; else bb.transparent=JDomUtility.getBoolAttr(child, BoxBase.TRANSPARENT, bb.transparent); bb.textMargin=JDomUtility.getIntAttr(child, BoxBase.MARGIN, bb.textMargin); return bb; } @Override public void doLayout(){ if(initiated<1){ invalidate(); return; } super.doLayout(); if(player!=null) player.setBounds(translateRect(playerRect)); if(progressBar!=null) progressBar.setBounds(translateRect(progressBarRect)); for(int i=0; i<buttons.length; i++) if(buttons[i]!=null) buttons[i].setBounds(translateRect(buttonsRect[i])); for(int i=0; i<Constants.NUM_COUNTERS; i++){ if(counters[i]!=null) counters[i].setLocation(translatePoint(countersRect[i][0].getLocation())); if(countersLabel[i]!=null) countersLabel[i].setLocation(translatePoint(countersRect[i][1].getLocation())); } if(msgBox!=null) msgBox.setBounds(translateRect(msgRect)); if(progressAnimation!=null) progressAnimation.setBounds(translateRect(progressAnimationRect)); for(int i=0; i<NUM_MSG_AREAS; i++) if(msgArea[i]!=null) msgArea[i].setBounds(translateRect(msgAreaRect[i])); if(player!=null) initiated=2; } @Override public void startAnimation(){ if(progressAnimation!=null){ if(hideProgressAnim) progressAnimation.setStartDelay(DEFAULT_PROGRESS_WAKE_ON); //progressAnimation.setVisible(true); progressAnimation.start(); } } @Override public void stopAnimation(){ if(progressAnimation!=null){ if(hideProgressAnim) progressAnimation.setVisible(false); progressAnimation.stop(false); } } public void render(Graphics2D g2, Rectangle clip){ if(player==null || initiated<2) return; if(!readyToPaint) readyToPaint=true; //super.paintComponent(g); if(counters!=null) for(int i=0; i<Constants.NUM_COUNTERS; i++){ if(counters[i]!=null && counters[i].getBounds().equals(clip)){ Utils.drawImage(g2, img, counters[i].getBounds(), countersRect[i][0], this); counters[i].update(g2, clip, this); return; } } drawSlicedFrame(g2, getBounds(), frame, img, leftSlicer, rightSlicer, topSlicer, bottomSlicer); if(boxes!=null) for(int i=0; i<NUM_BOXES; i++){ if(boxes[i]!=null){ boxes[i].update(g2, clip, this); if(boxes[i].getBounds().equals(clip)){ return; } } } } @Override public void setLocale(java.util.Locale l){ super.setLocale(l); if(ps!=null && countersLabel!=null) for(int i=0; i<Constants.NUM_COUNTERS; i++) if(countersLabel[i]!=null) countersLabel[i].setTextContent(ps.getMsg("label_"+Constants.counterNames[i])); } protected AbstractButton createButton(int buttonId, Dimension d, Point source, Point active, Point over, Point disabled, boolean toggle){ final AbstractButton button; Action action=ps.getAction(buttonId); if(source!=null){ ImageIcon icon; icon=new ImageIcon(img.getSubimage(source.x, source.y, d.width, d.height)); if(!toggle) //button=new JButton(icon); button=new JButton(action); else //button=new JToggleButton(icon); button=new JToggleButton(action); button.setIcon(icon); button.setText(null); if(active!=null){ icon=new ImageIcon(img.getSubimage(source.x+active.x, source.y+active.y, d.width, d.height)); if(!toggle) button.setPressedIcon(icon); else button.setSelectedIcon(icon); } if(over!=null){ icon=new ImageIcon(img.getSubimage(source.x+over.x, source.y+over.y, d.width, d.height)); button.setRolloverIcon(icon); } if(disabled!=null){ icon=new ImageIcon(img.getSubimage(source.x+disabled.x, source.y+disabled.y, d.width, d.height)); button.setDisabledIcon(icon); } button.setFocusPainted(false); button.setBorderPainted(false); button.setBorder(new EmptyBorder(0,0,0,0)); button.setContentAreaFilled(false); button.setMargin(new Insets(0,0,0,0)); } else{ button=new JButton(action); //button=new JButton(ac.getMsg("button_"+s+"_caption")); } //button.setToolTipText(ac.getMsg("button_"+s+"_tooltip")); button.setPreferredSize(buttonsRect[buttonId].getSize()); button.setVisible(true); //button.setEnabled(false); //button.setActionCommand(s); if(toggle){ Object o=action.getValue(AbstractAction.DEFAULT); button.setSelected(o!=null && o.equals(Boolean.FALSE)); action.addPropertyChangeListener(new java.beans.PropertyChangeListener(){ public void propertyChange(java.beans.PropertyChangeEvent evt){ if(evt.getPropertyName().equals("selected")){ button.setSelected(evt.getNewValue().equals(Boolean.FALSE)); } } }); } add(button); return button; } Point translatePoint(Point pt){ Rectangle bounds=getBounds(); Dimension extra=new Dimension(bounds.width-frame.width, bounds.height-frame.height); Point result=new Point(pt); if(pt.x>rightSlicer) result.x+=extra.width; if(pt.y>bottomSlicer) result.y+=extra.height; return result; } Rectangle translateRect(Rectangle r){ Rectangle bounds=getBounds(); Dimension extra=new Dimension(bounds.width-frame.width, bounds.height-frame.height); Rectangle result=new Rectangle(r.x, r.y, r.width, r.height); if(r.x>rightSlicer){ result.x+=extra.width; } else{ if(r.x+r.width>leftSlicer) result.width+=extra.width; } if(r.y>bottomSlicer){ result.y+=extra.height; } else{ if(r.y+r.height>topSlicer) result.height+=extra.height; } return result; } @Override public void setProgressMax(int max){ super.setProgressMax(max); if(progressBar!=null) progressBar.setMaximum(max); } @Override public void setProgressValue(int value){ super.setProgressValue(value); if(progressBar!=null){ progressBar.setValue(value); if(!progressBar.isVisible() && (System.currentTimeMillis()-progressStartTime)>=DEFAULT_PROGRESS_WAKE_ON) progressBar.setVisible(true); } } @Override public void endProgress(){ super.endProgress(); if(progressBar!=null && hideProgressBar==true) progressBar.setVisible(false); } }