// $Id: HegemonScroll.java,v 1.9 1999/06/05 23:29:12 greear Exp $ // $Revision: 1.9 $ $Author: greear $ $Date: 1999/06/05 23:29:12 $ // //Hegemon Client Code: Java Client for ScryMUD Server Code //Copyright (C) 1998 Ben Greear // //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. // // To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred) // greearb@agcs.com // import java.util.*; import java.awt.*; import java.awt.image.*; import java.text.*; import java.awt.event.*; /** Stores a certain amount of data (text). It also contains the logic needed to return vectors containing certain portions of the scroll. */ class HegemonScroll extends Panel { HegemonManager hm = null; ScrollComponentCollection components; HegemonDisplayProperties props; ScrollComponentText comp_in_progress; ScrollComponent last_added_component; HegemonScrollCanvas canvas; int vert_spacing; HegemonDisplay parent; int left_x; int top_y; boolean auto_scroll; Vector non_scrollables; /* vector of objects which are not intended to scroll with the rest of the text. */ ScrollComponentGraph hp; ScrollComponentGraph mana; ScrollComponentGraph mov; public HegemonScroll(HegemonManager h, HegemonDisplay par) { super(); hm = h; parent = par; components = new ScrollComponentQueue(1000); vert_spacing = 1; setBackground(new Color(250, 250, 250)); canvas = new HegemonScrollCanvas(parent); setLayout(new BorderLayout()); this.add(canvas, "Center"); props = new HegemonDisplayProperties(hm, canvas.getGraphics()); comp_in_progress = new ScrollComponentText(vert_spacing, props); hp = new ScrollComponentGraph(5, canvas.getSize().height - 5, 8, 55, 4, new Color(50, 0, 0), ScrollComponentGraph.O_EAST); mana = new ScrollComponentGraph(65, canvas.getSize().height - 5, 8, 55, 4, new Color(0, 0, 50), ScrollComponentGraph.O_EAST); mov = new ScrollComponentGraph(125, canvas.getSize().height - 5, 8, 55, 4, new Color(0, 50, 0), ScrollComponentGraph.O_EAST); non_scrollables = new Vector(); non_scrollables.addElement(hp); non_scrollables.addElement(mana); non_scrollables.addElement(mov); }//constructor public void notifyScrollCanvasResized() { Dimension d = canvas.getSize(); hp.setDefaultCoords(5, d.height - 10); mana.setDefaultCoords(65, d.height - 10); mov.setDefaultCoords(125, d.height - 10); } public void setPrompt(int h, int hm, int m, int mm, int v, int vm) { int cc; /* color component */ Color c; hp.setEnabled(true); mana.setEnabled(true); mov.setEnabled(true); hp.setPercent((float)h / (float)hm); cc = Math.max(200, 255 - Math.max(0, (hm / 8))); c = hp.getColor(); if (c.getRed() != cc) { hp.setColor(new Color(cc, calcOtherColor(cc), calcOtherColor(cc))); } mana.setPercent((float)m / (float)mm); cc = Math.max(200, 255 - Math.max(0, (mm / 8))); c = mana.getColor(); if (c.getBlue() != cc) { mana.setColor(new Color(calcOtherColor(cc), cc, calcOtherColor(cc))); } mov.setPercent((float)v / (float)vm); cc = Math.max(200, 255 - Math.max(0, (vm / 8))); c = mov.getColor(); if (c.getGreen() != cc) { mov.setColor(new Color(calcOtherColor(cc), calcOtherColor(cc), cc)); } }//setPrompt /** The other color component should always be less than the primary * color. Also, as the primary reaches its strongest (200), * the other colors should drop to zero. The goal is to go from * light shades for weaker players to deep, strong colors for more * powerful players. However, the general hue: Red==HP, Blue=MANA, * Green==MOVE, should remain the same. p should range from 255 * at the weakest, to 200 at the strongest. */ protected int calcOtherColor(int p) { return (p - 200) * 2; //Yeesh, is it that simple!! } public void clear() { props.reset(); components.clear(); canvas.clear(); vert_spacing = 1; comp_in_progress = new ScrollComponentText(vert_spacing, props); }//clear public HegemonDisplay getPar() { return parent; } public void setScrollComponentCollection(ScrollComponentCollection scc) { components = scc; } public int getScrollHeight() { return components.getTotalHeight(); } public final void setPaintAttributes(int x, int y) { left_x = x; top_y = y; canvas.setXOffset(left_x); } public void paint(boolean a_scroll) { Vector comps; auto_scroll = a_scroll; //Log.it("HegemonScroll.paint(" + auto_scroll + "), top_y: " // + top_y + " height: " + canvas.getSize().height); if (auto_scroll) { comps = components.getBottomPage(canvas.getSize().height - 25); } else { comps = components.getVector(top_y, top_y + canvas.getSize().height - 25); } //Log.it("In HegemonScroll.paint(), component's size: " // + comps.size()); canvas.setComponents(comps, non_scrollables); canvas.paint(); }//paint public void paint(Graphics g) { Log.instance().trc("In HegemonScroll.paint(Graphics g)"); if ((g != null) && (props.getGraphics() == null)) { Log.instance().dbg("Setting graphics in the Properties."); props.setGraphics(g); } Vector comps; // We can't send auto_scroll in here, but lets hope our cached value is // good enough.... if (auto_scroll) { comps = components.getBottomPage(canvas.getSize().height - 15); } else { comps = components.getVector(top_y, top_y + canvas.getSize().height - 15); } canvas.setComponents(comps, non_scrollables); super.paint(g); }//paint final public HegemonDisplayProperties getProperties() { return props; } private final void addComponent(ScrollComponent sc) { if (sc == last_added_component) { //Log.it("\n\n RETURNING FROM addComponent().\n\n"); return; //no need to add it again } else { last_added_component = sc; } //Log.it("\naddComponent: " + sc + "\n"); try { components.push(sc); } catch (Exception e) { Log.instance().err("addComponent: Trying to push: " + e); } }//addComponent /** appends text, using the current context, to the end of the scroll. */ public synchronized void append(String str) { //Log.it("In HegemonScroll.append(), str -: " + str + ":-"); if (str == null) return; else { drawString(str); //parent.paintScroll(); } }//append(String) private synchronized void drawString(String txt) { //Log.it("HegemonScroll.drawString: comp_in_progress: " // + comp_in_progress + "\nTEXT -:" + txt + ":-"); /* Assume text can and will be auto-wrapped. All whitespace will be translated to spaces which will be consolidated as per HTML. */ //this just screws things up in ScryMUD. Perhaps in some other //application it would be more useful... if (false) { //!props.isModePRE()) { int len = txt.length(); char sb[] = new char[len + 2]; int sb_len; char ch; boolean last_was_ws = false; int j = 0; for (int i = 0; i<len; i++) { ch = txt.charAt(i); if (Character.isWhitespace(ch)) { if (last_was_ws) { continue; //don't append it } else { last_was_ws = true; } }//if was ws else { last_was_ws = false; } sb[j] = ch; j++; }//for (consolidate white space) sb_len = j; /* when here: sb contains the string we want to deal with. */ /* now lets paint the string, wrapping as needed. */ int width = this.getSize().width; FontMetrics fm = props.getFontMetrics(); int max_adv = fm.getMaxAdvance(); int str_width; int space_avail; int offset = 0; int num_chars; BreakIterator line_breaker = BreakIterator.getLineInstance(); line_breaker.setText(new String(sb)); int brk1 = 0; int brk2 = 0; int our_break = 0; while (true) { //lets do the entire array... //Log.it("In while: sb: -:" + sb + ":- offset: -:" + offset + // ":- sb.length: -:" + sb_len); str_width = fm.charsWidth(sb, offset, sb_len - (offset + 1)); space_avail = width - comp_in_progress.getWidth(); if (str_width > space_avail) { /* gotta wrap the sucker */ /* num chars we can paint... */ num_chars = (int)(space_avail/max_adv); brk1 = line_breaker.following(offset + num_chars); brk2 = line_breaker.previous(); /* this is the one we want */ if (brk2 > offset) { our_break = brk2; } else { our_break = brk1; } comp_in_progress.addChars(sb, offset, (our_break - offset), props); offset = our_break + 1; addComponent(comp_in_progress); comp_in_progress = new ScrollComponentText(vert_spacing, props); }//if had to wrap else { comp_in_progress.addChars(sb, offset, (our_break - offset), props); break; } if (offset >= (sb.length - 1)) { /* subtract one b/c starts at 0 */ break; /* done */ } }//while true }//if not in MODE_PRE else { //IN MODE PRE (we'll do line wrapping at least now) int len = txt.length(); StringBuffer sb = new StringBuffer(100); char ch; int comp_len_sofar = 0; if (comp_in_progress != null) { comp_len_sofar = comp_in_progress.getWidth(); } FontMetrics fm = props.getFontMetrics(); Font font = props.getFont(); int sz = font.getSize(); int mx_size = parent.getSize().width - 40; //-20 is for scroll bar int last_ws_idx = 0; // Sanity checks for problems with closed frames and so on. if (mx_size < 200) { mx_size = 200; } for (int i = 0; i<len; i++) { ch = txt.charAt(i); if (Character.isWhitespace(ch)) { last_ws_idx = i; } if (fm == null) { /* gotta guestimate it then */ comp_len_sofar += (sz >> 1); }//if else { comp_len_sofar += fm.charWidth(ch); } if (ch == '\t') { //if a tab sb.append(" "); } else if (ch == '\r') { //carriage return continue; } else if (comp_len_sofar > mx_size) { int my_len = sb.length(); Log.instance().dbg("Comp_len_sofar: " + comp_len_sofar + " > mx_size: " + mx_size + " sb -:" + sb + "last_ws_idx: " + last_ws_idx + " sb.length(): " + sb.length()); if (last_ws_idx > 0) { my_len = sb.length() - (i - last_ws_idx); i = last_ws_idx; } Log.instance().dbg("i: " + i + " my_len: " + my_len); char[] buf = new char[my_len + 1]; sb.getChars(0, my_len, buf, 0); comp_in_progress.addChars(buf, 0, my_len, props); addComponent(comp_in_progress); comp_in_progress = new ScrollComponentText(vert_spacing, props); last_ws_idx = 0; sb = new StringBuffer(100); comp_len_sofar = 0; } else if (ch == '\n') { //newline //Log.it("Found a newline...\n"); int my_len = sb.length(); if (my_len > 0) { //Log.it("\tLength > 0"); char[] buf = new char[my_len + 1]; sb.getChars(0, my_len, buf, 0); comp_in_progress.addChars(buf, 0, my_len, props); addComponent(comp_in_progress); comp_in_progress = new ScrollComponentText(vert_spacing, props); sb = new StringBuffer(100); }//if the buffer contains something... else { //Log.it("\tLength == 0."); if (comp_in_progress.getWidth() > 0) { addComponent(comp_in_progress); comp_in_progress = new ScrollComponentText(vert_spacing, props); }//if addComponent(new ScrollComponentNewline(12, vert_spacing)); } last_ws_idx = 0; comp_len_sofar = 0; } else { sb.append(ch); } }//for if ((len = sb.length()) > 0) { //Log.it("\tWas some left over..."); comp_in_progress.addString(sb.toString(), props); if (comp_in_progress != last_added_component) { addComponent(comp_in_progress); }//if }//if we have some left over... }//else, IN MODE_PRE }//drawString public synchronized void pushColor(String color_name) { try { Color c = ColorUtils.getColor(color_name); props.pushColor(c); } catch (ColorNameException e) { Log.instance().err(e.toString()); } }//pushColor(String) public synchronized void pushColor(Color c) { props.pushColor(c); }//pushColor(Color) public synchronized void pushFont(Font f) { if (f != null) { props.pushFont(f); }//if }//setFont public synchronized void popColor() { props.popColor(); } public synchronized void popFont() { props.popFont(); } public void drawNewline() { addComponent(new ScrollComponentNewline(vert_spacing * 4, props.figurePointSize((props.getTextSize()).intValue()))); } }//HegemonScroll