/*
Copyright (C) Paul Falstad and Iain Sharp
This file is part of CircuitJS1.
CircuitJS1 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.
CircuitJS1 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 CircuitJS1. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lushprojects.circuitjs1.client;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
//import java.awt.*;
//import java.awt.event.*;
//import java.text.NumberFormat;
//import java.text.DecimalFormat;
interface Editable {
EditInfo getEditInfo(int n);
void setEditValue(int n, EditInfo ei);
}
// class EditDialog extends Dialog implements AdjustmentListener, ActionListener, ItemListener {
class EditDialog extends DialogBox {
Editable elm;
CirSim cframe;
Button applyButton, okButton, cancelButton;
EditInfo einfos[];
int einfocount;
final int barmax = 1000;
VerticalPanel vp;
HorizontalPanel hp;
NumberFormat noCommaFormat;
EditDialog(Editable ce, CirSim f) {
// super(f, "Edit Component", false);
super(); // Do we need this?
setText(CirSim.LS("Edit Component"));
cframe = f;
elm = ce;
// setLayout(new EditDialogLayout());
vp=new VerticalPanel();
setWidget(vp);
einfos = new EditInfo[10];
noCommaFormat=NumberFormat.getFormat("####.##########");
// noCommaFormat = DecimalFormat.getInstance();
// noCommaFormat.setMaximumFractionDigits(10);
// noCommaFormat.setGroupingUsed(false);
hp=new HorizontalPanel();
hp.setWidth("100%");
hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
hp.setStyleName("topSpace");
vp.add(hp);
hp.add(applyButton = new Button(CirSim.LS("Apply")));
applyButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
apply();
}
});
hp.add(okButton = new Button(CirSim.LS("OK")));
okButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
apply();
closeDialog();
}
});
hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
hp.add(cancelButton = new Button(CirSim.LS("Cancel")));
cancelButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
closeDialog();
}
});
buildDialog();
this.center();
}
void buildDialog() {
int i;
int idx;
for (i = 0; ; i++) {
Label l = null;
einfos[i] = elm.getEditInfo(i);
if (einfos[i] == null)
break;
EditInfo ei = einfos[i];
idx = vp.getWidgetIndex(hp);
String name = CirSim.LS(ei.name);
if (ei.name.startsWith("<"))
vp.insert(l = new HTML(name),idx);
else
vp.insert(l = new Label(name),idx);
if (i!=0 && l != null)
l.setStyleName("topSpace");
idx = vp.getWidgetIndex(hp);
if (ei.choice != null) {
vp.insert(ei.choice,idx);
ei.choice.addChangeHandler( new ChangeHandler() {
public void onChange(ChangeEvent e){
itemStateChanged(e);
}
});
} else if (ei.checkbox != null) {
vp.insert(ei.checkbox,idx);
ei.checkbox.addValueChangeHandler( new ValueChangeHandler<Boolean>() {
public void onValueChange(ValueChangeEvent<Boolean> e){
itemStateChanged(e);
}
});
} else if (ei.button != null) {
vp.insert(ei.button, idx);
ei.button.addClickHandler( new ClickHandler() {
public void onClick(ClickEvent event) {
itemStateChanged(event);
}
});
} else if (ei.textArea != null) {
vp.insert(ei.textArea, idx);
} else if (ei.anchor != null) {
vp.insert(ei.anchor, idx);
} else {
vp.insert(ei.textf = new TextBox(), idx);
if (ei.text != null)
ei.textf.setText(ei.text);
if (ei.text == null) {
ei.textf.setText(unitString(ei));
}
}
}
einfocount = i;
}
static final double ROOT2 = 1.41421356237309504880;
double diffFromInteger(double x) {
return Math.abs(x-Math.round(x));
}
String unitString(EditInfo ei) {
// for voltage elements, express values in rms if that would be shorter
if (elm != null && elm instanceof VoltageElm &&
Math.abs(ei.value) > 1e-4 &&
diffFromInteger(ei.value*1e4) > diffFromInteger(ei.value*1e4/ROOT2))
return unitString(ei, ei.value/ROOT2) + "rms";
return unitString(ei, ei.value);
}
String unitString(EditInfo ei, double v) {
double va = Math.abs(v);
if (ei.dimensionless)
return noCommaFormat.format(v);
if (v == 0) return "0";
if (va < 1e-9)
return noCommaFormat.format(v*1e12) + "p";
if (va < 1e-6)
return noCommaFormat.format(v*1e9) + "n";
if (va < 1e-3)
return noCommaFormat.format(v*1e6) + "u";
if (va < 1 && !ei.forceLargeM)
return noCommaFormat.format(v*1e3) + "m";
if (va < 1e3)
return noCommaFormat.format(v);
if (va < 1e6)
return noCommaFormat.format(v*1e-3) + "k";
if (va < 1e9)
return noCommaFormat.format(v*1e-6) + "M";
return noCommaFormat.format(v*1e-9) + "G";
}
double parseUnits(EditInfo ei) throws java.text.ParseException {
String s = ei.textf.getText();
s = s.trim();
double rmsMult = 1;
if (s.endsWith("rms")) {
s = s.substring(0, s.length()-3).trim();
rmsMult = ROOT2;
}
// rewrite shorthand (eg "2k2") in to normal format (eg 2.2k) using regex
s=s.replaceAll("([0-9]+)([pPnNuUmMkKgG])([0-9]+)", "$1.$3$2");
int len = s.length();
char uc = s.charAt(len-1);
double mult = 1;
switch (uc) {
case 'p': case 'P': mult = 1e-12; break;
case 'n': case 'N': mult = 1e-9; break;
case 'u': case 'U': mult = 1e-6; break;
// for ohm values, we assume mega for lowercase m, otherwise milli
case 'm': mult = (ei.forceLargeM) ? 1e6 : 1e-3; break;
case 'k': case 'K': mult = 1e3; break;
case 'M': mult = 1e6; break;
case 'G': case 'g': mult = 1e9; break;
}
if (mult != 1)
s = s.substring(0, len-1).trim();
return noCommaFormat.parse(s) * mult * rmsMult;
}
void apply() {
int i;
for (i = 0; i != einfocount; i++) {
EditInfo ei = einfos[i];
if (ei.textf!=null && ei.text==null) {
try {
double d = parseUnits(ei);
ei.value = d;
} catch (Exception ex) { /* ignored */ }
}
if (ei.button != null)
continue;
elm.setEditValue(i, ei);
}
cframe.needAnalyze();
}
public void itemStateChanged(GwtEvent e) {
Object src = e.getSource();
int i;
boolean changed = false;
for (i = 0; i != einfocount; i++) {
EditInfo ei = einfos[i];
if (ei.choice == src || ei.checkbox == src || ei.button == src) {
// if we're pressing a button, make sure to apply changes first
if (ei.button == src)
apply();
elm.setEditValue(i, ei);
if (ei.newDialog)
changed = true;
cframe.needAnalyze();
}
}
if (changed) {
clearDialog();
buildDialog();
}
}
public void clearDialog() {
while (vp.getWidget(0)!=hp)
vp.remove(0);
}
protected void closeDialog()
{
EditDialog.this.hide();
cframe.editDialog = null;
}
}