/* * Here comes the text of your license * Each line should be prefixed with * */ package nars.gui.output; import automenta.vivisect.Video; import automenta.vivisect.swing.NPanel; import automenta.vivisect.swing.PCanvas; import java.awt.BorderLayout; import static java.awt.BorderLayout.CENTER; import static java.awt.BorderLayout.EAST; import static java.awt.BorderLayout.NORTH; import static java.awt.BorderLayout.SOUTH; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.GridBagLayout; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import static java.util.Collections.unmodifiableList; import java.util.LinkedHashMap; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; import nars.util.EventEmitter.EventObserver; import nars.util.Events; import nars.util.Events.FrameEnd; import nars.NAR; import nars.entity.Concept; import nars.entity.Sentence; import nars.entity.Task; import nars.entity.TaskLink; import nars.entity.TermLink; import nars.gui.WrapLayout; import nars.gui.output.graph.TermSyntaxVis; import nars.inference.TruthFunctions; /** * Views one or more Concepts */ public class ConceptsPanel extends NPanel implements EventObserver, Runnable { private final NAR nar; private final LinkedHashMap<Concept, ConceptPanel> concept; public ConceptsPanel(NAR n, Concept... c) { super(); this.nar = n; this.concept = new LinkedHashMap(); if (c.length == 1) { ConceptPanel v = new ConceptPanel(c[0], nar.time()); setLayout(new BorderLayout()); add(v, CENTER); concept.put(c[0], v); } else { VerticalPanel v = new VerticalPanel() { @Override protected void onShowing(boolean showing) { ConceptsPanel.this.onShowing(showing); } }; add(v, CENTER); int i = 0; for (Concept x : c) { if (x==null) continue; ConceptPanel p = new ConceptPanel(x, nar.time()); v.addPanel(i++, p); concept.put(x, p); } } updateUI(); } @Override protected void onShowing(boolean showing) { nar.memory.event.set(this, showing, Events.FrameEnd.class, Events.ConceptBeliefAdd.class, Events.ConceptBeliefRemove.class, Events.ConceptQuestionAdd.class, Events.ConceptQuestionRemove.class, Events.ConceptGoalAdd.class, Events.ConceptGoalRemove.class); } @Override public void event(Class event, Object[] args) { if (event == FrameEnd.class) { //SwingUtilities.invokeLater(this); run(); } /* if (!(args.length > 0) && (args[0] instanceof Concept)) { return; } Concept c = (Concept) args[0]; ConceptPanel cp = concept.get(c); if (cp != null) { SwingUtilities.invokeLater(this); }*/ } @Override public void run() { //TODO only update the necessary concepts for (ConceptPanel cp : concept.values()) cp.update(nar.time()); } public static class ConceptPanel extends JPanel { private final Concept concept; private final TruthChart beliefChart; private final TruthChart desireChart; private final PriorityColumn questionChart; private final JTextArea title; private final JTextArea subtitle; final int chartWidth = 64; final int chartHeight = 64; final float titleSize = 16f; final float subfontSize = 16f; private BeliefTimeline beliefTime; private BeliefTimeline desireTime; // private final PCanvas syntaxPanel; long time = 0; public ConceptPanel(Concept c, long time) { this(c); this.time = time; update(time); } String filter = ""; public ConceptPanel(Concept c) { super(new BorderLayout()); this.concept = c; this.setPreferredSize(new Dimension(600,600)); JPanel overlay = new JPanel(new BorderLayout()); JPanel details = new JPanel(new WrapLayout(FlowLayout.LEFT)); details.setOpaque(false); details.add(new JLabel("Beliefs")); details.add(this.beliefChart = new TruthChart(chartWidth, chartHeight)); details.add(new JLabel("Questions")); details.add(this.questionChart = new PriorityColumn((int)Math.ceil(Math.sqrt(chartWidth)), chartHeight)); details.add(new JLabel("Desires")); details.add(this.desireChart = new TruthChart(chartWidth, chartHeight)); //details.add(this.questChart = new PriorityColumn((int)Math.ceil(Math.sqrt(chartWidth)), chartHeight))); JPanel titlePanel = new JPanel(new BorderLayout()); titlePanel.setOpaque(false); titlePanel.add(this.title = new JTextArea(concept.term.toString()), CENTER); JTextField jfilter = new JTextField(""); jfilter.setPreferredSize(new Dimension(255,20)); details.add(jfilter,SOUTH); jfilter.setBackground(Color.DARK_GRAY); jfilter.setForeground(Color.WHITE); ConceptPanel THIS = this; jfilter.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent ke) { } @Override public void keyPressed(KeyEvent ke) { } @Override public void keyReleased(KeyEvent ke) { THIS.update(time); THIS.filter = jfilter.getText(); } }); title.setEditable(false); title.setOpaque(false); subtitle = new JTextArea(""); subtitle.setEditable(false); titlePanel.add(subtitle, SOUTH); details.add(titlePanel); title.setFont(Video.monofont.deriveFont(titleSize )); overlay.add(details, CENTER); JPanel timepanels = new JPanel(); timepanels.setLayout(new BoxLayout(timepanels,BoxLayout.PAGE_AXIS)); timepanels.setOpaque(false); timepanels.setPreferredSize(new Dimension(250,100)); timepanels.add(new JLabel("belief-events:")); timepanels.add(this.beliefTime = new BeliefTimeline(chartWidth*6, chartHeight/3)); timepanels.add(new JLabel("desire-events:")); timepanels.add(this.desireTime = new BeliefTimeline(chartWidth*6, chartHeight/3)); overlay.add(timepanels, SOUTH); /* TermSyntaxVis tt = new TermSyntaxVis(c.term); syntaxPanel = new PCanvas(tt); syntaxPanel.setZoom(10f); syntaxPanel.noLoop(); syntaxPanel.redraw(); add(syntaxPanel);*/ add(overlay, NORTH); //setComponentZOrder(overlay, 1); //syntaxPanel.setBounds(0,0,400,400); } public void update(long time) { StringBuilder conceptstr = new StringBuilder(); //concept.toStringLong().replaceAll("\n", "<br/>"); /*if(concept.beliefs.size()>0) { conceptstr.append("\nBeliefs:\n"); for(Task tl : concept.beliefs) { conceptstr.append(tl.sentence.toString()); conceptstr.append("\n"); } } if(concept.desires.size()>0) { conceptstr.append("\nDesires:\n"); for(Task tl : concept.desires) { conceptstr.append(tl.sentence.toString()); conceptstr.append("\n"); } } if(concept.questions.size()>0) { conceptstr.append("\nQuestions:\n"); for(Task tl : concept.questions) { conceptstr.append(tl.sentence.toString()); conceptstr.append("\n"); } } if(concept.quests.size()>0) { conceptstr.append("\nQuests:\n"); for(Task tl : concept.quests) { conceptstr.append(tl.sentence.toString()); conceptstr.append("\n"); } }*/ if(concept.taskLinks.size()>0) { conceptstr.append("TaskLinks:\n"); for(TaskLink tl : concept.taskLinks) { String s = tl.targetTask.sentence.toString()+ " priority:" + tl.getBudget().getPriority(); if(s.contains(filter)) { conceptstr.append(s); conceptstr.append("\n"); } } } /*if(concept.termLinks.size()>0) { conceptstr.append("\nTermLinks:\n"); for(TermLink tl : concept.termLinks) { conceptstr.append(tl.getTerm().toString()); conceptstr.append("\n"); } }*/ this.time = time; String sub = ""; if (!concept.beliefs.isEmpty()) { List<Task> bbT = concept.getBeliefs(); List<Sentence> bb=new ArrayList<Sentence>(); for(Task ts : bbT) { bb.add(ts.sentence); } beliefChart.update(time, bb); sub+="truth: " + bb.get(0).truth.toString(); beliefTime.setVisible( beliefTime.update(time, bb)); } else { subtitle.setText(""); if (!concept.questions.isEmpty()) subtitle.setText("?(question)"); beliefTime.setVisible(false); } if (!concept.questions.isEmpty()) questionChart.update( unmodifiableList( concept.questions ) ); if (!concept.desires.isEmpty()) { List<Task> ddT = concept.getDesires(); List<Sentence> dd=new ArrayList<Sentence>(); for(Task ts : ddT) { dd.add(ts.sentence); } String s=sub; sub = (s.equals("") ? "" : s+" ")+" desire: "+concept.desires.get(0).sentence.truth.toString(); ArrayList<Sentence> desir=new ArrayList(); for(Task ts: concept.desires) { desir.add(ts.sentence); } desireChart.update( time, unmodifiableList( desir )); desireTime.setVisible( desireTime.update(time, dd)); } else { desireTime.setVisible(false); } String finalstr = sub+"\n\n"+conceptstr.toString(); subtitle.setText(finalstr); updateUI(); } } public static class ImagePanel extends JPanel { public BufferedImage image; final int w, h; public ImagePanel(int width, int height) { super(); this.w = width; this.h = height; setSize(width, height); setMinimumSize(new Dimension(width, height)); setPreferredSize(new Dimension(width, height)); } public Graphics g() { if (image == null) { image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); } if (image != null) { return image.createGraphics(); } return null; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image, 0, 0, null); } } public static class PriorityColumn extends ImagePanel { public PriorityColumn(int width, int height) { super(width, height); update(Collections.EMPTY_LIST); } public void update(Iterable<Task> i) { Graphics g = g(); if (g == null) return; g.setColor(new Color(0.1f, 0.1f, 0.1f)); g.fillRect(0, 0, getWidth(), getHeight()); for (Task s : i) { float pri = s.getBudget().getPriority(); float dur = s.getBudget().getDurability(); float ii = 0.1f + pri * 0.9f; g.setColor(new Color(ii, ii, ii, 0.5f + 0.5f * dur)); int h = 8; int y = (int)((1f - pri) * (getHeight() - h)); g.fillRect(0, y-h/2, getWidth(), h); } g.dispose(); } } /** normalized to entire history of non-eternal beliefs; * displayed horizontally */ public static class BeliefTimeline extends ImagePanel { float minTime, maxTime; private float timeFactor; public BeliefTimeline(int width, int height) { super(width, height); } public int getX(long when) { return (int)Math.round((when - minTime) / timeFactor); } public boolean update(long time, Collection<Sentence> i) { minTime = maxTime = time; for (Sentence s : i) { if (s.isEternal()) continue; long when = s.getOccurenceTime(); if (minTime > when) minTime = when; if (maxTime < when) maxTime = when; } if (minTime == maxTime) { //no time-distinct beliefs return false; } Graphics g = g(); if (g == null) return false; int thick = 4; timeFactor = ((float)maxTime - minTime) / ((float)w-thick); g.setColor(new Color(0.1f, 0.1f, 0.1f)); g.fillRect(0, 0, getWidth(), getHeight()); for (Sentence s : i) { if (s.isEternal()) continue; long when = s.getOccurenceTime(); int x = getX(when); float freq = s.getTruth().getFrequency(); float conf = s.getTruth().getConfidence(); int y = (int)((1.0f - freq) * (this.h - thick)); g.setColor(getColor(freq, conf, 1.0f)); g.fillRect(x, y, thick, thick); } // "now" axis g.setColor(Color.WHITE); g.fillRect(getX(time), 0, 1, getHeight()); g.dispose(); return true; } } public static Color getColor(float freq, float conf, float factor) { float ii = 0.25f + (factor * conf) * 0.75f; // float green = freq > 0.5f ? (freq/2f) : 0f; //float red = freq <= 0.5f ? ((1.0f-freq)/2f) : 0; float evidence = TruthFunctions.c2w(conf); float positive_evidence_in_0_1 = TruthFunctions.w2c(evidence*freq); float negative_evidence_in_0_1 = TruthFunctions.w2c(evidence*(1.0f-freq)); return new Color(positive_evidence_in_0_1,0.0f, negative_evidence_in_0_1, ii); } public static class TruthChart extends ImagePanel { public TruthChart(int width, int height) { super(width, height); } public void update(long now, Iterable<Sentence> i) { Graphics g = g(); if (g == null) return; g.setColor(new Color(0.1f, 0.1f, 0.1f)); g.fillRect(0, 0, (int) getWidth(), (int) getHeight()); for (Sentence s : i) { float freq = s.getTruth().getFrequency(); float conf = s.getTruth().getConfidence(); float factor = 1.0f; if (s instanceof Sentence) { Sentence ss = (Sentence)s; if (!ss.isEternal()) { //float factor = TruthFunctions.temporalProjection(now, ss.getOccurenceTime(), now); factor = 1.0f / (1f + Math.abs(ss.getOccurenceTime() - now) ); } } g.setColor(getColor(freq, conf, factor)); int w = 8; int h = 8; float dw = getWidth() - w; float dh = getHeight() - h; g.fillRect((int) (freq * dw), (int) ((1.0 - conf) * dh), w, h); } g.dispose(); } } }