From a116462fc578c2b3737753039d26769313d78551 Mon Sep 17 00:00:00 2001 From: skylarmt Date: Sat, 14 Mar 2015 21:26:54 -0600 Subject: [PATCH] Happy Pi Day, have code --- src/net/apocalypselabs/symat/CodeRunner.java | 5 +- src/net/apocalypselabs/symat/Functions.java | 178 +++++++++++++++++- src/net/apocalypselabs/symat/Main.java | 55 ++++-- src/net/apocalypselabs/symat/Tasks.form | 74 ++++++++ src/net/apocalypselabs/symat/Tasks.java | 136 +++++++++++++ .../apocalypselabs/symat/components/Task.form | 81 ++++++++ .../apocalypselabs/symat/components/Task.java | 159 ++++++++++++++++ .../symat/components/TaskMenu.form | 81 ++++++++ .../symat/components/TaskMenu.java | 162 ++++++++++++++++ src/net/apocalypselabs/symat/functions.js | 3 + src/net/apocalypselabs/symat/functions.py | 16 +- .../apocalypselabs/symat/icons/greenlight.png | Bin 0 -> 584 bytes .../apocalypselabs/symat/icons/redlight.png | Bin 0 -> 591 bytes src/net/apocalypselabs/symat/images/tasks.png | Bin 0 -> 3592 bytes 14 files changed, 928 insertions(+), 22 deletions(-) create mode 100644 src/net/apocalypselabs/symat/Tasks.form create mode 100644 src/net/apocalypselabs/symat/Tasks.java create mode 100644 src/net/apocalypselabs/symat/components/Task.form create mode 100644 src/net/apocalypselabs/symat/components/Task.java create mode 100644 src/net/apocalypselabs/symat/components/TaskMenu.form create mode 100644 src/net/apocalypselabs/symat/components/TaskMenu.java create mode 100644 src/net/apocalypselabs/symat/icons/greenlight.png create mode 100644 src/net/apocalypselabs/symat/icons/redlight.png create mode 100644 src/net/apocalypselabs/symat/images/tasks.png diff --git a/src/net/apocalypselabs/symat/CodeRunner.java b/src/net/apocalypselabs/symat/CodeRunner.java index 3a1ed9c..2769fa0 100644 --- a/src/net/apocalypselabs/symat/CodeRunner.java +++ b/src/net/apocalypselabs/symat/CodeRunner.java @@ -83,6 +83,7 @@ public class CodeRunner { // Add custom functions. se.eval("importClass(net.apocalypselabs.symat.Functions);" + "SyMAT_Functions = new net.apocalypselabs.symat.Functions();" + + "SyMAT_Functions.setLang('js');\n" + getFunctions("js")); // Allow engine access from scripts. se.put("engine", se); @@ -91,12 +92,14 @@ public class CodeRunner { } break; case "python": + case "jython": case "py": se = new ScriptEngineManager().getEngineByName("python"); try { se.eval("from math import *\n" + "from net.apocalypselabs.symat import Functions\n" - + "_=Functions()\n\n" + + "_=Functions()\n" + + "_.setLang('py')\n\n" + getFunctions("py")); // Allow engine access from scripts. se.put("engine", se); diff --git a/src/net/apocalypselabs/symat/Functions.java b/src/net/apocalypselabs/symat/Functions.java index 72f2547..4ec00aa 100644 --- a/src/net/apocalypselabs/symat/Functions.java +++ b/src/net/apocalypselabs/symat/Functions.java @@ -50,13 +50,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import static java.lang.Math.*; -import java.net.MalformedURLException; +import java.lang.reflect.Array; import java.net.URL; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import javax.swing.JOptionPane; import static net.apocalypselabs.symat.Main.API_URL; import org.matheclipse.core.eval.EvalUtilities; @@ -77,6 +81,8 @@ public class Functions { private final EvalUtilities util = new EvalUtilities(true, true); Graph graphwin = new Graph(true); + private String lang = "py"; + /* Useful interactions */ @@ -263,6 +269,54 @@ public class Functions { return ans; } + /** + * Get all prime factors of input number. + * + * @param n An integer number. + * @return Array of primes. + * + * Thanks to + * http://www.javacodegeeks.com/2014/05/how-to-find-prime-factors-of-integer-numbers-in-java-factorization.html + * and http://stackoverflow.com/a/2451219/2534036 + */ + public long[] factor(long n) { + long i; + Set primes = new HashSet<>(); + long copyOfInput = n; + + for (i = 2; i <= copyOfInput; i++) { + if (copyOfInput % i == 0) { + primes.add(i); // prime factor + copyOfInput /= i; + i--; + } + } + long[] a = new long[primes.size()]; + int j = 0; + for (Object val : primes) { + a[j++] = (long) val; + } + return a; + } + + /** + * Get all unique permutations of the given array. + * @param objs Array of items. + * @return Matrix + */ + public Object[] perms(Object... objs) { + Permutations perm = new Permutations<>(objs); + + Set perms = new HashSet<>(); + + while (perm.hasNext()) { + perms.add(perm.next()); + } + + Object[][] a = new Object[perms.size()][objs.length]; + return perms.toArray(a); + } + /** * Multiply two matrices. * @@ -272,13 +326,18 @@ public class Functions { * @throws net.apocalypselabs.symat.BadInputException When the matrices are * wrong. */ - public double[][] mtimes(double[][] a, double[][] b) throws BadInputException { + public Object mtimes(double[][] a, double[][] b) throws BadInputException { + return tonativearray(mTimes(a, b)); + } + + private double[][] mTimes(double[][] a, double[][] b) throws BadInputException { double[][] ans = new double[a.length][b[0].length]; double sum = 0; int c, d, k, m = a.length, q = b[0].length, p = b.length; if (a[0].length != b.length) { - throw new BadInputException("First matrix column count must match second matrix row count."); + throw new BadInputException("First matrix column count must match " + + "second matrix row count."); } for (c = 0; c < m; c++) { @@ -302,7 +361,7 @@ public class Functions { * @throws BadInputException if the matrix is not square or power is less * than 0 */ - public double[][] mpower(double[][] a, int b) throws BadInputException { + public Object mpower(double[][] a, int b) throws BadInputException { if (a.length != a[0].length) { throw new BadInputException("Matrix needs to be square."); } @@ -316,9 +375,13 @@ public class Functions { if (i == 0) { ans = a; } else { - ans = mtimes(a, ans); + ans = mTimes(a, ans); } } + return tonativearray(ans); + } + + private double[][] tonativearray(double[][] ans) { return ans; } @@ -372,6 +435,7 @@ public class Functions { * Substitute newvar for variable in function and attempt to calculate a * numerical answer. *
Example: subs('32*x','x',2) = 64.0 + * * @param function Function * @param variable Variable to substitute * @param newvar Value to replace with @@ -383,6 +447,7 @@ public class Functions { /** * Attempt to find numerical value of input. + * * @param f Function * @return answer or zero if it doesn't exist */ @@ -603,4 +668,103 @@ public class Functions { public Functions() { Main.loadFrame(graphwin, false); } + + public void setLang(String l) { + lang = l; + } + + /** + * This class finds permutations of an array. + * + * Credit to http://stackoverflow.com/a/14444037/2534036 + * + * License: CC-BY-SA 3.0 + * + * @param + */ + class Permutations implements Iterator { + + private E[] arr; + private int[] ind; + private boolean has_next; + + public E[] output;//next() returns this array, make it public + + Permutations(E[] arr) { + this.arr = arr.clone(); + ind = new int[arr.length]; + //convert an array of any elements into array of integers - first occurrence is used to enumerate + Map hm = new HashMap(); + for (int i = 0; i < arr.length; i++) { + Integer n = hm.get(arr[i]); + if (n == null) { + hm.put(arr[i], i); + n = i; + } + ind[i] = n.intValue(); + } + Arrays.sort(ind);//start with ascending sequence of integers + + //output = new E[arr.length]; <-- cannot do in Java with generics, so use reflection + output = (E[]) Array.newInstance(arr.getClass().getComponentType(), arr.length); + has_next = true; + } + + @Override + public boolean hasNext() { + return has_next; + } + + /** + * Computes next permutations. Same array instance is returned every + * time! + * + * @return + */ + @Override + public E[] next() { + if (!has_next) { + throw new NoSuchElementException(); + } + + for (int i = 0; i < ind.length; i++) { + output[i] = arr[ind[i]]; + } + + //get next permutation + has_next = false; + for (int tail = ind.length - 1; tail > 0; tail--) { + if (ind[tail - 1] < ind[tail]) {//still increasing + + //find last element which does not exceed ind[tail-1] + int s = ind.length - 1; + while (ind[tail - 1] >= ind[s]) { + s--; + } + + swap(ind, tail - 1, s); + + //reverse order of elements in the tail + for (int i = tail, j = ind.length - 1; i < j; i++, j--) { + swap(ind, i, j); + } + has_next = true; + break; + } + + } + return output; + } + + private void swap(int[] arr, int i, int j) { + int t = arr[i]; + arr[i] = arr[j]; + arr[j] = t; + } + + @Override + public void remove() { + + } + } } diff --git a/src/net/apocalypselabs/symat/Main.java b/src/net/apocalypselabs/symat/Main.java index 85c2d78..703485a 100644 --- a/src/net/apocalypselabs/symat/Main.java +++ b/src/net/apocalypselabs/symat/Main.java @@ -66,6 +66,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import javafx.application.Platform; import javax.swing.ImageIcon; @@ -94,7 +95,7 @@ public class Main extends JRibbonFrame { /** * Version name, as it should be displayed. */ - public static final String VERSION_NAME = "1.5"; + public static final String VERSION_NAME = "1.6"; /** * The word "SyMAT". @@ -107,7 +108,7 @@ public class Main extends JRibbonFrame { /** * Version number, for updates and //needs in scripts */ - public static final double APP_CODE = 17; + public static final double APP_CODE = 18; /** * Base URL for building API calls */ @@ -243,6 +244,16 @@ public class Main extends JRibbonFrame { if (!PrefStorage.getSetting("showrecent", "").equals("")) { recentItemsPanel.setVisible(false); } + + // Pi Day easter egg + GregorianCalendar piday = new GregorianCalendar(); + if ((piday.get(Calendar.MONTH) == 2) + && (piday.get(Calendar.DAY_OF_MONTH) == 14)) { + JOptionPane.showInternalMessageDialog(mainPane, + "Happy Pi Day from the SyMAT team!", + "3/14", + JOptionPane.PLAIN_MESSAGE); + } } /** @@ -304,15 +315,29 @@ public class Main extends JRibbonFrame { loadFrame(new Pads()); } }); + tasksbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Tasks()); + } + }); - shellbtn.setPopupKeyTip("Open a window " - + "for running interactive commands."); - editorbtn.setPopupKeyTip("Write and run multiple-line scripts."); - graphbtn.setPopupKeyTip("Plot mathematical functions."); - notepadbtn.setPopupKeyTip("Write quick notes on a virtual napkin."); - wikibtn.setPopupKeyTip("View online documentation and tutorials."); - forumbtn.setPopupKeyTip("Discuss and share with the SyMAT community."); - padsbtn.setPopupKeyTip("Collaborate over the Internet on projects."); + shellbtn.setActionRichTooltip(new RichTooltip("Command Shell", + "Open a window for running interactive commands.")); + editorbtn.setActionRichTooltip(new RichTooltip("Code Editor", + "Write and run JavaScript and Python scripts.")); + graphbtn.setActionRichTooltip(new RichTooltip("Graph", + "Plot mathematical functions on a 2D graph.")); + notepadbtn.setActionRichTooltip(new RichTooltip("Notepad", + "Write quick notes on a virtual napkin.")); + wikibtn.setActionRichTooltip(new RichTooltip("SyMAT Wiki", + "View and edit online documentation and tutorials.")); + forumbtn.setActionRichTooltip(new RichTooltip("Support Forum", + "Discuss and share with the SyMAT community.")); + padsbtn.setActionRichTooltip(new RichTooltip("Code Pads", + "Collaborate over the Internet on projects.")); + tasksbtn.setActionRichTooltip(new RichTooltip("Task List", + "Manage tasks and to-do lists for projects.")); coreband.addCommandButton(shellbtn, RibbonElementPriority.TOP); coreband.addCommandButton(editorbtn, RibbonElementPriority.TOP); @@ -324,6 +349,7 @@ public class Main extends JRibbonFrame { webband.addCommandButton(forumbtn, RibbonElementPriority.LOW); collabband.addCommandButton(padsbtn, RibbonElementPriority.MEDIUM); + collabband.addCommandButton(tasksbtn, RibbonElementPriority.MEDIUM); coreband.setResizePolicies((List) Arrays.asList( new CoreRibbonResizePolicies.None(coreband.getControlPanel()), @@ -460,9 +486,9 @@ public class Main extends JRibbonFrame { if (recent == null) { RibbonApplicationMenuEntrySecondary blanksubbtn - = new RibbonApplicationMenuEntrySecondary( - null, "No recent files", null, - JCommandButton.CommandButtonKind.ACTION_ONLY); + = new RibbonApplicationMenuEntrySecondary( + null, "No recent files", null, + JCommandButton.CommandButtonKind.ACTION_ONLY); blanksubbtn.setEnabled(false); openbtn.addSecondaryMenuGroup("Recent Files", blanksubbtn); } else { @@ -564,6 +590,7 @@ public class Main extends JRibbonFrame { /** * Add a file to the recent files lists. + * * @param file The file path. */ public static void addRecentFile(String file) { @@ -947,6 +974,8 @@ public class Main extends JRibbonFrame { = new JCommandButton("Forum", getRibbonIcon("forum")); public static JCommandButton padsbtn = new JCommandButton("Pads", getRibbonIcon("pads")); + public static JCommandButton tasksbtn + = new JCommandButton("Tasks", getRibbonIcon("tasks")); public static RibbonApplicationMenuEntryPrimary openbtn; // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/src/net/apocalypselabs/symat/Tasks.form b/src/net/apocalypselabs/symat/Tasks.form new file mode 100644 index 0000000..d44f13f --- /dev/null +++ b/src/net/apocalypselabs/symat/Tasks.form @@ -0,0 +1,74 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/net/apocalypselabs/symat/Tasks.java b/src/net/apocalypselabs/symat/Tasks.java new file mode 100644 index 0000000..c5a81b9 --- /dev/null +++ b/src/net/apocalypselabs/symat/Tasks.java @@ -0,0 +1,136 @@ +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat; + +import net.apocalypselabs.symat.components.Task; + +/** + * + * @author Skylar + */ +public class Tasks extends javax.swing.JInternalFrame { + + /** + * Creates new form Tasks + */ + public Tasks() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + taskList = new javax.swing.JScrollPane(); + listPanel = new javax.swing.JPanel(); + jMenuBar1 = new javax.swing.JMenuBar(); + jMenu1 = new javax.swing.JMenu(); + jMenuItem1 = new javax.swing.JMenuItem(); + + setClosable(true); + setIconifiable(true); + setMaximizable(true); + setResizable(true); + setTitle("Tasks"); + + listPanel.setLayout(new javax.swing.BoxLayout(listPanel, javax.swing.BoxLayout.Y_AXIS)); + taskList.setViewportView(listPanel); + + jMenu1.setText("File"); + + jMenuItem1.setText("Sample"); + jMenuItem1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jMenuItem1ActionPerformed(evt); + } + }); + jMenu1.add(jMenuItem1); + + jMenuBar1.add(jMenu1); + + setJMenuBar(jMenuBar1); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(taskList, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(taskList, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE) + ); + + pack(); + }// //GEN-END:initComponents + + private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed + for (int i = 1; i <= 5; i++) { + Task t = new Task( + (i % 2 == 0), + "Name " + i, + "Description " + i); + listPanel.add(t); + t.setVisible(true); + } + setSize(getWidth() + 1, getHeight()); + setSize(getWidth() - 1, getHeight()); + }//GEN-LAST:event_jMenuItem1ActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JMenu jMenu1; + private javax.swing.JMenuBar jMenuBar1; + private javax.swing.JMenuItem jMenuItem1; + private javax.swing.JPanel listPanel; + private javax.swing.JScrollPane taskList; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/components/Task.form b/src/net/apocalypselabs/symat/components/Task.form new file mode 100644 index 0000000..579a57e --- /dev/null +++ b/src/net/apocalypselabs/symat/components/Task.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/net/apocalypselabs/symat/components/Task.java b/src/net/apocalypselabs/symat/components/Task.java new file mode 100644 index 0000000..9592d5a --- /dev/null +++ b/src/net/apocalypselabs/symat/components/Task.java @@ -0,0 +1,159 @@ +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat.components; + +import javax.swing.ImageIcon; +import javax.swing.JOptionPane; + +/** + * + * @author Skylar + */ +public class Task extends javax.swing.JPanel { + + private boolean taskDone = false; + + public Task(boolean complete, String name, String desc) { + this(); + taskDone = complete; + setComplete(complete); + taskName.setText(name); + taskDesc.setText(desc); + } + + /** + * Creates new form Task + */ + public Task() { + initComponents(); + } + + private void setComplete(boolean b) { + statusLabel.setIcon(new ImageIcon( + getClass().getResource( + "/net/apocalypselabs/symat/icons/" + + (b ? "green" : "red") + "light.png" + ))); + statusLabel.setToolTipText(b ? "Complete" : "Incomplete"); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + taskName = new javax.swing.JLabel(); + taskDesc = new javax.swing.JLabel(); + menuBtn = new javax.swing.JButton(); + statusLabel = new javax.swing.JLabel(); + + taskName.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(20.0F)); + taskName.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + taskName.setText("Unnamed task"); + + taskDesc.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(12.0F)); + taskDesc.setText("No description"); + taskDesc.setVerticalAlignment(javax.swing.SwingConstants.TOP); + + menuBtn.setText("Menu"); + menuBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuBtnActionPerformed(evt); + } + }); + + statusLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icons/redlight.png"))); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(statusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(taskName, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(menuBtn)) + .addComponent(taskDesc, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(menuBtn) + .addGap(0, 7, Short.MAX_VALUE)) + .addComponent(taskName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(statusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(taskDesc, javax.swing.GroupLayout.DEFAULT_SIZE, 38, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void menuBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuBtnActionPerformed + TaskMenu tm = new TaskMenu(taskDone, + taskName.getText(), + taskDesc.getText()); + JOptionPane.showInternalMessageDialog(this, tm, + "Task Options", JOptionPane.PLAIN_MESSAGE); + taskDone = tm.isComplete(); + setComplete(taskDone); + taskName.setText(tm.toString()); + taskDesc.setText(tm.getDesc()); + }//GEN-LAST:event_menuBtnActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton menuBtn; + private javax.swing.JLabel statusLabel; + private javax.swing.JLabel taskDesc; + private javax.swing.JLabel taskName; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/components/TaskMenu.form b/src/net/apocalypselabs/symat/components/TaskMenu.form new file mode 100644 index 0000000..4275bec --- /dev/null +++ b/src/net/apocalypselabs/symat/components/TaskMenu.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/net/apocalypselabs/symat/components/TaskMenu.java b/src/net/apocalypselabs/symat/components/TaskMenu.java new file mode 100644 index 0000000..02f70ec --- /dev/null +++ b/src/net/apocalypselabs/symat/components/TaskMenu.java @@ -0,0 +1,162 @@ +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat.components; + +/** + * + * @author Skylar + */ +public class TaskMenu extends javax.swing.JPanel { + + /** + * Creates new TaskMenu + * @param complete If the task is completed. + * @param name Task name + * @param desc Task description + */ + public TaskMenu(boolean complete, String name, String desc) { + this(); + completeBox.setSelected(complete); + nameBox.setText(name); + descBox.setText(desc); + } + + /** + * Creates new TaskMenu + */ + public TaskMenu() { + initComponents(); + } + + /** + * Check if the task is marked as done. + * @return true if it is. + */ + public boolean isComplete() { + return completeBox.isSelected(); + } + + /** + * Get the name of the task. + * @return Task name. + */ + @Override + public String toString() { + return nameBox.getText(); + } + + /** + * Get the task description. + * @return The description. + */ + public String getDesc() { + return descBox.getText(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + completeBox = new javax.swing.JCheckBox(); + nameBox = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + descBox = new javax.swing.JTextArea(); + + completeBox.setText("Task complete"); + + jLabel1.setText("Task Name:"); + + jLabel2.setText("Task Description:"); + + descBox.setColumns(20); + descBox.setRows(5); + jScrollPane1.setViewportView(descBox); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(nameBox) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(completeBox) + .addComponent(jLabel2)) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(completeBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(nameBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox completeBox; + private javax.swing.JTextArea descBox; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTextField nameBox; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/functions.js b/src/net/apocalypselabs/symat/functions.js index e69de29..1c986f3 100644 --- a/src/net/apocalypselabs/symat/functions.js +++ b/src/net/apocalypselabs/symat/functions.js @@ -0,0 +1,3 @@ +function mprint(m) { + return JSON.stringify(m); +} \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/functions.py b/src/net/apocalypselabs/symat/functions.py index 3183acc..a4917be 100644 --- a/src/net/apocalypselabs/symat/functions.py +++ b/src/net/apocalypselabs/symat/functions.py @@ -33,4 +33,18 @@ def vpa(expr): def readfile(path): return _.readfile(path) def savefile(data,path): - _.savefile(data,path) \ No newline at end of file + _.savefile(data,path) +def mtimes(a,b): + return _.mtimes(a,b) +def mpower(a,b): + return _.mpower(a,b) +def add(*a): + return _.add(a) +def subtract(*a): + return _.subtract(a) +def times(*a): + return _.times(a) +def divide(*a): + return _.divide(a) +def mod(*a): + return _.mod(a) \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/icons/greenlight.png b/src/net/apocalypselabs/symat/icons/greenlight.png new file mode 100644 index 0000000000000000000000000000000000000000..0113c8fb1cd8a229baefdeb06000a532e50c9961 GIT binary patch literal 584 zcmV-O0=NB%P)W|GHI3L+Frvth|qarT`OBHsAdC@7k(s2fsf5x)q+3Mf63k zI<0V0;nU#5YsjY?pZ@KO*mvj6#W&jj|NsAkl9~8b_*csX$=Mlp8VX_4e7^kryGQFD z9r}3ZV<<{yLI&KT+}^CBtoiI>>>_MJY@&>ej0`{D{(SZG&CfT#U;du-_4U`S$m#*j Wxaeq$}qhtH=VBAJ$DU1c(f;AQAB=$JFC? zABO$@@y$TMUn{(xOj_S9%Q!0(=ARr>H7a8tR6$tnbh$eGf}kP*WJ;x!d4F&IFO{~_ doJXts9{}XD=aj0N@p=FN002ovPDHLkV1kgM2k-y@ literal 0 HcmV?d00001 diff --git a/src/net/apocalypselabs/symat/images/tasks.png b/src/net/apocalypselabs/symat/images/tasks.png new file mode 100644 index 0000000000000000000000000000000000000000..e08938a7ec4c5408ca207c5ae85a247800dafce4 GIT binary patch literal 3592 zcmV+j4)^hiP)k8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H14TVWWK~#90?Ol6J6xSO6o!Ob)Wfvd7f?Nb$>n&|*ZAD>?wn(eq z+j?89NZdAJX`8erO`|b=nbh==5}KxI{Nw)FX!=KEqJ)N$-dK~CqT=I5BcNWuYxc@x z7g=DJM-g_JeVqHpJ{*==b{2Maw}oGFLYO&wzHiR&eBXI}a|V=B1QLKOLdX$~MstM_ z;sQVyQ|uEV#O1H!BLK3591uSdAcW*9mCEMFAAj6!G#a}qDk}Q4TCEq0h&db%2UAy9 zxAOGq(`(w>+gYCHODLrl06szpA=yf$^4iNUzih3ot-Y3Lg%=WxMq_b9Lqj&t^Tm`> zE1{G^sZ{=R)22;3nwy)?C0fCSh#fn2Jagf~g>yX5A0hyBEX($sKYzYq%a$#piB@hQ zqNSx}$)-)4_PE{d)eIrz!20#;&5L9t4jVRX7%wa=>?MR8VAN{$#;2ctdMMFKEp%+z zvc;xWt2eR$@(T(IdgK%~G&IE3*4F0q_V#Kir9@6yV&FK=TU1mu{QUFJ4{0=-q#QXG z6cmgB$Y)(Hm%gyD@P=H18XFtaUwP$~7wvX?s$4Rpf@N7xet!NyO-;>}-Me=WCR!gM z3JVKIT`pHC<954KSFT(+C6}PL-g;|WGLQiPZns;}(b18!XV0EJyLRm=vDs`~qIC*j z<;s;)Znry?kyFUMd-qh`-QAgT%9sl%rR1ldetKf_=FMeRt5un3eS~1;EL`kiRVtN> zVHhf>TmayCp7nSm&uT5+a6^Cr|!VQBg4MY541tIJ9zEM2g?V~ExXc-VfWT_ZJ$P7Xh3PoHVkY!nf$ez&<4j(?; zRb5?uUW}Bova+2+Lql;Rg%HAcJRYBg#F&s^inE1;5)#&B3Dd!Y2fM%c;)@F+q-5^i zz5DqHq(tkQ!nrpE0LJZhgYj=r$;P?}A#%u?Q866H5v5WY&Sg!jjCbC7r}y*EKfkC} ztEZ7-Hk&i|?%n%$o6RPBM^6YLE|&|8$K!z?F&Dxx4B zudiR%(b2ICF|=Yq;^B)(2@*m9cw=2DVLJ8slquPYMO+r7%BifZ?0f(H_pgQaKi_}< z{lhXe9sgQQKSfQ9(yIshPaS(3|%RxSVpT$bQ}#^G>8T5b=PzjyE6 z{-1yT*?#x#-Hd?#U0q!nc%b`SAf~?qK4b9dDY)VC|CJ(8Dj`IKkU-0jTu!udftiGu zOs1^u+qakd^$Mr&jB7&utyb%Dr_;%*)#^yQj#Blc04ApC9ddILz)}eXCB22{bUI#0 zh(IUtf~8$&tX6A^UaxnEW{y%v0K)*>!V96x?@j<}f0_;RAtcZjM2o1%d+xdCtj*2M z4~gg`Ubw{Tf;n3_NY(Rq_zYkg#P&mehmVkOLM2xW!!V3eshn|bma=C2xam@+BA0*Vm_QXlQt3TA}kNga=>?cQf3M;UoZ!KSe9>K}LV4E`$UNiB*^o z0f3B*4A0iBTZg6Q7ox4L&2{F?ndzA#6CzrcA6@_h5R9rqG20gIFaRZ_4~1uHC1N2V zoq7;F&oe*%_+zeCt99?(xwGHDp#%WVsOZVd%L{hc z48t%i%TCKL(Za>_aRa!A2cub0%tnY8fE7SCfRqRdh->BFmYikS3jjEK_H6cS_5YEsuV24@Brh*-N|0~Husy^=q&9>} z0DS;FkupXKa_|D^2k;jFT8YAgm}QhTjgU*1F6EAnj%xk0X=1nAmozmstuh!4V*rA) zWw{9vEb9byjR7Hc0E6%^jYNW!s1phwDcOiTN13Le7$Ko1fA{WP?cm_xGNEfDgrL8_ zf9b@;1gF(%J%LG{+=PU>)4*!=90~ElXBA_!&;#GRE-FMDmu2+}TLJOOT|^5BeQ2dp ziTwQhvFq2brv&1qSeB(vJn_UxAYWkRHc4F8Y%2{O07LM(s5u37&m~Z91ipDnHfGLM zq`0gZEo}e({oQ)Ke&XiMn;9(2(v2H84iy&{+XMMD8jUw6CubtuXe!!@7Xzh~_}{6V z=CVR3wgUZyg?r&6VgMmaA<<&4k&7Pq{No6KTs#bV4Y6le~z-S*e(BDCs1CI{=>$-Y z{DDq=+K(R)G7Mj%jJltg4Y7*twZXSGli^PqKzybi#^j|S?gWNf$k5Ob#>dA8Gcq#F z5Ns;N60r=ncEjgG2jC+_M=8yjWu~6=gfI-ljE#+gJlH_lg0Co~!j)~;QP zZQHilRV77HvE3)E`0EiW(czwqzkjgOD7nA?-j9dUamMr3k(LsC_=VWCkGm$jZu6Y}>ZYl$Mr8 z&z?QI(q^-1Qc_Zol9B?AMuU`;6mT2|r_%|C!-2`kNjMyiU<&74 zr3GC@W@hH^`}Xa-ok*P$g@juO0317Z>_3MN9Ws6J!3P^sQ&ahGzWL^cPNxgbda?y}guhK7cV@zy6%ND7y=hzD3CB*~C8 zE(-v>UN3~f4FQadjIa)eV=lpUQ6W1!drC}xJdqTHn9XL@d+)us;o7xpxg5uNo_Xe( z-ebp(wWXz{xdFgnFzm9~Y_gu0;_-Nxnwpw(2M-?XmQzk7Bn2U_zyA8uO-)U~fHafI zv|?gnf~&2qy%M-KIyxG4kVUlMc|PGTJmCshtybmDn>TYpuV1}-HP_{G#cGB34}*jg z($&?KGC4UpBM9#P{rjr%@$sav;CLe8glyitdF;_gAGL;FU$<^ue|ma)OtwY;NJuy# z0C4#5;kL&fd+eS{rE+OBnyDwBeA4{sr=PY4?kD0{z(gS_TtZb zB*P*hNrt%hA(fStWv{*Vn(T*Q#sXfiH}0c5SqTw4RB~!+DrwHjoeShXC{tFKm6MY* zrPu5KH0R3e_4=WloE+H>od$gGUfl2N>zng?gpqLk`0?K|GBRY{evJn*GBWNTKYsi- zxytYB>r=5Td!OYvuDi9hb$M}d@$Yg7+P;1JaA#-dsYD*eKOYc6=&Dt#CX7boz0Ax^ z*_LuzTU(cN9M{bPxYN2zMdbm>ykozK3| zaQX6Oozv;O&QMCfZEI`GyL|cb@Jp>TSe$6(78;C3V{vnHbDGQL`Vzp*4@<6Fw~jX& zjoszt<@XjpEGZ8h4hK_TU!Qa8)G7U~Tepi+@n4O