Package pump

Source Code of pump.ClassNameRenderer

package pump;

import javax.swing.*;
import javax.imageio.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.*;
import java.awt.Toolkit;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Optional;
import java.util.List;
import sodium.*;


class PumpFace extends Component {
    private Listener l = new Listener();
    private final BufferedImage background;
    private final BufferedImage[] smalls = new BufferedImage[8];
    private final BufferedImage[] larges = new BufferedImage[8];
    private final BufferedImage[] nozzleImgs = new BufferedImage[3];
    private final Behavior<List<Integer>> presetLCD;
    private final Behavior<List<Integer>> saleCostLCD;
    private final Behavior<List<Integer>> saleQuantityLCD;
    private final Behavior<List<Integer>> priceLCD1;
    private final Behavior<List<Integer>> priceLCD2;
    private final Behavior<List<Integer>> priceLCD3;
    @SuppressWarnings("unchecked")
    private final Behavior<UpDown> nozzles[] = new Behavior[3];
    @SuppressWarnings("unchecked")
    public final Behavior<Rectangle>[] nozzleRects = new Behavior[3];
    PumpFace(
        URL rootURL,
        EventSink<Point> eClick,
        Behavior<List<Integer>> presetLCD,
        Behavior<List<Integer>> saleCostLCD,
        Behavior<List<Integer>> saleQuantityLCD,
        Behavior<List<Integer>> priceLCD1,
        Behavior<List<Integer>> priceLCD2,
        Behavior<List<Integer>> priceLCD3,
        Behavior<UpDown> nozzle1,
        Behavior<UpDown> nozzle2,
        Behavior<UpDown> nozzle3
    ) throws IOException {
        addMouseListener(new MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent ev) {
                eClick.send(new Point(ev.getX(), ev.getY()));
            }
        });
        this.presetLCD = presetLCD;
        this.saleCostLCD = saleCostLCD;
        this.saleQuantityLCD = saleQuantityLCD;
        this.priceLCD1 = priceLCD1;
        this.priceLCD2 = priceLCD2;
        this.priceLCD3 = priceLCD3;
        this.nozzles[0] = nozzle1;
        this.nozzles[1] = nozzle2;
        this.nozzles[2] = nozzle3;
        l = l.append(presetLCD.updates().listen(text -> {
            this.repaintSegments(193, 140, larges, 5);
        })).append(saleCostLCD.updates().listen(text -> {
            this.repaintSegments(517, 30, larges, 5);
        })).append(saleQuantityLCD.updates().listen(text -> {
            this.repaintSegments(517, 120, larges, 5);
        })).append(priceLCD1.updates().listen(text -> {
            this.repaintSegments(355, 230, smalls, 4);
        })).append(priceLCD2.updates().listen(text -> {
            this.repaintSegments(485, 230, smalls, 4);
        })).append(priceLCD3.updates().listen(text -> {
            this.repaintSegments(615, 230, smalls, 4);
        })).append(nozzle1.updates().listen(ud -> {
            this.repaint(0);
        })).append(nozzle2.updates().listen(ud -> {
            this.repaint(0);
        })).append(nozzle3.updates().listen(ud -> {
            this.repaint(0);
        }));
        background = ImageIO.read(new URL(rootURL, "images/petrol-pump-front.png"));
        for (int i = 0; i < 8; i++) {
            smalls[i] = ImageIO.read(new URL(rootURL, "images/small"+i+".png"));
            larges[i] = ImageIO.read(new URL(rootURL, "images/large"+i+".png"));
        }
        for (int i = 0; i < 3; i++) {
            nozzleImgs[i] = ImageIO.read(new URL(rootURL, "images/nozzle"+(i+1)+".png"));
            final int x = 270 + i*130;
            final int width = nozzleImgs[i].getWidth(null);
            final int height = nozzleImgs[i].getHeight(null);
            nozzleRects[i] = nozzles[i].map(upDown ->
                new Rectangle(x, upDown == UpDown.UP ? 300 : 330, width, height)
            );
        }
    }
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(background.getWidth(null), background.getHeight(null));
    }
    @Override
    public void paint(Graphics g) {
        g.drawImage(background, 0, 0, null);
        Transaction.runVoid(() -> {
            drawSegments(g, 193, 140, presetLCD.sample(), larges, 5);
            drawSegments(g, 517, 30, saleCostLCD.sample(), larges, 5);
            drawSegments(g, 517, 120, saleQuantityLCD.sample(), larges, 5);
            drawSegments(g, 355, 230, priceLCD1.sample(), smalls, 4);
            drawSegments(g, 485, 230, priceLCD2.sample(), smalls, 4);
            drawSegments(g, 615, 230, priceLCD3.sample(), smalls, 4);
            for (int i = 0; i < 3; i++) {
                Rectangle r = nozzleRects[i].sample();
                g.drawImage(nozzleImgs[i], r.x, r.y, null);
            }
        })
        Toolkit.getDefaultToolkit().sync();
    }
    @Override
    public void update(Graphics g) {
        paint(g)// Don't clear the background, since we are painting the whole lot
    }

    private static Rectangle lcdBounds(int ox, int oy, BufferedImage[] images, int noOfDigits)
    {
        int w = images[0].getWidth(null);
        int h = images[0].getHeight(null);
        return new Rectangle(ox - w * noOfDigits, oy, w * noOfDigits, h);
    }

    private void repaintSegments(int ox, int oy, BufferedImage[] images, int noOfDigits)
    {
        Rectangle r = lcdBounds(ox, oy, images, noOfDigits);
        repaint(0, r.x, r.y, r.width, r.height);
    }

    public static void drawSegments(Graphics g, int ox, int oy, List<Integer> digits,
                                         BufferedImage[] images, int noOfDigits)
    {
        if (g.getClipBounds().intersects(lcdBounds(ox, oy, images, noOfDigits)))
            for (int i = 0; i < digits.size() && i < noOfDigits; i++) {
                int x = ox - images[0].getWidth(null)*(i+1);
                int digit = digits.get(digits.size() - 1 - i);
                for (int j = 0; j < 8; j++)
                    if ((digit & (1 << j)) != 0)
                        g.drawImage(images[j], x, oy, null);
            }
    }
}

class ClassNameRenderer extends DefaultListCellRenderer {
    public ClassNameRenderer() {
        setOpaque(true);
    }

    public Component getListCellRendererComponent(JList<?> list,
                                                  Object value,
                                                  int index,
                                                  boolean isSelected,
                                                  boolean cellHasFocus) {
        return super.getListCellRendererComponent(list, value.getClass().getName(), index, isSelected, cellHasFocus);
    }
}

public class PetrolPump extends JFrame
{
    private Listener l = new Listener();
    private Event<Key> eKey;
    public EventSink<Integer> eFuelPulses = new EventSink<>();
    public Behavior<Delivery> delivery;

    private static Behavior<List<Integer>> format7Seg(Behavior<String> text, int digits)
    {
        return text.map(text_ -> {
            Integer[] segs = new Integer[digits];
            for (int i = 0; i < digits; i++)
                segs[i] = 0;
            int i = digits-1;
            int j = text_.length() - 1;
            while (j >= 0 && i >= 0) {
                char ch = text_.charAt(j);
                switch (ch) {
                    case '-': segs[i] |= 0x08; i--; break;
                    case '0': segs[i] |= 0x77; i--; break;
                    case '1': segs[i] |= 0x24; i--; break;
                    case '2': segs[i] |= 0x6b; i--; break;
                    case '3': segs[i] |= 0x6d; i--; break;
                    case '4': segs[i] |= 0x3c; i--; break;
                    case '5': segs[i] |= 0x5d; i--; break;
                    case '6': segs[i] |= 0x5f; i--; break;
                    case '7': segs[i] |= 0x64; i--; break;
                    case '8': segs[i] |= 0x7f; i--; break;
                    case '9': segs[i] |= 0x7c; i--; break;
                    case '.': segs[i] |= 0x80;
                }
                j--;
            }
            return Arrays.<Integer>asList(segs);
        });
    }

    public static <A> Event<A> changes(Behavior<A> b)
    {
        return Event.filterOptional(
            b.value().snapshot(b, (neu, old) ->
                old.equals(neu) ? Optional.empty() : Optional.of(neu)));
    }

    @SuppressWarnings("unchecked")
    public PetrolPump(URL rootURL) throws IOException
    {
        super("Functional Reactive Petrol Pump");

        Transaction.runVoid(() -> {
            try {
                setLayout(new BorderLayout());

                Container topTwoPanels = new Container();
                add(topTwoPanels, BorderLayout.NORTH);
                topTwoPanels.setLayout(new GridLayout(0,1));
                Container firstPanel = new Container();
                firstPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
                topTwoPanels.add(firstPanel);
                Container secondPanel = new Container();
                secondPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
                topTwoPanels.add(secondPanel);
                firstPanel.add(new JLabel("Logic"));

                SComboBox<Pump> logic = new SComboBox<>(new DefaultComboBoxModel<Pump>(new Pump[] {
                    new chapter2.section3.Beeper(),
                    new chapter2.section7.Nozzle8888(),
                    new chapter2.section8.NozzlePrice(),
                    new chapter2.section9.CapturePrice(),
                    new chapter2.section10.CapturePriceFiltered(),
                    new chapter2.section11.AccumulatePulses(),
                    new chapter3.section2.LifeCyclePump(),
                    new chapter3.section4.AccumulatePulsesPump(),
                    new chapter3.section5.ShowDollarsPump(),
                    new chapter3.section6.ClearSalePump(),
                    new chapter3.section7.KeypadPump(),
                    new chapter3.section9.PresetAmountPump()
                }));
                logic.setRenderer(new ClassNameRenderer());
                firstPanel.add(logic);
                secondPanel.add(new JLabel("Price1"));
                STextField textPrice1 = new STextField("2.149", 7);
                secondPanel.add(textPrice1);
                secondPanel.add(new JLabel("Price2"));
                STextField textPrice2 = new STextField("2.341", 7);
                secondPanel.add(textPrice2);
                secondPanel.add(new JLabel("Price3"));
                STextField textPrice3 = new STextField("1.499", 7);
                secondPanel.add(textPrice3);
               
                Lambda1<String,Double> parseDbl = str -> {
                    try {
                        return Double.parseDouble(str);
                    }
                    catch (NumberFormatException e) {
                        return 0.0;
                    }
                };

                // An event of mouse presses
                EventSink<Point> eClick = new EventSink<Point>();

                /*
                l = l.append(eClick.listen(pt -> {
                    System.out.println(pt);
                }));
                */

                eKey = toKey(eClick);

                /*
                l = l.append(eKey.listen(key -> {
                    System.out.println(key);
                }));
                */

                Integer[] five = {0xff, 0xff, 0xff, 0xff, 0xff};
                List<Integer> five8s = Arrays.asList(five);
                Integer[] four = {0xff, 0xff, 0xff, 0xff};
                List<Integer> four8s = Arrays.asList(four);
                @SuppressWarnings("unchecked")
                BehaviorLoop<UpDown>[] nozzles = new BehaviorLoop[3];
                for (int i = 0; i < 3; i++)
                    nozzles[i] = new BehaviorLoop<UpDown>();

                Behavior<Double> calibration = new Behavior<>(0.001);
                Behavior<Double> price1 = textPrice1.text.map(parseDbl);
                Behavior<Double> price2 = textPrice2.text.map(parseDbl);
                Behavior<Double> price3 = textPrice3.text.map(parseDbl);
                EventSink<Unit> eClearSale = new EventSink<>();

                Behavior<Outputs> outputs = logic.selectedItem.map(
                    pump -> pump.create(
                        new Inputs(
                            nozzles[0].updates(),
                            nozzles[1].updates(),
                            nozzles[2].updates(),
                            eKey,
                            eFuelPulses,
                            calibration,
                            price1,
                            price2,
                            price3,
                            eClearSale
                        )
                    )
                );

                delivery = Behavior.switchB(outputs.map(o -> o.delivery));
                Behavior<String> presetLCD = Behavior.switchB(outputs.map(o -> o.presetLCD));
                Behavior<String> saleCostLCD = Behavior.switchB(outputs.map(o -> o.saleCostLCD));
                Behavior<String> saleQuantityLCD = Behavior.switchB(outputs.map(o -> o.saleQuantityLCD));
                Behavior<String> priceLCD1 = Behavior.switchB(outputs.map(o -> o.priceLCD1));
                Behavior<String> priceLCD2 = Behavior.switchB(outputs.map(o -> o.priceLCD2));
                Behavior<String> priceLCD3 = Behavior.switchB(outputs.map(o -> o.priceLCD3));
                Event<Unit> eBeep = Behavior.switchE(outputs.map(o -> o.eBeep));
                Event<Sale> eSaleComplete = Behavior.switchE(outputs.map(o -> o.eSaleComplete));

                AudioClip beepClip = Applet.newAudioClip(new URL(rootURL, "sounds/beep.wav"));
                l = l.append(eBeep.listen(u -> {
                    System.out.println("BEEP!");
                    beepClip.play();
                }));

                AudioClip fastRumble = Applet.newAudioClip(new URL(rootURL, "sounds/fast.wav"));
                AudioClip slowRumble = Applet.newAudioClip(new URL(rootURL, "sounds/slow.wav"));

                l = l.append(changes(delivery).listen(d -> {
                    switch (d) {
                    case FAST1:
                    case FAST2:
                    case FAST3:
                        fastRumble.loop();
                        break;
                    default:
                        fastRumble.stop();
                    }
                    switch (d) {
                    case SLOW1:
                    case SLOW2:
                    case SLOW3:
                        slowRumble.loop();
                        break;
                    default:
                        slowRumble.stop();
                    }
                }));

                PumpFace face = new PumpFace(
                        rootURL, eClick,
                        format7Seg(presetLCD,5),
                        format7Seg(saleCostLCD,5),
                        format7Seg(saleQuantityLCD,5),
                        format7Seg(priceLCD1,4),
                        format7Seg(priceLCD2,4),
                        format7Seg(priceLCD3,4),
                        nozzles[0],
                        nozzles[1],
                        nozzles[2]
                    );
                add(face, BorderLayout.CENTER);
                for (int i = 0; i < 3; i++) {
                    final Behavior<Tuple2<Rectangle, UpDown>> rect_state =
                        Behavior.lift(
                            (rect, state) -> new Tuple2<Rectangle, UpDown>(rect, state),
                            face.nozzleRects[i], nozzles[i]);
                    ((BehaviorLoop<UpDown>)nozzles[i]).loop(
                        Event.<UpDown>filterOptional(
                            eClick.snapshot(rect_state,
                                (pt, rs) -> rs.a.contains(pt) ? Optional.of(invert(rs.b))
                                                              : Optional.empty()
                            )
                        ).hold(UpDown.DOWN)
                    );
                }

                l = l.append(eSaleComplete.listen(sale -> {
                    JDialog dialog = new JDialog(this, "Sale complete", false);
                    dialog.setLayout(new GridLayout(5,2));
                    dialog.add(new JLabel("Fuel "));
                    dialog.add(new JLabel(sale.fuel.toString()));
                    dialog.add(new JLabel("Price "));
                    dialog.add(new JLabel(Formatters.priceFmt.format(sale.price)));
                    dialog.add(new JLabel("Dollars delivered "));
                    dialog.add(new JLabel(Formatters.costFmt.format(sale.cost)));
                    dialog.add(new JLabel("Liters delivered "));
                    dialog.add(new JLabel(Formatters.quantityFmt.format(sale.quantity)));
                    SButton ok = new SButton("OK");
                    dialog.add(ok);
                    dialog.pack();
                    dialog.setVisible(true);
                    this.l = l.append(ok.eClicked.listen(u -> {
                        dialog.dispose();
                        eClearSale.send(Unit.UNIT);
                    }));
                }));
            }
            catch (MalformedURLException e) {
                System.err.println("Unexpected exception: "+e);
            }
            catch (IOException e) {
                System.err.println("Unexpected exception: "+e);
            }
        });
        pack();
    }

    private static UpDown invert(UpDown u) {
        return u == UpDown.UP ? UpDown.DOWN : UpDown.UP;
    }

    public static Event<Key> toKey(Event<Point> eClick) {
        HashMap<Tuple2<Integer,Integer>, Key> keys = new HashMap<>();
        keys.put(new Tuple2<>(0,0), Key.ONE);
        keys.put(new Tuple2<>(1,0), Key.TWO);
        keys.put(new Tuple2<>(2,0), Key.THREE);
        keys.put(new Tuple2<>(0,1), Key.FOUR);
        keys.put(new Tuple2<>(1,1), Key.FIVE);
        keys.put(new Tuple2<>(2,1), Key.SIX);
        keys.put(new Tuple2<>(0,2), Key.SEVEN);
        keys.put(new Tuple2<>(1,2), Key.EIGHT);
        keys.put(new Tuple2<>(2,2), Key.NINE);
        keys.put(new Tuple2<>(1,3), Key.ZERO);
        keys.put(new Tuple2<>(2,3), Key.CLEAR);

        return Event.filterOptional(eClick.map(pt -> {
            int x = pt.x - 40;
            int y = pt.y - 230;
            int col = x / 50;
            int row = y / 50;
            boolean valid =
                x >= 0 && x % 50 < 40 &&
                y >= 0 && y % 50 < 40 &&
                col < 3 && row < 4;
            Key key = valid ? keys.get(new Tuple2<>(col, row)) : null;
            return Optional.ofNullable(key);
        }));
    }

    public void removeNotify() {
        l.unlisten();
        super.removeNotify();
    }

    public static void main(String[] args) throws MalformedURLException, IOException
    {
        URL rootURL = new URL("file:.");
        PetrolPump view = new PetrolPump(rootURL);
        view.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        view.setVisible(true);

        // Simuate fuel pulses when 'delivery' is on.
        while (true) {
            Transaction.runVoid(() -> {
                switch (view.delivery.sample()) {
                case FAST1:
                case FAST2:
                case FAST3:
                    view.eFuelPulses.send(40);
                    break;
                case SLOW1:
                case SLOW2:
                case SLOW3:
                    view.eFuelPulses.send(2);
                }
            });
            try { Thread.sleep(200); } catch (InterruptedException e) {}
        }
    }
}
TOP

Related Classes of pump.ClassNameRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.