package haven; import haven.Resource.Image; import java.awt.Color; import java.awt.event.KeyEvent; import java.awt.font.TextAttribute; import java.awt.image.BufferedImage; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; public class ToolbarWnd extends Window implements DTarget, DropTarget { private static final Color pressedColor = new Color(196, 196, 196, 196); public final static Tex bg = Resource.loadtex("gfx/hud/invsq"); private static final int BELTS_NUM = 15; private static final BufferedImage ilockc = Resource.loadimg("gfx/hud/lockc"); private static final BufferedImage ilockch = Resource.loadimg("gfx/hud/lockch"); private static final BufferedImage ilocko = Resource.loadimg("gfx/hud/locko"); private static final BufferedImage ilockoh = Resource.loadimg("gfx/hud/lockoh"); @SuppressWarnings("unchecked") private static final Indir<Resource>[] defbelt = new Indir[10]; public final static Coord bgsz = bg.sz().add(-1, -1); private static final Properties beltsConfig = new Properties(); private Coord gsz, off, beltNumC; Slot pressed, dragging, layout[]; private IButton lockbtn, flipbtn, minus, plus; public boolean flipped = false, locked = false; public int belt, key; private Tex[] nums; private static Tex[] beltNums; public String name; public final static RichText.Foundry ttfnd = new RichText.Foundry(TextAttribute.FAMILY, "SansSerif", TextAttribute.SIZE, 10); static { /* Text rendering is slow, so pre-cache the belt numbers. */ beltNums = new Tex[BELTS_NUM]; for(int i = 0; i < BELTS_NUM; i++) { beltNums[i] = new TexI(Utils.outline2(Text.render(Integer.toString(i)).img, Color.BLACK, true)); } } public ToolbarWnd(Coord c, Widget parent, String name) { super( c, Coord.z, parent, null); this.name = name; init(1, 10, new Coord(5, 10), KeyEvent.VK_0); } public ToolbarWnd(Coord c, Widget parent, String name, int belt, int key, int sz, Coord off) { super( c, Coord.z, parent, null); this.name = name; init(belt, sz, off, key); } public ToolbarWnd(Coord c, Widget parent, String name, int belt, int key) { super( c, Coord.z, parent, null); this.name = name; init(belt, 10, new Coord(5, 10), key); } private void loadOpts() { synchronized (Config.window_props) { if(Config.window_props.getProperty(name+"_locked", "false").equals("true")) { locked = true; } if(Config.window_props.getProperty(name+"_flipped", "false").equals("true")) { flip(); } if(Config.window_props.getProperty(name+"_folded", "false").equals("true")) { folded = true; checkfold(); } visible = Config.window_props.getProperty(name, "true").equals("true"); c = new Coord(Config.window_props.getProperty(name+"_pos", c.toString())); } } private void init(int belt, int sz, Coord off, int key) { gsz = new Coord(1, sz); this.off = off; fbtn.show(); mrgn = new Coord(2,18); layout = new Slot[sz]; loadOpts(); cbtn.visible = false; lockbtn = new IButton(Coord.z, this, locked?ilockc:ilocko, locked?ilocko:ilockc, locked?ilockch:ilockoh) { public void click() { locked = !locked; if(locked) { up = ilockc; down = ilocko; hover = ilockch; } else { up = ilocko; down = ilockc; hover = ilockoh; } Config.setWindowOpt(name+"_locked", locked); } }; lockbtn.recthit = true; flipbtn = new IButton(Coord.z, this, Resource.loadimg("gfx/hud/flip"), Resource.loadimg("gfx/hud/flip"), Resource.loadimg("gfx/hud/flipo")) { public void click() { flip(); } }; minus = new IButton(Coord.z, this, Resource.loadimg("gfx/hud/charsh/minusup"), Resource.loadimg("gfx/hud/charsh/minusdown")) { public void click() { prevBelt(); } }; plus = new IButton(Coord.z, this, Resource.loadimg("gfx/hud/charsh/plusup"), Resource.loadimg("gfx/hud/charsh/plusdown")) { public void click() { nextBelt(); } }; flipbtn.recthit = true; loadBelt(belt); this.key = key; pack(); /* Text rendering is slow, so pre-cache the hotbar numbers. */ nums = new Tex[sz]; for(int i = 0; i < sz; i++) { String slot; if(key == KeyEvent.VK_0){ slot = Integer.toString(i); } else if(key == KeyEvent.VK_F1){ slot = "F"+Integer.toString(i+1); } else { slot = "N"+Integer.toString(i); } nums[i] = new TexI(Utils.outline2(Text.render(slot).img, Color.BLACK, true)); } } protected void nextBelt() { loadBelt(belt + 2); } protected void prevBelt() { loadBelt(belt - 2); } public static void loadBelts() { String configFileName = "belts_" + Config.currentCharName.replaceAll("[^a-zA-Z()]", "_") + ".conf"; try { synchronized (beltsConfig) { beltsConfig.load(new FileInputStream(configFileName)); } } catch (FileNotFoundException e) { } catch (IOException e) { } } protected void loadBelt(int beltNr) { belt = beltNr % BELTS_NUM; if(belt < 0) belt += BELTS_NUM; synchronized (beltsConfig) { for (int slot = 0; slot < layout.length; slot++) { String icon = beltsConfig.getProperty("belt_" + belt + "_" + slot, ""); if (icon.length() > 0) { layout[slot] = new Slot(icon, belt, slot); } else { layout[slot] = null; } } } } public static void saveBelts() { synchronized (beltsConfig) { String configFileName = "belts_" + Config.currentCharName.replaceAll("[^a-zA-Z()]", "_") + ".conf"; try { beltsConfig.store(new FileOutputStream(configFileName), "Belts actions for " + Config.currentCharName); } catch (FileNotFoundException e) { } catch (IOException e) { } } } public void wdgmsg(Widget sender, String msg, Object... args) { if(sender == cbtn) ui.destroy(this); Boolean _folded = folded; if(sender == fbtn) super.wdgmsg(sender, msg, args); if(_folded != folded) { Config.setWindowOpt(name+"_folded", folded); } } public void draw(GOut g) { super.draw(g); if(folded) return; for(int y = 0; y < gsz.y; y++) { for(int x = 0; x < gsz.x; x++) { Coord p = getcoord(x, y); g.image(bg, p); int slot = x+y; if(key == KeyEvent.VK_0) slot = (slot + 1) % 10; Slot s = layout[x+y]; Resource btn = (s==null)?null:s.getres(); if(btn != null) { Image img = btn.layer(Resource.imgc); if(img != null){ Tex btex = img.tex(); if(s == pressed) { g.chcolor(pressedColor); } if(Config.highlightSkills) g.chcolor(btn.getStateColor()); g.image(btex, p.add(1, 1)); } else { System.out.println(btn.name); } } g.aimage(nums[slot], p.add(bg.sz()), 1, 1); g.chcolor(); } } g.chcolor(); Resource res; if((dragging != null)&&((res = dragging.getres()) != null)) { final Tex dt = res.layer(Resource.imgc).tex(); ui.drawafter(new UI.AfterDraw() { public void draw(GOut g) { g.image(dt, ui.mc.add(dt.sz().div(2).inv())); } }); } g.aimage(beltNums[belt], beltNumC, 1, 1); } private Coord getcoord(int x, int y) { Coord p = xlate(bgsz.mul(new Coord(x, y)),true); if (off.x > 0) if (flipped) { p.x += off.y*(x/off.x); } else { p.y += off.y*(y/off.x); } return p; } public void checkfold() { super.checkfold(); Coord max = new Coord(ssz); if((folded)&&(flipped)) { max.x = 0; recalcsz(max); } placecbtn(); } protected void recalcsz(Coord max) { sz = max.add(wbox.bsz().add(mrgn.mul(2)).add(tlo).add(rbo)).add(-1, -1); wsz = sz.sub(tlo).sub(rbo); if(folded) if (flipped) wsz.x = wsz.x/2; else wsz.y = wsz.y/2; asz = wsz.sub(wbox.bl.sz()).sub(wbox.br.sz()).sub(mrgn.mul(2)); } public void flip() { flipped = !flipped; gsz = new Coord(gsz.y, gsz.x); mrgn = new Coord(mrgn.y, mrgn.x); pack(); Config.setWindowOpt(name+"_flipped", flipped); } protected void placecbtn() { cbtn.c = new Coord(wsz.x - 3 - Utils.imgsz(cbtni[0]).x, 3).sub(mrgn).sub(wbox.tloff()); if(flipped) { fbtn.c = new Coord(cbtn.c.x, wsz.y - 3 - Utils.imgsz(fbtni[0]).y - mrgn.y - wbox.tloff().y); if(lockbtn != null) lockbtn.c = new Coord(3 - wbox.tloff().x - mrgn.x, cbtn.c.y ); if(flipbtn != null) flipbtn.c = new Coord(5 - wbox.tloff().x - mrgn.x, fbtn.c.y); if(plus != null) plus.c = cbtn.c.sub(16,0); if(minus != null) { minus.c = fbtn.c.sub(16,0); beltNumC = minus.c.add(plus.c).div(2).add(36, 22); } } else { fbtn.c = new Coord(3 - wbox.tloff().x, cbtn.c.y); if(lockbtn != null) lockbtn.c = new Coord(fbtn.c.x, wsz.y - 21 - mrgn.y - wbox.tloff().y ); if(flipbtn != null) flipbtn.c = new Coord(cbtn.c.x - 2, wsz.y - 21 - mrgn.y - wbox.tloff().y); if(plus != null) plus.c = flipbtn.c.sub(0, 16); if(minus != null) { minus.c = lockbtn.c.sub(0, 16); beltNumC = minus.c.add(plus.c).div(2).add(20, 38); } } } public void pack() { ssz = bgsz.mul(gsz); if (off.x > 0) if (flipped) { ssz.x += off.y*((gsz.x/off.x) - ((gsz.x%off.x == 0)?1:0)) + 16; } else { ssz.y += off.y*((gsz.y/off.x) - ((gsz.y%off.x == 0)?1:0)) + 16; } checkfold(); placecbtn(); } private Slot bhit(Coord c) { int i = index(c); if (i >= 0) return (layout[i]); else return (null); } private int index(Coord c) { for(int y = 0; y < gsz.y; y++) { for(int x = 0; x < gsz.x; x++) { if (c.isect(getcoord(x, y), bgsz)) return x+y; } } return -1; } public boolean mousedown(Coord c, int button) { Slot h = bhit(c); if (button == 1) { if (h != null) { pressed = h; ui.grabmouse(this); } else { super.mousedown(c, button); } } else if((button == 3)&&(!locked)){ clearslot(index(c)); } return (true); } public boolean mouseup(Coord c, int button) { Slot h = bhit(c); if (button == 1) { if(dragging != null) { ui.dropthing(ui.root, ui.mc, dragging.getres()); dragging = pressed = null; } else if (pressed != null) { if (pressed == h) h.use(); pressed = null; } ui.grabmouse(null); } if(dm) { Config.setWindowOpt(name+"_pos", this.c.toString()); } super.mouseup(c, button); return (true); } public void clearslot(int slot){ if((slot<0)||(slot>=layout.length)){return;} Slot s = layout[slot]; layout[slot] = null; setBeltSlot(slot, ""); if((s != null) && (s.isitem)){ ui.slen.wdgmsg("belt", s.slot, 3, ui.modflags()); } } public void mousemove(Coord c) { if ((!locked)&&(dragging == null) && (pressed != null)) { dragging = pressed; int slot = index(c); if(slot >= 0){ clearslot(slot); } pressed = null; } else { super.mousemove(c); } } public boolean drop(Coord cc, Coord ul) { if(!locked){ int s = getbeltslot(); if(s<0){ String msg = "No empty item slots!"; ui.cons.out.println(msg); ui.slen.error(msg); } else { int slot = index(cc); if(slot >= 0){ String val = "@"+s; layout[slot] = new Slot(val, belt, slot); ui.slen.wdgmsg("setbelt", s, 0); setbeltslot(belt, slot, val); } } } return(true); } public boolean iteminteract(Coord cc, Coord ul) { return(false); } public boolean dropthing(Coord c, Object thing) { if ((!locked)&&(thing instanceof Resource)) { int slot = index(c); if(slot < 0){return false;} Resource res = (Resource)thing; setBeltSlot(slot, res.name); layout[slot] = new Slot(res.name, belt, slot ); return true; } return false; } private void setBeltSlot(int slot, String icon) { setbeltslot(belt, slot, icon); } private Resource curttr = null; private boolean curttl = false; private Text curtt = null; private long hoverstart; public Object tooltip(Coord c, boolean again) { Slot slot = bhit(c); Resource res = (slot==null)?null:slot.getres(); long now = System.currentTimeMillis(); if((res != null) && ((res.layer(Resource.action) != null)||(res.layer(Resource.tooltip) != null))) { if(!again) hoverstart = now; boolean ttl = (now - hoverstart) > 500; if((res != curttr) || (ttl != curttl)) { curtt = rendertt(res, ttl); curttr = res; curttl = ttl; } return(curtt); } else { hoverstart = now; return(""); } } private static Text rendertt(Resource res, boolean withpg) { Resource.AButton ad = res.layer(Resource.action); Resource.Pagina pg = res.layer(Resource.pagina); String tt; if(ad != null){ tt = ad.name; } else { tt = res.layer(Resource.tooltip).t; } if(withpg && (pg != null)) { tt += "\n\n" + pg.text; } return(ttfnd.render(tt, 0)); } private boolean checkKey(char ch, KeyEvent ev) { if(!visible){return false;} int code = ev.getKeyCode(); int slot = code - key; boolean alt = ev.isAltDown(); boolean ctrl = ev.isControlDown(); if(alt && key == KeyEvent.VK_F1){ slot = code - KeyEvent.VK_0; if((slot>0)&&(slot<=5)){ loadBelt(slot*2); return true; } } else if (ctrl && key == KeyEvent.VK_0) { slot = code - KeyEvent.VK_0; if((slot>0)&&(slot<=5)){ slot = ((slot-1)<<1) + 1; loadBelt(slot); return true; } } else if(!alt && !ctrl && (slot >= 0)&&(slot < gsz.x*gsz.y)) { if(key == KeyEvent.VK_0) slot = (slot == 0)?9:slot-1; Slot h = layout[slot]; if(h!=null) h.use(); return true; } return false; } public boolean globtype(char ch, KeyEvent ev) { if(!checkKey(ch, ev)) return(super.globtype(ch, ev)); else return true; } public boolean type(char key, KeyEvent ev) { if(key == 27) { wdgmsg(fbtn, "click"); return(true); } if(!checkKey(key, ev)) return(super.type(key, ev)); else return true; } public void removedef(int slot){ for(int i=0; i<layout.length; i++){ Slot s = layout[i]; if((s != null) && s.isitem && (s.slot == slot)){ clearslot(i); } } } public static void setbelt(int slot, Indir<Resource> res){ synchronized (defbelt) { defbelt[slot] = res; } if(res == null){ MenuGrid mnu = UI.instance.mnu; mnu.digitbar.removedef(slot); mnu.functionbar.removedef(slot); mnu.numpadbar.removedef(slot); } } public static Indir<Resource>getbelt(int slot){ Indir<Resource> res; synchronized (defbelt) { res = defbelt[slot]; } return res; } public static int getbeltslot(){ synchronized (defbelt) { for(int i = 0; i<defbelt.length; i++){ if(defbelt[i] == null){ return i; } } } return -1; } private static void setbeltslot(int belt, int slot, String value){ synchronized (beltsConfig) { beltsConfig.setProperty("belt_"+belt+"_"+slot, value); } saveBelts(); } private static class Slot { public boolean isitem; public String action; public int slot; private Resource res; private int belt, ind; public Slot(String str, int belt, int ind){ this.ind = ind; this.belt = belt; if(str.charAt(0) == '@'){ isitem = true; slot = Integer.decode(str.substring(1)); } else { isitem = false; action = str; res = Resource.load(action); } } public Resource getres(){ if((res == null) && (isitem)) { Indir<Resource> indir = getbelt(slot); if(indir == null){ res = null; } else { res = indir.get(); } } return res; } public void use(){ UI ui = UI.instance; if(isitem){ if(slot>=0){ ui.slen.wdgmsg("belt", slot, 1, ui.modflags()); } } else if(ui.mnu != null){ ui.mnu.use(res); } } } }