From de149c5d85ec5a9c3254de5f486ae9a1fbccec76 Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Sat, 1 Feb 2020 17:05:02 +0000 Subject: [PATCH] Added options tooltips --- deps/commons-lang3.jar | 3 + deps/commons-text.jar | 3 + .../audiobookrecorder/icons/tooltip.png | Bin 0 -> 1320 bytes .../audiobookrecorder/AudiobookRecorder.java | 2 +- .../co/majenko/audiobookrecorder/Icons.java | 1 + .../co/majenko/audiobookrecorder/Options.java | 188 ++++++------------ src/uk/co/majenko/audiobookrecorder/Tip.java | 115 +++++++++++ 7 files changed, 189 insertions(+), 123 deletions(-) create mode 100644 deps/commons-lang3.jar create mode 100644 deps/commons-text.jar create mode 100644 resources/uk/co/majenko/audiobookrecorder/icons/tooltip.png create mode 100644 src/uk/co/majenko/audiobookrecorder/Tip.java diff --git a/deps/commons-lang3.jar b/deps/commons-lang3.jar new file mode 100644 index 0000000..5e934cb --- /dev/null +++ b/deps/commons-lang3.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e8dc31e046508d9953c96534edf0c2e0bfe6f468966b5b842b3f87e43b6a847 +size 499634 diff --git a/deps/commons-text.jar b/deps/commons-text.jar new file mode 100644 index 0000000..5809876 --- /dev/null +++ b/deps/commons-text.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4a57bbc1627da7c391308fd0fe910b83170fb66afd117236a5b111d2db1590b +size 136544 diff --git a/resources/uk/co/majenko/audiobookrecorder/icons/tooltip.png b/resources/uk/co/majenko/audiobookrecorder/icons/tooltip.png new file mode 100644 index 0000000000000000000000000000000000000000..84303464d193a7639c6f559db9edba7b0ba26703 GIT binary patch literal 1320 zcmV+@1=sqCP)lOXuwD`8ZXAgtdMxngB(aacrr02h!;&TgrMLevO$6dapfh*bJ>B}dF{Nq ztGmjo+HpB-0KfD<)l>EF-}j~Zn=Yc1!tH|Sz{n;BH_l+fZv;5@d7$p_;2d}!Z1sm6 zscIsf$u8|%n0-Fin|aL47mBrmlZDE+)k@(4ZUhbdy~8(2?g%DiE5)OQ^uXe~-+SVb zk+&E0^}5P&5W+F5V33Fqpja%6eFuNtasK@Ik1(FDC^af?2__piI=q-)vuefAt~DdW zdE!PPL=Rfh&v-0L=l z24EJngq860$`o39ZuiLsiZZ3)v+J3-i|XWMG5*Wp^7xjkLCr8^P5YiB&S z)V)^oA*F&1(Z)M3ufXd3AWTFfzv0uvEej?JD6~DK(hGQQVBqUZ>n27ts-$#K>(0OF zQXU`eTb3VcdLaVOM<}#>A4yfmvi^nEX05plr0{@1CpXfbO0|L9;Lsq8_k3Vj#y1O2 zCQ{LK`t@WgYmIZ#@KO-Lp7FnIg>BEn*u<1hC^UCAaUhI5$dI7BZ_yh_yGgqhL`T>9 zw}unR0dCB8=gj^Q02221wmp;haiWMyE5M%xGihB$=HA};o{vN<#Y-`HpGJ-`)BIA> z4Lst)_x(Aego3>~p)FK_9RG^H4f;}6KZ2E-({amWbI)`a++rJ64 zRa2`cms4zcW*F182DX2H8YgZrNErZHGL$w6h(dR=3!49sVKRui-V4&z(!N01ZkRPv z2IWxbba?-z$1${I5lmDXJ~r*V3WN-?NCcDy2t->a&^>)&8Wb{Om<(Y;a8jPAm8;IS53UN22Vq7~OpJ;s z$NqM^fqF}z)>f#tfwCS;daSfV)M_QBI2I>NonRSaG#j~o{ZETy|-+Rum=6yC7Kess+@!hYk_{j}o z$%7oJK7e%rZWJq%b(F(6t_Lx|Zvn!*;mhC`4~ra|`SMcGvsoP&4Q~CR-@28qI&%Hh zLW_M|O0LYP%wmFA7Krx(gaFMF&?tdaF01a^>FI@WfAgtW@jJC^SNOk@@$N%F+tr=&g|ZP?aoKj{ICZ={((}$&8lIj(4P)t#|!%s eE&D;gP5cYV>#pDB3eKef0000 effectChains; - JComboBox mixerList; JComboBox playbackList; JComboBox channelList; @@ -72,7 +72,7 @@ public class Options extends JDialog { } } - JComboBox addDropdown(JPanel panel, String label, KVPair[] options, String def) { + JComboBox addDropdown(JPanel panel, String label, KVPair[] options, String def, String tip) { JLabel l = new JLabel(label); constraint.gridx = 0; constraint.gridwidth = 1; @@ -83,6 +83,9 @@ public class Options extends JDialog { JComboBox o = new JComboBox(options); constraint.gridx = 1; panel.add(o, constraint); + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); for (KVPair p : options) { if (p.key.equals(def)) { @@ -113,7 +116,7 @@ public class Options extends JDialog { constraint.gridy++; } - JTextField addTextField(JPanel panel, String label, String def) { + JTextField addTextField(JPanel panel, String label, String def, String tip) { JLabel l = new JLabel(label); constraint.gridx = 0; constraint.gridwidth = 1; @@ -127,13 +130,18 @@ public class Options extends JDialog { constraint.fill = GridBagConstraints.HORIZONTAL; panel.add(a, constraint); + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); + + constraint.fill = GridBagConstraints.NONE; constraint.gridy++; return a; } - JTextField[] addTwoField(JPanel panel, String def1, String def2) { + JTextField[] addTwoField(JPanel panel, String def1, String def2, String tip) { JTextField a = new JTextField(def1); constraint.gridx = 0; constraint.fill = GridBagConstraints.HORIZONTAL; @@ -144,13 +152,18 @@ public class Options extends JDialog { panel.add(b, constraint); constraint.fill = GridBagConstraints.NONE; + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); + + constraint.gridy++; return new JTextField[] { a, b }; } - JTextField addFilePath(JPanel panel, String label, String path, boolean dironly) { + JTextField addFilePath(JPanel panel, String label, String path, boolean dironly, String tip) { JLabel l = new JLabel(label); constraint.gridx = 0; constraint.gridwidth = 1; @@ -212,6 +225,10 @@ public class Options extends JDialog { constraint.fill = GridBagConstraints.HORIZONTAL; panel.add(p, constraint); + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); + constraint.fill = GridBagConstraints.NONE; constraint.gridy++; @@ -238,7 +255,7 @@ public class Options extends JDialog { constraint.gridy++; } - JSpinner addSpinner(JPanel panel, String label, int min, int max, int step, int value, String suffix) { + JSpinner addSpinner(JPanel panel, String label, int min, int max, int step, int value, String suffix, String tip) { JLabel l = new JLabel(label); constraint.gridx = 0; constraint.gridwidth = 1; @@ -258,6 +275,10 @@ public class Options extends JDialog { constraint.fill = GridBagConstraints.HORIZONTAL; panel.add(p, constraint); + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); + constraint.fill = GridBagConstraints.NONE; @@ -266,11 +287,16 @@ public class Options extends JDialog { } - JCheckBox addCheckBox(JPanel panel, String label, boolean state) { + JCheckBox addCheckBox(JPanel panel, String label, boolean state, String tip) { constraint.gridx = 1; JCheckBox cb = new JCheckBox(label); cb.setSelected(state); panel.add(cb, constraint); + Tip t = new Tip(tip); + constraint.gridx = 2; + panel.add(t, constraint); + + constraint.gridy++; return cb; } @@ -298,95 +324,71 @@ public class Options extends JDialog { addSeparator(optionsPanel); - mixerList = addDropdown(optionsPanel, "Recording device:", getRecordingMixerList(), get("audio.recording.device")); - channelList = addDropdown(optionsPanel, "Channels:", getChannelCountList(), get("audio.recording.channels")); - rateList = addDropdown(optionsPanel, "Sample rate:", getSampleRateList(), get("audio.recording.samplerate")); - bitDepth = addDropdown(optionsPanel, "Sample resolution:", getResolutionList(), get("audio.recording.resolution")); - trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim")); - fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), ""); - fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize")); - maxGainVariance = addSpinner(optionsPanel, "Maximum gain variance:", 0, 100, 1, getInteger("audio.recording.variance"), ""); + mixerList = addDropdown(optionsPanel, "Recording device:", getRecordingMixerList(), get("audio.recording.device"), "This is the system device to record through"); + channelList = addDropdown(optionsPanel, "Channels:", getChannelCountList(), get("audio.recording.channels"), "How many channels do you want to record - stereo or mono?"); + rateList = addDropdown(optionsPanel, "Sample rate:", getSampleRateList(), get("audio.recording.samplerate"), "The higher the sample rate the better the quality, but the bigger the files."); + bitDepth = addDropdown(optionsPanel, "Sample resolution:", getResolutionList(), get("audio.recording.resolution"), "The higher the resolution the better the quality, but the bigger the files."); + trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim"), "None: don't auto-trim. FFT: Compare the FFT profile of blocks to the room noise profile and trim silent blocks, Peak: Look for the start and end rise and fall points"); + fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), "", "This specifies the difference (in hundredths) between the power of FFT buckets in a sample block compared to the overall power of the same FFT bucket in the room noise. Raising this number makes the FFT trimming less sensitive."); + fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize"), "How large an FFT block should be when processing. Larger values increase sensitivity but at the epxense of resolution."); + maxGainVariance = addSpinner(optionsPanel, "Maximum gain variance:", 0, 100, 1, getInteger("audio.recording.variance"), "", "This is how much the gain is allowed to vary by from phrase to phrase when normalizing an entire chapter."); addSeparator(optionsPanel); - playbackList = addDropdown(optionsPanel, "Playback device:", getPlaybackMixerList(), get("audio.playback.device")); - playbackBlockSize = addDropdown(optionsPanel, "Playback Block size:", getPlaybackBlockSizes(), get("audio.playback.blocksize")); + playbackList = addDropdown(optionsPanel, "Playback device:", getPlaybackMixerList(), get("audio.playback.device"), "Which device to play back through"); + playbackBlockSize = addDropdown(optionsPanel, "Playback Block size:", getPlaybackBlockSizes(), get("audio.playback.blocksize"), "How big the playback buffer should be. Larger is smoother playback but the playback marker in the waveform becomes more out of sync"); addSeparator(optionsPanel); - storageFolder = addFilePath(optionsPanel, "Storage folder:", get("path.storage"), true); - archiveFolder = addFilePath(optionsPanel, "Archive folder:", get("path.archive"), true); + storageFolder = addFilePath(optionsPanel, "Storage folder:", get("path.storage"), true, "This is where all your working audiobooks are stored."); + archiveFolder = addFilePath(optionsPanel, "Archive folder:", get("path.archive"), true, "This is where audiobooks are archived to."); addSeparator(optionsPanel); - preChapterGap = addSpinner(optionsPanel, "Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms"); - postChapterGap = addSpinner(optionsPanel, "Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms"); - postSentenceGap = addSpinner(optionsPanel, "Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms"); - shortSentenceGap = addSpinner(optionsPanel, "Short post-sentence gap:", 0, 5000, 100, getInteger("catenation.short-sentence"), "ms"); - postParagraphGap = addSpinner(optionsPanel, "Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms"); - postSectionGap = addSpinner(optionsPanel, "Default post-section gap:", 0, 5000, 100, getInteger("catenation.post-section"), "ms"); + preChapterGap = addSpinner(optionsPanel, "Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms", "How much room noise to add at the beginning of a chapter."); + postChapterGap = addSpinner(optionsPanel, "Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms", "How much room noise to add to the end of a chapter."); + postSentenceGap = addSpinner(optionsPanel, "Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms", "How much room noise to add between normal sentences."); + shortSentenceGap = addSpinner(optionsPanel, "Short post-sentence gap:", 0, 5000, 100, getInteger("catenation.short-sentence"), "ms", "How much room noise to add between 'continuations'."); + postParagraphGap = addSpinner(optionsPanel, "Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms", "How much room noise to add between paragraphs."); + postSectionGap = addSpinner(optionsPanel, "Default post-section gap:", 0, 5000, 100, getInteger("catenation.post-section"), "ms", "How much room noise to add between sections."); addSeparator(optionsPanel); - ffmpegLocation = addFilePath(optionsPanel, "FFMPEG location:", get("path.ffmpeg"), false); - bitRate = addDropdown(optionsPanel, "Export bitrate:", getBitrates(), get("audio.export.bitrate")); - channels = addDropdown(optionsPanel, "Export channels:", getChannelCountList(), get("audio.export.channels")); - exportRate = addDropdown(optionsPanel, "Export sample rate:", getSampleRateList(), get("audio.export.samplerate")); + ffmpegLocation = addFilePath(optionsPanel, "FFMPEG location:", get("path.ffmpeg"), false, "Path to your ffmpeg executable."); + bitRate = addDropdown(optionsPanel, "Export bitrate:", getBitrates(), get("audio.export.bitrate"), "The MP3 bitrate to produce"); + channels = addDropdown(optionsPanel, "Export channels:", getChannelCountList(), get("audio.export.channels"), "Mono or stereo MP3 production"); + exportRate = addDropdown(optionsPanel, "Export sample rate:", getSampleRateList(), get("audio.export.samplerate"), "Sample frequency of the produced MP3"); addSeparator(optionsPanel); - enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text (**SLOW**)", getBoolean("process.sphinx")); - speechCommand = addTextField(optionsPanel, "Speech to text command (must take 1 filename parameter):", get("process.command")); - workerThreads = addSpinner(optionsPanel, "Worker threads:", 1, 100, 1, getInteger("process.threads"), ""); + enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text (**SLOW**)", getBoolean("process.sphinx"), "This will automatically start recognising the speech in every sentence you record. This can really slow down recording though so it's recommended to leave it turned off and do your recognition afterwards as a batch operation."); + speechCommand = addTextField(optionsPanel, "Speech to text command (must take 1 filename parameter):", get("process.command"), "This specifies what command to run to recognize the speech. This command must take only one parameter, which is the full path of the WAV file. It should return (on standard output) the recognised speech."); + workerThreads = addSpinner(optionsPanel, "Worker threads:", 1, 100, 1, getInteger("process.threads"), "", "How many concurrent threads to run when processing speech. This should ideally be no more than the number of CPU cores you have in your computer."); addSeparator(optionsPanel); - externalEditor = addTextField(optionsPanel, "External Editor Command", get("editor.external")); + externalEditor = addTextField(optionsPanel, "External Editor Command", get("editor.external"), "The program to run when you select 'Open in external editor'."); addSeparator(optionsPanel); - cacheSize = addSpinner(optionsPanel, "Cache size:", 2, 100, 1, getInteger("cache.size"), ""); + cacheSize = addSpinner(optionsPanel, "Cache size:", 2, 100, 1, getInteger("cache.size"), "", "How many phrases to keep cached in memory at once. More gives a smoother editing experience, but you can easily run out of memory if you are not careful."); addSeparator(optionsPanel); tabs.add("Options", new JScrollPane(optionsPanel)); - JPanel effectChains = new JPanel(); - effectChains.setLayout(new BorderLayout()); - JPanel effectDetails = new JPanel() { - public Dimension getPreferredSize() { - return new Dimension(200, 400); - } - }; - DefaultTreeModel m = new DefaultTreeModel(new DefaultMutableTreeNode("Effect Chains")); - - JTree effectChainTree = new JTree(m); - effectChains.add(effectChainTree, BorderLayout.CENTER); - effectChains.add(effectDetails, BorderLayout.EAST); - - tabs.add("Effects Chains", new JScrollPane(effectChains)); JPanel startScript = new JPanel(); startScript.setLayout(new BorderLayout()); + startScript.setBorder(new EmptyBorder(15, 15, 15, 15)); startupScript = new JTextArea(get("scripts.startup")); + startupScript.setBorder(new EmptyBorder(5, 5, 5, 5)); + startupScript.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); startScript.add(startupScript, BorderLayout.CENTER); tabs.add("Startup Script", startScript); - JPanel effects = new JPanel(); - effects.setLayout(new GridBagLayout()); - constraint.gridx = 0; - constraint.gridy = 0; - constraint.gridwidth = 1; - constraint.gridheight = 1; - - etherealOffset = addSpinner(effects, "Ethereal Voice Offset", 0, 2000, 10, getInteger("effects.ethereal.offset"), "ms"); - etherealIterations = addSpinner(effects, "Ethereal Voice Iterations", 1, 10, 1, getInteger("effects.ethereal.iterations"), ""); - etherealAttenuation = addSpinner(effects, "Ethereal Voice Attenuation", 0, 100, 1, getInteger("effects.ethereal.attenuation"), "%"); - - tabs.add("Effects", effects); - JPanel processors = new JPanel(); processors.setLayout(new BorderLayout()); @@ -411,19 +413,16 @@ public class Options extends JDialog { String command = get("editor.processor." + i + ".command"); if (name == null || command == null) break; if (name.equals("") || command.equals("")) break; - JTextField[] f = addTwoField(processorListPanel, name, command); + JTextField[] f = addTwoField(processorListPanel, name, command, "Specify the name of the operation (which will appear in context menus) and the command to run for that operation. The command should have parameters separated with :: and %f for the input filename and %o for the output filename."); processorList.add(f); } - JTextField[] f = addTwoField(processorListPanel, "", ""); + JTextField[] f = addTwoField(processorListPanel, "", "", "Specify the name of the operation (which will appear in context menus) and the command to run for that operation. The command should have parameters separated with :: and %f for the input filename and %o for the output filename."); processorList.add(f); tabs.add("Processors", processors); - - - add(tabs, BorderLayout.CENTER); setTitle("Options"); @@ -608,10 +607,6 @@ public class Options extends JDialog { defaultPrefs.put("scripts.startup", ""); - defaultPrefs.put("effects.ethereal.offset", "50"); - defaultPrefs.put("effects.ethereal.iterations", "3"); - defaultPrefs.put("effects.ethereal.attenuation", "50"); - if (prefs == null) { prefs = Preferences.userNodeForPackage(AudiobookRecorder.class); } @@ -734,10 +729,6 @@ public class Options extends JDialog { set("audio.recording.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key); set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key); - set("effects.ethereal.offset", etherealOffset.getValue()); - set("effects.ethereal.iterations", etherealIterations.getValue()); - set("effects.ethereal.attenuation", etherealAttenuation.getValue()); - set("scripts.startup", startupScript.getText()); int procNo = 0; @@ -832,51 +823,4 @@ public class Options extends JDialog { pairs[7] = new KVPair("131072", "131072"); return pairs; } - - public static void createEffectChains() { - effectChains = new ArrayList(); - - for (int i = 0; i < 999999; i++) { - if (get("effects." + i + ".name") == null) { - EffectGroup e = new EffectGroup(get("effects." + i + ".name")); - for (int j = 0; i < 999999; j++) { - String type = get("effects." + i + ".children." + j + ".type"); - if (type == null) break; - - if (type.equals("biquad")) { - int bqt = getInteger("effects." + i + ".children." + j + ".filtertype"); - double fc = getDouble("effects." + i + ".children." + j + ".fc"); - double q = getDouble("effects." + i + ".children." + j + ".q"); - double gain = getDouble("effects." + i + ".children." + j + ".gain"); - Biquad b = new Biquad(bqt, fc, q, gain); - e.addEffect(b); - continue; - } - - if (type.equals("amplifier")) { - double gain = getDouble("effects." + i + ".children." + j + ".gain"); - Amplifier a = new Amplifier(gain); - e.addEffect(a); - continue; - } - - if (type.equals("delayline")) { - DelayLine l = new DelayLine(); - for (int c = 0; c < 999999; c++) { - if (get("effects." + i + ".children." + j + ".lines." + c + ".samples") == null) break; - int samples = getInteger("effects." + i + ".children." + j + ".lines." + c + ".samples"); - double gain = getDouble("effects." + i + ".children." + j + ".lines." + c + ".gain"); - l.addDelayLine(samples, gain); - } - e.addEffect(l); - continue; - } - - - } - effectChains.add(e); - break; - } - } - } } diff --git a/src/uk/co/majenko/audiobookrecorder/Tip.java b/src/uk/co/majenko/audiobookrecorder/Tip.java new file mode 100644 index 0000000..0729de7 --- /dev/null +++ b/src/uk/co/majenko/audiobookrecorder/Tip.java @@ -0,0 +1,115 @@ +package uk.co.majenko.audiobookrecorder; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JToolTip; +import javax.swing.SwingUtilities; +import java.awt.event.MouseListener; +import java.awt.event.MouseEvent; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Font; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.FontMetrics; +import java.awt.Dimension; +import org.apache.commons.text.WordUtils; + +public class Tip extends JLabel implements MouseListener { + String tip = null; + + public Tip(String text) { + tip = WordUtils.wrap(text, 50); + + setToolTipText(text); + setIcon(Icons.tooltip); + addMouseListener(this); + } + + @Override + public JToolTip createToolTip() { + JToolTip tt = new JToolTip() { + public String getTipText() { + return "*" + tip + "*"; + } + + public void paintComponent(Graphics g) { + + Rectangle r = g.getClipBounds(); + + JLabel l = new JLabel(); + + AffineTransform affinetransform = new AffineTransform(); + FontRenderContext frc = new FontRenderContext(affinetransform,true,true); + Font f = l.getFont().deriveFont(14f); + + g.setColor(new Color(200, 200, 180)); + g.fillRect(0, 0, r.width, r.height); + + g.setColor(new Color(10, 10, 10)); + g.setFont(f); + int y = 3; + String[] lines = tip.split("\n"); + for (String line : lines) { + Rectangle2D bounds = f.getStringBounds(line, frc); + y += bounds.getHeight(); + g.drawString(line, 5, y); + } + + } + + public Dimension getPreferredSize() { + + JLabel l = new JLabel(); + AffineTransform affinetransform = new AffineTransform(); + FontRenderContext frc = new FontRenderContext(affinetransform,true,true); + Font f = l.getFont().deriveFont(14f); + + String[] lines = tip.split("\n"); + int w = 0; + int h = 0; + for (String line : lines) { + Rectangle2D bounds = f.getStringBounds(line, frc); + double fw = bounds.getWidth(); + if (fw > w) w = (int)fw; + h += bounds.getHeight(); + } + + Dimension s = new Dimension(w + 10, h + 10); + return s; + } + }; + + tt.removeAll(); + JPanel p = new JPanel(); + tt.add(p); + JLabel l = new JLabel(tip); + l.setBackground(new Color(200, 200, 180)); + l.setForeground(new Color(0, 0, 0)); + p.add(l); + return tt; + } + + public void mouseEntered(MouseEvent evt) { +// showTipWindow(); + } + + public void mouseExited(MouseEvent evt) { +// hideTipWindow(); + } + + public void mousePressed(MouseEvent evt) { + } + + public void mouseReleased(MouseEvent evt) { + } + + public void mouseClicked(MouseEvent evt) { + } + +}