diff --git a/README.md b/README.md index 589cc20..e330fb0 100644 --- a/README.md +++ b/README.md @@ -30,25 +30,43 @@ Legend: * Mouse Scroll wheel: MScrl * Context any means Name List, Value List or Waveform -| Input | Modifier | Context | Action | -|-----------|----------|----------|-----------------------------------| -| LMB klick | | any | select | -| LMB klick | Shift | Waveform | move selected marker to position | -| LMB klick | Control | Waveform | move cursor to position | -| LMB drag | | Waveform | zoom to range | -| MMB klick | | Waveform | move selected marker to position | -| MScrl | | any | scroll window up/down | -| MScrl | Shift | any | scroll window left/right | -| Key left | | Waveform | scroll window to the left (slow) | -| Key right | | Waveform | scroll window to the right (slow) | -| Key left | Shift | Waveform | scroll window to the left (fast) | -| Key right | Shift | Waveform | scroll window to the right (fast) | -| Key up | | Waveform | move selection up | -| Key down | | Waveform | move selection down | -| Key up | Control | Waveform | move selected track up | -| Key down | Control | Waveform | move selected track down | -| Key + | Control | Waveform | zoom in | -| Key - | Control | Waveform | zoom out | -| Key Pos1 | | Waveform | jump to selected marker | -| Key End | | Waveform | jump to cursor | -| Key Del | | any | delete selected entries | +| Input | Modifier | Context | Action | +|------------|----------|----------|-----------------------------------| +| LMB click | | any | select | +| LMB click | Shift | Waveform | move selected marker to position | +| LMB click | Control | Waveform | move cursor to position | +| LMB drag | | Waveform | zoom to range | +| MMB click | | Waveform | move selected marker to position | +| MScrl | | any | scroll window up/down | +| MScrl | Shift | any | scroll window left/right | +| MScrl | Control | Waveform | zoom in/out | +| Key left | | Waveform | scroll window to the left (slow) | +| Key right | | Waveform | scroll window to the right (slow) | +| Key left | Shift | Waveform | scroll window to the left (fast) | +| Key right | Shift | Waveform | scroll window to the right (fast) | +| Key up | | Waveform | move selection up | +| Key down | | Waveform | move selection down | +| Key up | Control | Waveform | move selected track up | +| Key down | Control | Waveform | move selected track down | +| Key + | Control | Waveform | zoom in | +| Key - | Control | Waveform | zoom out | +| Key Pos1 | | Waveform | jump to selected marker | +| Key End | | Waveform | jump to cursor | +| Key Del | | any | delete selected entries | +| LMB click | | ZoomBar | increment/decrement 1 page | +| LMB drag | | ZoomBar | drag both markers (pan) | +| LMB drag | Control | ZoomBar | drag one marker (zoom) | +| MMB drag | | ZoomBar | drag one marker (zoom) | +| xMB dclick | | ZoomBar | pan to position | +| MScrl | | ZoomBar | scroll window left/right | +| MScrl | Shift | ZoomBar | scroll window left/right double speed | +| MScrl | Control | ZoomBar | zoom in/out | +| Key left | | ZoomBar | scroll window to the left (slow) | +| Key right | | ZoomBar | scroll window to the right (slow) | +| Key up | | ZoomBar | scroll window to the left (slow) | +| Key down | | ZoomBar | scroll window to the right (slow) | +| Key PgUp | | ZoomBar | scroll window to the left (fast) | +| Key PgDown | | ZoomBar | scroll window to the right (fast) | +| Key Pos1 | | ZoomBar | scroll to begin | +| Key End | | ZoomBar | scroll to end | + diff --git a/doc/com.minres.scviewer.doc/.gitignore b/doc/com.minres.scviewer.doc/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/doc/com.minres.scviewer.doc/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/doc/com.minres.scviewer.doc/.project b/doc/com.minres.scviewer.doc/.project new file mode 100644 index 0000000..f250ef1 --- /dev/null +++ b/doc/com.minres.scviewer.doc/.project @@ -0,0 +1,11 @@ + + + com.minres.scviewer.doc + + + + + + + + diff --git a/doc/com.minres.scviewer.doc/pom.xml b/doc/com.minres.scviewer.doc/pom.xml new file mode 100644 index 0000000..23cab87 --- /dev/null +++ b/doc/com.minres.scviewer.doc/pom.xml @@ -0,0 +1,168 @@ + + 4.0.0 + com.minres.scviewer.doc + 1.0.0-SNAPSHOT + pom + + com.minres.scviewer + com.minres.scviewer.parent + 2.16.0 + ../.. + + + + UTF-8 + 2.0.0 + 1.6.2 + ../../plugins/com.minres.scviewer.e4.application.help + + + + + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor.maven.plugin.version} + + + org.asciidoctor + asciidoctorj-pdf + ${asciidoctorj.pdf.version} + + + + src/asciidoc + SCViewerHelp.adoc + true + + + + output-html + generate-resources + + process-asciidoc + + + coderay + html + + + false + + + + + output-docbook + generate-resources + + process-asciidoc + + + docbook + + + + output-pdf + generate-resources + + process-asciidoc + + + pdf + coderay + + font + + + + - + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.6 + + + copy-asciidoc-resources + generate-resources + + copy-resources + + + + + target/generated-docs/ + + SCViewerHelp.xml + **/*.jpg + **/*.png + **/*.svg + + + + src/docbkx + + + + + + com.agilejava.docbkx + docbkx-maven-plugin + 2.0.17 + + + + generate-resources + + generate-eclipse + + + + + + org.docbook + docbook-xml + 4.4 + runtime + + + + src/docbkx + ${help.plugin.target.dir} + + + + + + + + + ./ + + 1 + 1 + java + 1 + A4 + + + + + css/narrow_style.css + + SCViewerHelp.xml + true + true + + com.minres.scviewer.e4.application.help + + + + + diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/Overview.adoc b/doc/com.minres.scviewer.doc/src/asciidoc/Overview.adoc new file mode 100644 index 0000000..14dbff3 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/asciidoc/Overview.adoc @@ -0,0 +1,25 @@ +[#_introduction] +== Introduction + +[#_overview] +=== SCViewer overview + +SCViewer is composed of a set of eclipse plugins to display VCD and transaction streams +created by the SystemC VCD trace implementation and the SystemC Verification Library (SCV). +For further description of the SCV please refer to +http://www.accellera.org/activities/committees/systemc-verification. + + +[#_features] +=== SCViewer features + +Features include: + +* support of VCD files (compressed and uncompressed) +** real numbers +** showing vectors and real numbers as analog (step-wise & continuous) +* various value representations of bit vectors +* support of SCV transaction recordings in various formats +** text log files (compressed and uncompressed) +** sqlite based +** visualization of transaction relations diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/Reference.adoc b/doc/com.minres.scviewer.doc/src/asciidoc/Reference.adoc new file mode 100644 index 0000000..d32f393 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/asciidoc/Reference.adoc @@ -0,0 +1,55 @@ +[#_reference] +== Reference + +In this section you will find detailed descriptions of all GUI and menu elements of the SCViewer including their functions and keyboard shortcuts. + +[#_keybindings] +=== Key Shortcuts + +Legend: + +* Left Mouse Button: LMB +* Middle Mouse Button: MMB +* Mouse Scroll wheel: MScrl +* Context any means Name List, Value List or Waveform + +[cols="1,1,1,4",options="header"] +|=== +| Input | Modifier | Context | Action +| LMB click | | any | select +| LMB click | Shift | Waveform | move selected marker to position +| LMB click | Control | Waveform | move cursor to position +| LMB drag | | Waveform | zoom to range +| MMB click | | Waveform | move selected marker to position +| MScrl | | any | scroll window up/down +| MScrl | Shift | any | scroll window left/right +| Key left | | Waveform | scroll window to the left (slow) +| Key right | | Waveform | scroll window to the right (slow) +| Key left | Shift | Waveform | scroll window to the left (fast) +| Key right | Shift | Waveform | scroll window to the right (fast) +| Key up | | Waveform | move selection up +| Key down | | Waveform | move selection down +| Key up | Control | Waveform | move selected track up +| Key down | Control | Waveform | move selected track down +| Key + | Control | Waveform | zoom in +| Key - | Control | Waveform | zoom out +| Key Pos1 | | Waveform | jump to selected marker +| Key End | | Waveform | jump to cursor +| Key Del | | any | delete selected entries +| LMB click | | ZoomBar | increment/decrement 1 page +| LMB drag | | ZoomBar | drag both markers (pan) +| LMB drag | Control | ZoomBar | drag one marker (zoom) +| MMB drag | | ZoomBar | drag one marker (zoom) +| xMB dclick | | ZoomBar | pan to position +| MScrl | | ZoomBar | scroll window left/right +| MScrl | Shift | ZoomBar | scroll window left/right double speed +| MScrl | Control | ZoomBar | zoom in/out +| Key left | | ZoomBar | scroll window to the left (slow) +| Key right | | ZoomBar | scroll window to the right (slow) +| Key up | | ZoomBar | scroll window to the left (slow) +| Key down | | ZoomBar | scroll window to the right (slow) +| Key PgUp | | ZoomBar | scroll window to the left (fast) +| Key PgDown | | ZoomBar | scroll window to the right (fast) +| Key Pos1 | | ZoomBar | scroll to begin +| Key End | | ZoomBar | scroll to end +|=== diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/SCViewerHelp.adoc b/doc/com.minres.scviewer.doc/src/asciidoc/SCViewerHelp.adoc new file mode 100644 index 0000000..279c0d0 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/asciidoc/SCViewerHelp.adoc @@ -0,0 +1,39 @@ +[#_start] += SCViewer User Guide +:title-logo-image: image:Minres_logo_docs.png[width=750, align="right"] +:doctype: book +:source-highlighter: coderay +:coderay-linenums-mode: inline +:coderay-css: class +:listing-caption: Listing +:icons: font +//add table-of-contents (toc) and set its depth +:toc: +:toclevels: 3 +:data-uri: +:sectnums: +:toc-title: Contents +:homepage: https://www.minres.com/ +:keywords: +:title-page: +:xrefstyle: short +:table-caption: Table +:figure-caption: Figure +:appendix-caption: Appendix +:section-refsig: Chapter +//set directories +:imagesdir: ./images +:iconsdir: ./icons +:stylesdir: ./styles +:scriptsdir: ./js +:pdf-themesdir: ./themes +:pdf-theme: mnrs-doc +:pdf-fontsdir: ./fonts + + +// unset toc, otherwise it appears in table cells -> known bug, should be fixed in later versions! +:toc!: + +include::Overview.adoc[] + +include::Reference.adoc[] diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/OFL.txt b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/OFL.txt new file mode 100644 index 0000000..4a44b9b --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2009-2011 by Accademia di Belle Arti di Urbino and students of MA course of Visual design. Some rights reserved. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Black.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Black.ttf new file mode 100644 index 0000000..ec5b093 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Black.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Bold.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Bold.ttf new file mode 100644 index 0000000..b51a4d6 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Bold.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-BoldItalic.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-BoldItalic.ttf new file mode 100644 index 0000000..d0fe23b Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-BoldItalic.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLight.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLight.ttf new file mode 100644 index 0000000..a590b73 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLight.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLightItalic.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLightItalic.ttf new file mode 100644 index 0000000..8fe0256 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-ExtraLightItalic.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Italic.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Italic.ttf new file mode 100644 index 0000000..266d5cb Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Italic.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Light.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Light.ttf new file mode 100644 index 0000000..fbba05d Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Light.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-LightItalic.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-LightItalic.ttf new file mode 100644 index 0000000..3783f8d Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-LightItalic.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Regular.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Regular.ttf new file mode 100644 index 0000000..a54ad4b Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-Regular.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBold.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBold.ttf new file mode 100644 index 0000000..49109f8 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBold.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBoldItalic.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBoldItalic.ttf new file mode 100644 index 0000000..22243ff Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/TitilliumWeb-SemiBoldItalic.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l001-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l001-webfont.ttf new file mode 100644 index 0000000..9fc52e5 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l001-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l002-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l002-webfont.ttf new file mode 100644 index 0000000..b05b52d Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l002-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003-webfont.ttf new file mode 100644 index 0000000..26e2d68 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003.ttf new file mode 100644 index 0000000..1df2687 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l003.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l004-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l004-webfont.ttf new file mode 100644 index 0000000..fa1ee55 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l004-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l005-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l005-webfont.ttf new file mode 100644 index 0000000..901be70 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l005-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l006-webfont.ttf b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l006-webfont.ttf new file mode 100644 index 0000000..5adb209 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/fonts/titilliumtext22l006-webfont.ttf differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo.png b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo.png new file mode 100644 index 0000000..35240a8 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo.png differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_docs.png b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_docs.png new file mode 100644 index 0000000..4cc6339 Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_docs.png differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_square.png b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_square.png new file mode 100644 index 0000000..981da5e Binary files /dev/null and b/doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo_square.png differ diff --git a/doc/com.minres.scviewer.doc/src/asciidoc/themes/mnrs-doc-theme.yml b/doc/com.minres.scviewer.doc/src/asciidoc/themes/mnrs-doc-theme.yml new file mode 100644 index 0000000..9446bfe --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/asciidoc/themes/mnrs-doc-theme.yml @@ -0,0 +1,55 @@ +page: + layout: portrait + margin: [2.3cm, 2cm, 2cm, 2.2cm] + size: A4 +base: + font-color: #000000 + font-color-mnrs-grey: #6a747c + font-color-mnrs-blue: #197788 + font-family: titillium + font-size: 12 + line-height-length: 16 + line-height: $base-line-height-length / $base-font-size + align: justify + vertical-spacing: $base-line-height-length +heading: + font-color: $base-font-color-mnrs-grey + font-size: $base-font-size * 1.25 + font-style: bold + line-height: $base-line-height * 1.2 + margin-bottom: $vertical-spacing +link: + font-color: $base_font-color-mnrs-blue +outline-list: + indent: $base-font-size * 1.5 +footer: + height: $base-line-height-length * 3.0 + font-color: $base-font-color-mnrs-grey + font-size: $base-font-size * 0.9 + line-height: 1 + recto: + left: + content: '{description} v{revision}, © 2021 MINRES' + right: + content: '{page-number}' + verso: + left: + content: $footer_recto_right_content + right: + content: $footer_recto_left_content +table: + border_color: $base-font-color + border_width: 0.1 +title-page: + align: right + font-color: $base-font-color-mnrs-grey + font-size: $base-font-size * 1.80 + font-style: bold +font: + fallbacks: titilliumtext22l002-webfont.ttf + catalog: + titillium: + normal: titilliumtext22l002-webfont.ttf + bold: titilliumtext22l005-webfont.ttf + italic: TitilliumWeb-Italic.ttf + bold_italic: TitilliumWeb-BoldItalic.ttf diff --git a/doc/com.minres.scviewer.doc/src/docbkx/.gitignore b/doc/com.minres.scviewer.doc/src/docbkx/.gitignore new file mode 100644 index 0000000..467e3a2 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/docbkx/.gitignore @@ -0,0 +1 @@ +/SCViewerHelp.xml diff --git a/doc/com.minres.scviewer.doc/src/docbkx/css/narrow_style.css b/doc/com.minres.scviewer.doc/src/docbkx/css/narrow_style.css new file mode 100644 index 0000000..e3ffd53 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/docbkx/css/narrow_style.css @@ -0,0 +1,124 @@ +P.Code { + display: block; + text-align: left; + text-indent: 0.00pt; + margin-top: 0.000000pt; + margin-bottom: 0.000000pt; + margin-right: 0.000000pt; + margin-left: 1.5em; + font-size: 100%; + font-weight: medium; + font-style: Regular; + color: #4444CC; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Courier New"; +} +H6.CaptionFigColumn { + display: block; + text-align: left; + text-indent: 0.000000pt; + margin-top: 0.3em; + margin-bottom: 1.1em; + margin-right: 0.000000pt; + margin-left: 0.000000pt; + font-size: 90%; + font-weight: medium; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Arial"; +} +P.Note { + display: block; + text-align: left; + text-indent: 0pt; + margin-top: 1.95em; + margin-bottom: 1.95em; + margin-right: 0.000000pt; + margin-left: 3.0em; + font-size: 110%; + font-weight: medium; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Arial"; +} +EM.UILabel { + font-weight: Bold; + font-style: Regular; + text-decoration: none; + vertical-align: baseline; + text-transform: none; +} +EM.CodeName { + font-weight: Bold; + font-style: Regular; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family:"Courier New"; +} + + + +body, html { border: 0px } + +/* following font face declarations need to be removed for DBCS */ + +body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font: message-box; color: #000000} +pre { font-family: Courier, monospace} + +/* end font face declarations */ + +/* following font size declarations should be OK for DBCS */ +body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font: message-box; } +pre { font-size: 100% } +code,samp { font-size: 100%; } + +/* end font size declarations */ + +body { background: #FFFFFF} +h1 { font-size: 180%; font-weight: medium; margin-top: 0.28em; margin-bottom: 0.05em; color: Highlight } +h2 { font-size: 140%; font-weight: bold; margin-top: 0.22em; margin-bottom: 3; color: Highlight } +h3 { font-size: 110%; font-weight: bold; margin-top: 0.18em; margin-bottom: 3 } +h4 { font-size: 100%; font-weight: bold; margin-top: 0.2em; margin-bottom: 3; font-style: italic } +p { margin-top: 1.0em; margin-bottom: 1.0em } +pre { margin-left: 6; font-size: 90% } +a:link { color: #0000FF } +a:hover { color: #000080 } +a:visited { text-decoration: underline } +ul { margin-top: 0; + margin-bottom: 1.0em; + margin-left : 1.0em; + padding-left: 0; + } +li { margin-top: 0; + margin-bottom: 0; + padding-left: 0; + margin-left: 0; + } +li p { margin-top: 0; margin-bottom: 0 } +ol { margin-top: 0; + margin-bottom: 10; + padding-left: 0; + margin-left: 1.4em } +dl { margin-top: 0; margin-bottom: 10 } +dt { margin-top: 0; margin-bottom: 0; font-weight: bold } +dd { margin-top: 0; margin-bottom: 0 } +strong { font-weight: bold} +em { font-style: italic} +var { font-style: italic} +div.revision { border-left-style: solid; border-left-width: thin; + border-left-color: #7B68EE; padding-left:5 } +th { font-weight: bold } + +.figure-contents .mediaobject img { + width: 100%; + heigth: auto; +} diff --git a/doc/com.minres.scviewer.doc/src/docbkx/css/style.css b/doc/com.minres.scviewer.doc/src/docbkx/css/style.css new file mode 100644 index 0000000..9cbd9bc --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/docbkx/css/style.css @@ -0,0 +1,108 @@ +P.Code { + display: block; + text-align: left; + text-indent: 0.00pt; + margin-top: 0.000000pt; + margin-bottom: 0.000000pt; + margin-right: 0.000000pt; + margin-left: 15pt; + font-weight: normal; + font-style: normal; + color: #4444CC; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Courier New", Courier, monospace; +} +H6.CaptionFigColumn { + display: block; + text-align: left; + text-indent: 0.000000pt; + margin-top: 3.000000pt; + margin-bottom: 11.000000pt; + margin-right: 0.000000pt; + margin-left: 0.000000pt; + font-size: 75%; + font-weight: bold; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; +} +P.Note { + display: block; + text-align: left; + text-indent: 0pt; + margin-top: 19.500000pt; + margin-bottom: 19.500000pt; + margin-right: 0.000000pt; + margin-left: 30pt; + font-size: 110%; + font-weight: normal; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; +} +EM.UILabel { + font-weight: Bold; + font-style: normal; + text-decoration: none; + vertical-align: baseline; + text-transform: none; +} +EM.CodeName { + font-weight: Bold; + font-style: normal; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Courier New", Courier, monospace; +} +UL.NavList { + margin-left: 1.5em; + padding-left: 0px; + list-style-type: none; +} + +body, html { border: 0px } + + +/* following font face declarations need to be removed for DBCS */ + +body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font-family: Arial, Helvetica, sans-serif; color: #000000} +pre, code { font-family: "Courier New", Courier, monospace;} + +/* end font face declarations */ + +@media print { + html { font-size: 12pt } +} + +body { font-size: 83%; background: #FFFFFF; margin-bottom: 1em } +h1 { font-size: 180%; margin-top: 5px; margin-bottom: 1px } +h2 { font-size: 140%; margin-top: 25px; margin-bottom: 3px } +h3 { font-size: 110%; margin-top: 20px; margin-bottom: 3px } +h4 { font-size: 100%; margin-top: 20px; margin-bottom: 3px; font-style: italic } +p { margin-top: 10px; margin-bottom: 10px } +pre { font-size: 93%; margin-left: 6; color: #4444CC } +code { font-size: 93%; } +table { font-size: 100% } /* needed for quirks mode */ +a:link { color: #0000FF } +a:hover { color: #000080 } +a:visited { text-decoration: underline } +ul { margin-top: 10px; margin-bottom: 10px; } +li { margin-top: 5px; margin-bottom: 5px; } +li p { margin-top: 5px; margin-bottom: 5px; } +ol { margin-top: 10px; margin-bottom: 10px; } +dl { margin-top: 10px; margin-bottom: 10px; } +dt { margin-top: 5px; margin-bottom: 5px; font-weight: bold; } +dd { margin-top: 5px; margin-bottom: 5px; } +strong { font-weight: bold} +em { font-style: italic} +var { font-style: italic} +div.revision { border-left-style: solid; border-left-width: thin; + border-left-color: #7B68EE; padding-left:5 } +th { font-weight: bold } diff --git a/doc/com.minres.scviewer.doc/src/docbkx/images/.gitignore b/doc/com.minres.scviewer.doc/src/docbkx/images/.gitignore new file mode 100644 index 0000000..b44ef38 --- /dev/null +++ b/doc/com.minres.scviewer.doc/src/docbkx/images/.gitignore @@ -0,0 +1 @@ +/*.png diff --git a/features/com.minres.scviewer.database.feature/pom.xml b/features/com.minres.scviewer.database.feature/pom.xml index 034912f..b5553f2 100644 --- a/features/com.minres.scviewer.database.feature/pom.xml +++ b/features/com.minres.scviewer.database.feature/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 3.0.0-SNAPSHOT diff --git a/features/com.minres.scviewer.e4.feature/pom.xml b/features/com.minres.scviewer.e4.feature/pom.xml index 7dc7611..680e93f 100644 --- a/features/com.minres.scviewer.e4.feature/pom.xml +++ b/features/com.minres.scviewer.e4.feature/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 1.1.0-SNAPSHOT diff --git a/features/com.minres.scviewer.e4.help.feature/.gitignore b/features/com.minres.scviewer.e4.help.feature/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/features/com.minres.scviewer.e4.help.feature/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/features/com.minres.scviewer.e4.help.feature/.project b/features/com.minres.scviewer.e4.help.feature/.project new file mode 100644 index 0000000..5f245e2 --- /dev/null +++ b/features/com.minres.scviewer.e4.help.feature/.project @@ -0,0 +1,17 @@ + + + com.minres.scviewer.e4.help.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/com.minres.scviewer.e4.help.feature/build.properties b/features/com.minres.scviewer.e4.help.feature/build.properties new file mode 100644 index 0000000..64f93a9 --- /dev/null +++ b/features/com.minres.scviewer.e4.help.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/features/com.minres.scviewer.e4.help.feature/feature.xml b/features/com.minres.scviewer.e4.help.feature/feature.xml new file mode 100644 index 0000000..ffba2a7 --- /dev/null +++ b/features/com.minres.scviewer.e4.help.feature/feature.xml @@ -0,0 +1,207 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/features/com.minres.scviewer.e4.help.feature/pom.xml b/features/com.minres.scviewer.e4.help.feature/pom.xml new file mode 100644 index 0000000..b011cb8 --- /dev/null +++ b/features/com.minres.scviewer.e4.help.feature/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + com.minres.scviewer.e4.help.feature + eclipse-feature + + com.minres.scviewer + com.minres.scviewer.parent + 2.16.0 + ../.. + + 1.0.0-SNAPSHOT + diff --git a/features/com.minres.scviewer.e4.platform.feature/pom.xml b/features/com.minres.scviewer.e4.platform.feature/pom.xml index 734d0f2..e54aa8e 100644 --- a/features/com.minres.scviewer.e4.platform.feature/pom.xml +++ b/features/com.minres.scviewer.e4.platform.feature/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 1.0.0-SNAPSHOT diff --git a/features/com.minres.scviewer.feature/pom.xml b/features/com.minres.scviewer.feature/pom.xml index 904e438..c4ef4d3 100644 --- a/features/com.minres.scviewer.feature/pom.xml +++ b/features/com.minres.scviewer.feature/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 1.1.0-SNAPSHOT diff --git a/features/com.minres.scviewer.ui.feature/pom.xml b/features/com.minres.scviewer.ui.feature/pom.xml index 9f65328..6ff0b7a 100644 --- a/features/com.minres.scviewer.ui.feature/pom.xml +++ b/features/com.minres.scviewer.ui.feature/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 1.1.0-SNAPSHOT diff --git a/plugins/com.minres.scviewer.database.sqlite/pom.xml b/plugins/com.minres.scviewer.database.sqlite/pom.xml index 9ffe5b1..707af5c 100644 --- a/plugins/com.minres.scviewer.database.sqlite/pom.xml +++ b/plugins/com.minres.scviewer.database.sqlite/pom.xml @@ -4,7 +4,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.database.text/META-INF/MANIFEST.MF b/plugins/com.minres.scviewer.database.text/META-INF/MANIFEST.MF index 6de81a4..a6887f6 100644 --- a/plugins/com.minres.scviewer.database.text/META-INF/MANIFEST.MF +++ b/plugins/com.minres.scviewer.database.text/META-INF/MANIFEST.MF @@ -9,7 +9,8 @@ Import-Package: org.osgi.framework;version="1.3.0" Require-Bundle: com.minres.scviewer.database, org.eclipse.osgi.services;bundle-version="3.4.0", com.google.guava;bundle-version="15.0.0", - org.eclipse.collections;bundle-version="10.4.0" + org.eclipse.collections;bundle-version="10.4.0", + org.apache.commons.compress;bundle-version="1.20.0" Service-Component: OSGI-INF/component.xml Bundle-ActivationPolicy: lazy Automatic-Module-Name: com.minres.scviewer.database.text diff --git a/plugins/com.minres.scviewer.database.text/pom.xml b/plugins/com.minres.scviewer.database.text/pom.xml index f96e290..06fcec1 100644 --- a/plugins/com.minres.scviewer.database.text/pom.xml +++ b/plugins/com.minres.scviewer.database.text/pom.xml @@ -6,7 +6,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java index 16fcf6e..95e616e 100644 --- a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java +++ b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java @@ -13,6 +13,7 @@ package com.minres.scviewer.database.text; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -33,6 +34,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream; import org.eclipse.collections.impl.map.mutable.UnifiedMap; import org.mapdb.DB; import org.mapdb.DBMaker; @@ -56,6 +58,8 @@ import com.minres.scviewer.database.tx.ITx; */ public class TextDbLoader implements IWaveformDbLoader { + enum FileType { NONE, PLAIN, GZIP, LZ4}; + /** the file size limit of a zipped txlog where the loader starts to use a file mapped database */ private static final long MEMMAP_LIMIT=256l*1024l*1024l; @@ -190,8 +194,9 @@ public class TextDbLoader implements IWaveformDbLoader { @Override public boolean canLoad(File inputFile) { if (!inputFile.isDirectory() && inputFile.exists()) { - boolean gzipped = isGzipped(inputFile); - try(InputStream stream = gzipped ? new GZIPInputStream(new FileInputStream(inputFile)) : new FileInputStream(inputFile)){ + FileType fType = getFileType(inputFile); + try(InputStream stream = fType==FileType.GZIP ? new GZIPInputStream(new FileInputStream(inputFile)) : + fType==FileType.LZ4? new FramedLZ4CompressorInputStream(new FileInputStream(inputFile)) : new FileInputStream(inputFile)){ byte[] buffer = new byte[x.length]; int readCnt = stream.read(buffer, 0, x.length); if (readCnt == x.length) { @@ -213,13 +218,18 @@ public class TextDbLoader implements IWaveformDbLoader { * @param f the f * @return true, if is gzipped */ - private static boolean isGzipped(File f) { + private static FileType getFileType(File f) { try (InputStream is = new FileInputStream(f)) { - byte[] signature = new byte[2]; + byte[] signature = new byte[4]; int nread = is.read(signature); // read the gzip signature - return nread == 2 && signature[0] == (byte) 0x1f && signature[1] == (byte) 0x8b; + if(nread > 2 && signature[0] == (byte) 0x1f && signature[1] == (byte) 0x8b) + return FileType.GZIP; + else if(nread>4 && signature[0] == (byte) 0x04 && signature[1] == (byte) 0x22 && signature[2] == (byte) 0x4d && signature[3] == (byte) 0x18) + return FileType.LZ4; + else + return FileType.PLAIN; } catch (IOException e) { - return false; + return FileType.NONE; } } @@ -235,8 +245,8 @@ public class TextDbLoader implements IWaveformDbLoader { @Override public void load(IWaveformDb db, File file) throws InputFormatException { dispose(); - boolean gzipped = isGzipped(file); - if (file.length() < MEMMAP_LIMIT * (gzipped ? 1 : 10) + FileType fType = getFileType(file); + if (file.length() < MEMMAP_LIMIT * (fType!=FileType.PLAIN ? 1 : 10) || "memory".equals(System.getProperty("ScvBackingDB", "file"))) mapDb = DBMaker.memoryDirectDB().make(); else { @@ -256,7 +266,8 @@ public class TextDbLoader implements IWaveformDbLoader { try { parser.txSink = mapDb.hashMap("transactions", Serializer.LONG, Serializer.JAVA).create(); - parser.parseInput(gzipped ? new GZIPInputStream(new FileInputStream(file)) : new FileInputStream(file)); + InputStream is = new BufferedInputStream(new FileInputStream(file)); + parser.parseInput(fType==FileType.GZIP ? new GZIPInputStream(is) : fType==FileType.LZ4? new FramedLZ4CompressorInputStream(is) : is); transactions = parser.txSink; } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException e) { } catch (Exception e) { diff --git a/plugins/com.minres.scviewer.database.ui.swt/pom.xml b/plugins/com.minres.scviewer.database.ui.swt/pom.xml index 95a4bcf..f38087c 100644 --- a/plugins/com.minres.scviewer.database.ui.swt/pom.xml +++ b/plugins/com.minres.scviewer.database.ui.swt/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. 4.0.0-SNAPSHOT diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/DatabaseUiPlugin.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/DatabaseUiPlugin.java index 98aa447..0d8b315 100644 --- a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/DatabaseUiPlugin.java +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/DatabaseUiPlugin.java @@ -13,6 +13,7 @@ package com.minres.scviewer.database.ui.swt; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Status; +import org.eclipse.wb.swt.SWTResourceManager; import org.osgi.framework.BundleContext; public class DatabaseUiPlugin extends Plugin { @@ -24,6 +25,7 @@ public class DatabaseUiPlugin extends Plugin { @Override public void stop(BundleContext context) throws Exception { + SWTResourceManager.dispose(); getLog().log(new Status(IStatus.OK, "org.eclipse.e4.core", "Stopping org.eclipse.e4.core bundle...")); } } \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/HorizontalSpinner.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/HorizontalSpinner.java new file mode 100644 index 0000000..521bb8d --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/HorizontalSpinner.java @@ -0,0 +1,1113 @@ +package com.minres.scviewer.database.ui.swt.internal; + +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Text; + +/** + * Instances of this class are selectable user interface objects that allow the + * user to enter and modify numeric values. + *

+ *

+ *
Styles:
+ *
READ_ONLY, FLAT
+ *
Events:
+ *
Selection, Modify
+ *
+ *

+ */ +public class HorizontalSpinner extends Composite { + + private enum ALIGNMENT { + LEFT, RIGHT, BOTH + }; + + private final List modifyListeners = new ArrayList(); + + private Button leftButton; + private Button rightButton; + private Text text; + private int digits = 0; + private int increment = 1; + private int maximum = 0; + private int minimum = 255; + private int pageIncrement = 10; + private int storedValue = 0; + private ALIGNMENT alignment = ALIGNMENT.BOTH; + + private final char decimalFormatSeparator; + + /** + * Constructs a new instance of this class given its parent and a style + * value describing its behavior and appearance. + *

+ * The style value is either one of the style constants defined in class + * SWT which is applicable to instances of this class, or must + * be built by bitwise OR'ing together (that is, using the + * int "|" operator) two or more of those SWT + * style constants. The class description lists the style constants that are + * applicable to the class. Style bits are also inherited from superclasses. + *

+ * + * @param parent a composite control which will be the parent of the new + * instance (cannot be null) + * @param style the style of control to construct + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see SWT#READ_ONLY + * @see SWT#FLAT + */ + public HorizontalSpinner(final Composite parent, final int style) { + super(parent, style); + + if ((style & SWT.LEFT) == SWT.LEFT) { + alignment = ALIGNMENT.LEFT; + } + + if ((style & SWT.RIGHT) == SWT.RIGHT) { + alignment = ALIGNMENT.RIGHT; + } + + final GridLayout gd = new GridLayout(3, false); + gd.horizontalSpacing = gd.verticalSpacing = 0; + gd.marginWidth = gd.marginHeight = 0; + setLayout(gd); + + createContent(style); + addTextListeners(); + addButtonsListener(); + addModifyListeners(); + + decimalFormatSeparator = new DecimalFormatSymbols().getDecimalSeparator(); + } + + /** + * Create the content of the widget + * + * @param style style of the widget + */ + private void createContent(final int style) { + final boolean readOnly = (style & SWT.READ_ONLY) == SWT.READ_ONLY; + final boolean flat = (style & SWT.FLAT) == SWT.FLAT; + final int buttonStyle = SWT.ARROW | (flat ? SWT.FLAT : SWT.NONE); + + if (alignment == ALIGNMENT.BOTH) { + createMinusButton(buttonStyle); + createText(readOnly); + createPlusButton(buttonStyle); + } else if (alignment == ALIGNMENT.LEFT) { + createMinusButton(buttonStyle); + createPlusButton(buttonStyle); + createText(readOnly); + } else { + createText(readOnly); + createMinusButton(buttonStyle); + createPlusButton(buttonStyle); + } + } + + /** + * Create minus button + * + * @param buttonStyle button style + */ + private void createMinusButton(final int buttonStyle) { + leftButton = new Button(this, buttonStyle | SWT.LEFT); + leftButton.setFont(getFont()); + leftButton.setBackground(getBackground()); + leftButton.setCursor(getCursor()); + leftButton.setEnabled(getEnabled()); + leftButton.setFont(getFont()); + leftButton.setForeground(getForeground()); + leftButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false)); + } + + /** + * Create the text zone + * + * @param readOnly if true, the text is read only + */ + private void createText(final boolean readOnly) { + text = new Text(this, readOnly ? SWT.READ_ONLY : SWT.NONE); + final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false); + gd.minimumWidth = 40; + text.setLayoutData(gd); + } + + /** + * Create plus button + * + * @param buttonStyle button style + */ + private void createPlusButton(final int buttonStyle) { + rightButton = new Button(this, buttonStyle | SWT.RIGHT); + rightButton.setFont(getFont()); + rightButton.setBackground(getBackground()); + rightButton.setCursor(getCursor()); + rightButton.setEnabled(getEnabled()); + rightButton.setFont(getFont()); + rightButton.setForeground(getForeground()); + rightButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false)); + } + + /** + * Add the text listeners + */ + private void addTextListeners() { + text.addListener(SWT.Verify, e -> { + if (e.character != 0 && !(Character.isDigit(e.character) || e.character == '-') && e.keyCode != SWT.BS && e.keyCode != SWT.DEL) { + e.doit = false; + return; + } + e.doit = verifyEntryAndStoreValue(e.text, e.keyCode); + }); + + text.addListener(SWT.KeyUp, e -> { + if (e.keyCode == SWT.ARROW_UP) { + increaseValue(increment); + } + if (e.keyCode == SWT.ARROW_DOWN) { + decreaseValue(increment); + } + if (e.keyCode == SWT.PAGE_UP) { + increaseValue(pageIncrement); + } + if (e.keyCode == SWT.PAGE_DOWN) { + decreaseValue(pageIncrement); + } + + }); + + text.addListener(SWT.FocusOut, e -> { + if (text.getText().trim().equals("")) { + setSelection(storedValue); + } + }); + } + + /** + * Verify the entry and store the value in the field storedValue + * + * @param entry entry to check + * @param keyCode code of the typed key + * @return true if the entry if correct, false + * otherwise + */ + private boolean verifyEntryAndStoreValue(final String entry, final int keyCode) { + + return true; + } + + /** + * Add the listener to the buttons + */ + private void addButtonsListener() { + leftButton.addListener(SWT.Selection, e -> { + decreaseValue(increment); + }); + + rightButton.addListener(SWT.Selection, e -> { + increaseValue(increment); + }); + + } + + /** + * Increase the value stored in this snippet + * + * @param value value to increase + */ + private void increaseValue(final int value) { + setSelection(getSelection() + value); + + } + + /** + * Decrease the value stored in this snippet + * + * @param value value to decrease + */ + private void decreaseValue(final int value) { + setSelection(getSelection() - value); + } + + /** + * Add the modify listeners + */ + private void addModifyListeners() { + text.addModifyListener(e -> { + for (final ModifyListener m : modifyListeners) { + m.modifyText(e); + } + }); + + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the receiver's text is modified, by sending it one of the messages + * defined in the ModifyListener interface. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see ModifyListener + * @see #removeModifyListener + * @see org.eclipse.swt.widgets.Spinner#addModifyListener(org.eclipse.swt.events.ModifyListener) + */ + + public void addModifyListener(final ModifyListener listener) { + checkWidget(); + modifyListeners.add(listener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the control is selected by the user, by sending it one of the + * messages defined in the SelectionListener interface. + *

+ * widgetSelected is not called for texts. + * widgetDefaultSelected is typically called when ENTER is + * pressed in a single-line text. + *

+ * + * @param listener the listener which should be notified when the control is + * selected by the user + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ + public void addSelectionListener(final SelectionListener listener) { + checkWidget(); + } + + /** + * Copies the selected text. + *

+ * The current selection is copied to the clipboard. + *

+ * + * @exception SWTException + * + */ + public void copy() { + checkWidget(); + text.copy(); + } + + /** + * Cuts the selected text. + *

+ * The current selection is first copied to the clipboard and then deleted + * from the widget. + *

+ * + * @exception SWTException + * + */ + public void cut() { + checkWidget(); + text.cut(); + } + + /** + * Returns the number of decimal places used by the receiver. + * + * @return the digits + * + * @exception SWTException + * + */ + public int getDigits() { + checkWidget(); + return digits; + } + + /** + * Returns the amount that the receiver's value will be modified by when the + * up/down arrows are pressed. + * + * @return the increment + * + * @exception SWTException + * + */ + public int getIncrement() { + checkWidget(); + return increment; + } + + /** + * Returns the maximum value which the receiver will allow. + * + * @return the maximum + * + * @exception SWTException + * + */ + public int getMaximum() { + checkWidget(); + return maximum; + } + + /** + * Returns the minimum value which the receiver will allow. + * + * @return the minimum + * + * @exception SWTException + * + */ + public int getMinimum() { + checkWidget(); + return minimum; + } + + /** + * Returns the amount that the receiver's position will be modified by when + * the page up/down keys are pressed. + * + * @return the page increment + * + * @exception SWTException + * + */ + public int getPageIncrement() { + checkWidget(); + return pageIncrement; + } + + /** + * Returns the selection, which is the receiver's position. + * + * @return the selection + * + * @exception SWTException + * + */ + public int getSelection() { + checkWidget(); + return storedValue; + } + + /** + * Returns a string containing a copy of the contents of the receiver's text + * field, or an empty string if there are no contents. + * + * @return the receiver's text + * + * @exception SWTException + * + * + */ + public String getText() { + checkWidget(); + return text.getText(); + } + + /** + * Returns the maximum number of characters that the receiver's text field + * is capable of holding. If this has not been changed by + * setTextLimit(), it will be the constant + * Spinner.LIMIT. + * + * @return the text limit + * + * @exception SWTException + * + * + * @see #LIMIT + */ + public int getTextLimit() { + checkWidget(); + return text.getTextLimit(); + } + + /** + * Pastes text from clipboard. + *

+ * The selected text is deleted from the widget and new text inserted from + * the clipboard. + *

+ * + * @exception SWTException + * + */ + public void paste() { + checkWidget(); + text.paste(); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the receiver's text is modified. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see ModifyListener + * @see #addModifyListener + */ + public void removeModifyListener(final ModifyListener listener) { + checkWidget(); + modifyListeners.remove(listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the control is selected by the user. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(final SelectionListener listener) { + checkWidget(); + } + + /** + * Sets the number of decimal places used by the receiver. + *

+ * The digit setting is used to allow for floating point values in the + * receiver. For example, to set the selection to a floating point value of + * 1.37 call setDigits() with a value of 2 and setSelection() with a value + * of 137. Similarly, if getDigits() has a value of 2 and getSelection() + * returns 137 this should be interpreted as 1.37. This applies to all + * numeric APIs. + *

+ * + * @param value the new digits (must be greater than or equal to zero) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + public void setDigits(final int value) { + checkWidget(); + digits = value; + convertSelectionToStringValue(); + } + + /** + * Sets the amount that the receiver's value will be modified by when the + * up/down arrows are pressed to the argument, which must be at least one. + * + * @param value the new increment (must be greater than zero) + * + * @exception SWTException + * + */ + public void setIncrement(final int value) { + checkWidget(); + increment = value; + } + + /** + * Sets the maximum value that the receiver will allow. This new value will + * be ignored if it is less than the receiver's current minimum value. If + * the new maximum is applied then the receiver's selection value will be + * adjusted if necessary to fall within its new range. + * + * @param value the new maximum, which must be greater than or equal to the + * current minimum + * + * @exception SWTException + * + */ + public void setMaximum(final int value) { + checkWidget(); + maximum = value; + } + + /** + * Sets the minimum value that the receiver will allow. This new value will + * be ignored if it is greater than the receiver's current maximum value. If + * the new minimum is applied then the receiver's selection value will be + * adjusted if necessary to fall within its new range. + * + * @param value the new minimum, which must be less than or equal to the + * current maximum + * + * @exception SWTException + * + */ + public void setMinimum(final int value) { + checkWidget(); + minimum = value; + } + + /** + * Sets the amount that the receiver's position will be modified by when the + * page up/down keys are pressed to the argument, which must be at least + * one. + * + * @param value the page increment (must be greater than zero) + * + * @exception SWTException + * + */ + public void setPageIncrement(final int value) { + checkWidget(); + pageIncrement = value; + } + + /** + * Sets the selection, which is the receiver's position, to the + * argument. If the argument is not within the range specified by minimum + * and maximum, it will be adjusted to fall within this range. + * + * @param value the new selection (must be zero or greater) + * + * @exception SWTException + * + */ + public void setSelection(int selection) { + checkWidget(); + if (selection < minimum) { + selection = minimum; + } else if (selection > maximum) { + selection = maximum; + } + + storedValue = selection; + text.setText(convertSelectionToStringValue()); + } + + /** + * Convert the selection into a string + * + * @return the string representation of the selection + */ + private String convertSelectionToStringValue() { + if (getDigits() == 0) { + return String.valueOf(storedValue); + } + final StringBuilder unformatted = new StringBuilder(String.valueOf(storedValue * Math.pow(10, -1 * getDigits()))); + for (int i = 0; i < digits; i++) { + unformatted.append("0"); + } + final int position = unformatted.indexOf("."); + final String temp = unformatted.substring(0, position + 1 + digits); + return temp.replace('.', decimalFormatSeparator); + + } + + /** + * Sets the maximum number of characters that the receiver's text field is + * capable of holding to be the argument. + *

+ * To reset this value to the default, use + * setTextLimit(Spinner.LIMIT). Specifying a limit value larger + * than Spinner.LIMIT sets the receiver's limit to + * Spinner.LIMIT. + *

+ * + * @param limit new text limit + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + * + * @see #LIMIT + */ + public void setTextLimit(final int limit) { + checkWidget(); + text.setTextLimit(limit); + } + + /** + * Sets the receiver's selection, minimum value, maximum value, digits, + * increment and page increment all at once. + *

+ * Note: This is similar to setting the values individually using the + * appropriate methods, but may be implemented in a more efficient fashion + * on some platforms. + *

+ * + * @param selection the new selection value + * @param minimum the new minimum value + * @param maximum the new maximum value + * @param digits the new digits value + * @param increment the new increment value + * @param pageIncrement the new pageIncrement value + * + * @exception SWTException + * + */ + public void setValues(final int selection, final int minimum, final int maximum, final int digits, final int increment, final int pageIncrement) { + setMinimum(minimum); + setMaximum(maximum); + setDigits(digits); + setIncrement(increment); + setPageIncrement(pageIncrement); + setSelection(selection); + } + + /** + * Sets the receiver's drag detect state. If the argument is + * true, the receiver will detect drag gestures, otherwise + * these gestures will be ignored. + * + * @param dragDetect the new drag detect state + * + * @exception SWTException + * + */ + @Override + public boolean setFocus() { + checkWidget(); + return text.setFocus(); + } + + /** + * Forces the receiver to have the keyboard focus, causing all + * keyboard events to be delivered to it. + * + * @return true if the control got focus, and + * false if it was unable to. + * + * @exception SWTException + * + * + * @see #setFocus + */ + @Override + public boolean forceFocus() { + checkWidget(); + return text.forceFocus(); + } + + /** + * Sets the receiver's background color to the color specified by the + * argument, or to the default system color for the control if the argument + * is null. + *

+ * Note: This operation is a hint and may be overridden by the platform. For + * example, on Windows the background of a Button cannot be changed. + *

+ * + * @param color the new color (or null) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setBackground(final Color color) { + super.setBackground(color); + leftButton.setBackground(color); + rightButton.setBackground(color); + text.setBackground(color); + } + + /** + * Sets the receiver's background image to the image specified by the + * argument, or to the default system color for the control if the argument + * is null. The background image is tiled to fill the available space. + *

+ * Note: This operation is a hint and may be overridden by the platform. For + * example, on Windows the background of a Button cannot be changed. + *

+ * + * @param image the new image (or null) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setBackgroundImage(final Image image) { + super.setBackgroundImage(image); + leftButton.setBackgroundImage(image); + rightButton.setBackgroundImage(image); + text.setBackgroundImage(image); + + } + + /** + * Sets the receiver's cursor to the cursor specified by the argument, or to + * the default cursor for that kind of control if the argument is null. + *

+ * When the mouse pointer passes over a control its appearance is changed to + * match the control's cursor. + *

+ * + * @param cursor the new cursor (or null) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setCursor(final Cursor cursor) { + super.setCursor(cursor); + leftButton.setCursor(cursor); + rightButton.setCursor(cursor); + text.setCursor(cursor); + } + + /** + * Enables the receiver if the argument is true, and disables + * it otherwise. A disabled control is typically not selectable from the + * user interface and draws with an inactive or "grayed" look. + * + * @param enabled the new enabled state + * + * @exception SWTException + * + */ + @Override + public void setEnabled(final boolean enabled) { + super.setEnabled(enabled); + leftButton.setEnabled(enabled); + rightButton.setEnabled(enabled); + text.setEnabled(enabled); + } + + /** + * Sets the font that the receiver will use to paint textual information to + * the font specified by the argument, or to the default font for that kind + * of control if the argument is null. + * + * @param font the new font (or null) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setFont(final Font font) { + super.setFont(font); + text.setFont(font); + } + + /** + * Sets the receiver's foreground color to the color specified by the + * argument, or to the default system color for the control if the argument + * is null. + *

+ * Note: This operation is a hint and may be overridden by the platform. + *

+ * + * @param color the new color (or null) + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setForeground(final Color color) { + super.setForeground(color); + leftButton.setForeground(color); + rightButton.setForeground(color); + text.setForeground(color); + } + + /** + * Sets the receiver's pop up menu to the argument. All controls may + * optionally have a pop up menu that is displayed when the user requests + * one for the control. The sequence of key strokes, button presses and/or + * button releases that are used to request a pop up menu is platform + * specific. + *

+ * Note: Disposing of a control that has a pop up menu will dispose of the + * menu. To avoid this behavior, set the menu to null before the control is + * disposed. + *

+ * + * @param menu the new pop up menu + * + * @exception IllegalArgumentException + * + * @exception SWTException + * + */ + @Override + public void setMenu(final Menu menu) { + super.setMenu(menu); + leftButton.setMenu(menu); + rightButton.setMenu(menu); + text.setMenu(menu); + } + + /** + * Sets the receiver's tool tip text to the argument, which may be null + * indicating that the default tool tip for the control will be shown. For a + * control that has a default tool tip, such as the Tree control on Windows, + * setting the tool tip text to an empty string replaces the default, + * causing no tool tip text to be shown. + *

+ * The mnemonic indicator (character '&') is not displayed in a tool + * tip. To display a single '&' in the tool tip, the character '&' + * can be escaped by doubling it in the string. + *

+ * + * @param string the new tool tip text (or null) + * + * @exception SWTException + * + */ + @Override + public void setToolTipText(final String tooltipText) { + super.setToolTipText(tooltipText); + leftButton.setToolTipText(tooltipText); + rightButton.setToolTipText(tooltipText); + text.setToolTipText(tooltipText); + } + +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/TrackAreaPainter.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/TrackAreaPainter.java index 90326e3..300c7be 100644 --- a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/TrackAreaPainter.java +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/TrackAreaPainter.java @@ -19,7 +19,7 @@ import org.eclipse.swt.graphics.Rectangle; import com.minres.scviewer.database.ui.WaveformColors; public class TrackAreaPainter implements IPainter { - + /** * */ @@ -35,14 +35,15 @@ public class TrackAreaPainter implements IPainter { } public void paintArea(Projection proj, Rectangle a) { - Rectangle area = proj.unProject(new Rectangle(a.x, a.y+waveCanvas.rulerHeight, a.width, a.height-waveCanvas.rulerHeight)); - proj.setBackground(this.waveCanvas.styleProvider.getColor(WaveformColors.TRACK_BG_EVEN)); - proj.setFillRule(SWT.FILL_EVEN_ODD); - proj.fillRectangle(area); + Rectangle area = proj.unProject(new Rectangle(a.x, a.y+waveCanvas.rulerHeight, a.width, a.height-waveCanvas.rulerHeight)); + proj.setBackground(this.waveCanvas.styleProvider.getColor(WaveformColors.TRACK_BG_EVEN)); + proj.setFillRule(SWT.FILL_EVEN_ODD); + proj.fillRectangle(area); if(trackVerticalOffset.size()>0){ Integer firstKey=trackVerticalOffset.floorKey(area.y); if(firstKey==null) firstKey=trackVerticalOffset.firstKey(); Integer lastKey = trackVerticalOffset.floorKey(area.y+area.height); + //if(lastKey==null) lastKey= trackVerticalOffset.lastKey(); Rectangle subArea = new Rectangle(area.x, 0, area.width, 0); if(lastKey.equals(firstKey)){ subArea.y=firstKey; @@ -61,9 +62,9 @@ public class TrackAreaPainter implements IPainter { public void addTrackPainter(IWaveformPainter trackPainter){ trackVerticalOffset.put(trackPainter.getVerticalOffset()+waveCanvas.rulerHeight, trackPainter); - + } - + public int getHeight(){ if(trackVerticalOffset.size()==0) return 1; return trackVerticalOffset.lastKey() + trackVerticalOffset.lastEntry().getValue().getHeight(); diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/WaveformCanvas.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/WaveformCanvas.java index cc8eb37..ec07c38 100644 --- a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/WaveformCanvas.java +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/WaveformCanvas.java @@ -46,21 +46,24 @@ import com.minres.scviewer.database.ui.IWaveformZoom; import com.minres.scviewer.database.ui.TrackEntry; import com.minres.scviewer.database.ui.ZoomKind; import com.minres.scviewer.database.ui.swt.Constants; +import com.minres.scviewer.database.ui.swt.internal.slider.ZoomBar; public class WaveformCanvas extends Canvas implements IWaveformZoom{ public static final long ZOOM_FIT = -2; public static final long ZOOM_FULL = -1; + + private static final int INITIAL_ZOOM_BAR_MAX = 1000; private boolean doubleBuffering = true; IWaveformStyleProvider styleProvider; private int scaleMagnitude = 6; - + private long scaleFactor = Constants.POWERS_OF_TEN[scaleMagnitude]; - + private long maxTime; protected Point origin; /* original size */ @@ -81,22 +84,23 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ private List cursorPainters; + private ZoomBar horizontal; + + private int[] lastHorSelection; + + private long sliderScaleFactor = 1; + + private ScrollBar vertical; + HashMap wave2painterMap; - /** - * Constructor for ScrollableCanvas. - * - * @param parent - * the parent of this control.super(parent, style | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL); - * @param style - * the style of this control. - */ - public WaveformCanvas(final Composite parent, int style, IWaveformStyleProvider styleProvider) { - super(parent, style | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); + + public WaveformCanvas(final Composite parent, int style, IWaveformStyleProvider styleProvider, ZoomBar.IProvider scrollbarProvider) { + super(parent, (style & ~SWT.H_SCROLL) | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.V_SCROLL ); this.styleProvider=styleProvider; addControlListener(new ControlAdapter() { /* resize listener. */ @Override public void controlResized(ControlEvent event) { - syncScrollBars(); + syncSb(); } }); addPaintListener((final PaintEvent event) -> paint(event.gc)); @@ -106,6 +110,8 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ cursorPainters= new ArrayList<>(); wave2painterMap=new HashMap<>(); + horizontal = scrollbarProvider.getScrollBar(); + vertical = getVerticalBar(); initScrollBars(); // order is important: it is bottom to top trackAreaPainter=new TrackAreaPainter(this); @@ -114,10 +120,10 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ painterList.add(arrowPainter); rulerPainter=new RulerPainter(this); painterList.add(rulerPainter); - CursorPainter cp = new CursorPainter(this, scaleFactor * 10, cursorPainters.size()-1); + CursorPainter cp = new CursorPainter(this, getScale() * 10, cursorPainters.size()-1); painterList.add(cp); cursorPainters.add(cp); - CursorPainter marker = new CursorPainter(this, scaleFactor * 100, cursorPainters.size()-1); + CursorPainter marker = new CursorPainter(this, getScale() * 100, cursorPainters.size()-1); painterList.add(marker); cursorPainters.add(marker); wave2painterMap=new HashMap<>(); @@ -149,15 +155,9 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ public void setOrigin(int x, int y) { checkWidget(); - ScrollBar hBar = getHorizontalBar(); - if(x<=0) hBar.setSelection(-x); - x = -hBar.getSelection(); - ScrollBar vBar = getVerticalBar(); - if(y<=0) vBar.setSelection(-y); - y = -vBar.getSelection(); origin.x = x; origin.y = y; - syncScrollBars(); + syncSb(); } @Override @@ -167,14 +167,20 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ public void setMaxTime(long maxTime) { this.maxTime = maxTime; - syncScrollBars(); + if(maxTime>INITIAL_ZOOM_BAR_MAX) { + long maxBarTime = maxTime; + while(maxBarTime>Integer.MAX_VALUE) maxBarTime/=1000; + horizontal.setMaximum((int) maxBarTime); + } + sliderScaleFactor = maxTime/horizontal.getMaximum(); + syncSb(); } @Override public long getScale() { return scaleFactor; } - + @Override public void setScale(long factor) { setScalingFactor(factor, (getMaxVisibleTime()+getMinVisibleTime())/2); @@ -206,37 +212,41 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ factor=1; else if(factor>maxFactor) factor=maxFactor; - if(factor!=scaleFactor || (getMaxVisibleTime()+getMinVisibleTime()/2) != centerTime) { - scaleFactor = factor; - scaleMagnitude = 0; - for(int i=Constants.POWERS_OF_TEN.length-1; i>0; i--) { - if(scaleFactor>=Constants.POWERS_OF_TEN[i]) { - scaleMagnitude = i; - break; - } - } + if(factor!=getScale() || (getMaxVisibleTime()+getMinVisibleTime()/2) != centerTime) { + updateScaleFactor(factor); ITx tx = arrowPainter.getTx(); arrowPainter.setTx(null); /* * xc = tc/oldScaleFactor * xoffs = xc+origin.x * xcn = tc/newScaleFactor - * t0n = (xcn-xoffs)*scaleFactor + * t0n = (xcn-xoffs)*getScale() */ long xoffs = clientAreaWidth/2; - long xcn=centerTime/scaleFactor; // new total x-offset + long xcn=centerTime/getScale(); // new total x-offset long originX=xcn-xoffs; if(originX>0) { origin.x=(int) -originX; // new cursor time offset relative to left border }else { origin.x=0; } - syncScrollBars(); + syncSb(); arrowPainter.setTx(tx); redraw(); } } + private void updateScaleFactor(long factor) { + scaleFactor = factor; + scaleMagnitude = 0; + for(int i=Constants.POWERS_OF_TEN.length-1; i>0; i--) { + if(scaleFactor>=Constants.POWERS_OF_TEN[i]) { + scaleMagnitude = i; + break; + } + } + } + @Override public String timeToString(long time) { int idx = scaleMagnitude/3; @@ -245,7 +255,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ } public long getTimeForOffset(int xOffset){ - return (xOffset-origin.x) * scaleFactor; + return (xOffset-origin.x) * getScale(); } public void addPainter(IPainter painter) { @@ -265,7 +275,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ void clearAllWaveformPainter(boolean update) { trackAreaPainter.trackVerticalOffset.clear(); wave2painterMap.clear(); - if(update) syncScrollBars(); + if(update) syncSb(); } public void addWaveformPainter(IWaveformPainter painter) { @@ -275,7 +285,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ void addWaveformPainter(IWaveformPainter painter, boolean update) { trackAreaPainter.addTrackPainter(painter); wave2painterMap.put(painter.getTrackEntry().waveform, painter); - if(update) syncScrollBars(); + if(update) syncSb(); } public List getCursorPainters() { @@ -284,26 +294,41 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ /* Initialize the scrollbar and register listeners. */ private void initScrollBars() { - ScrollBar horizontal = getHorizontalBar(); horizontal.setEnabled(false); horizontal.setVisible(true); horizontal.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { - if (painterList.isEmpty()) - return; - setOrigin(-((ScrollBar) event.widget).getSelection(), origin.y); + if (!painterList.isEmpty()) { + int[] sel = horizontal.getSelection(); + long lowerTime = sel[0]*sliderScaleFactor; + long upperTime = sel[1]*sliderScaleFactor; + if(sel[1]-sel[0] != lastHorSelection[1]-lastHorSelection[0]) { + long time_diff = upperTime-lowerTime; + long factor = time_diff/getClientArea().width; + setScalingFactor(factor, lowerTime+time_diff/2); + } else { + origin.x = -(int) (lowerTime/getScale()); + WaveformCanvas.this.getDisplay().asyncExec(() -> {redraw();}); + } + lastHorSelection=sel; + } } }); - ScrollBar vertical = getVerticalBar(); + horizontal.setMinimum(0); + horizontal.setMaximum(INITIAL_ZOOM_BAR_MAX); + lastHorSelection = horizontal.getSelection(); + vertical.setEnabled(false); vertical.setVisible(true); vertical.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { - if (painterList.isEmpty()) - return; - setOrigin(origin.x, -((ScrollBar) event.widget).getSelection()); + if (!painterList.isEmpty()) { + origin.y=-vertical.getSelection(); + fireSelectionEvent(); + WaveformCanvas.this.getDisplay().asyncExec(() -> {redraw();}); + } } }); } @@ -313,50 +338,48 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ * range, it will correct it. This function considers only following factors * : transform, image size, client area. */ - public void syncScrollBars() { - if (painterList.isEmpty()) { - redraw(); - return; + public void syncSb() { + if (!painterList.isEmpty()) { + syncHSb(); + syncVSb(); + fireSelectionEvent(); } - int height = trackAreaPainter.getHeight(); // incl. Ruler - long width = maxTime / scaleFactor; - Rectangle clientArea=getClientArea(); - ScrollBar horizontal = getHorizontalBar(); - horizontal.setIncrement(getClientArea().width / 100); - horizontal.setPageIncrement(getClientArea().width); - int clientWidthw = clientArea.width; - if (width > clientWidthw) { /* image is wider than client area */ - horizontal.setMinimum(0); - horizontal.setMaximum((int)width); - horizontal.setEnabled(true); - if (-origin.x > horizontal.getMaximum() - clientWidthw) { - origin.x = -horizontal.getMaximum() + clientWidthw; - } - } else { /* image is narrower than client area */ - horizontal.setEnabled(false); - } - horizontal.setThumb(clientWidthw); - horizontal.setSelection(-origin.x); + redraw(); + } - ScrollBar vertical = getVerticalBar(); - vertical.setIncrement(getClientArea().height / 100); - vertical.setPageIncrement(getClientArea().height); - int clientHeighth = clientArea.height; - if (height > clientHeighth) { /* image is higher than client area */ + private void syncVSb() { + Rectangle clientArea=getClientArea(); + int height = trackAreaPainter.getHeight(); // incl. Ruler + int clientHeight = clientArea.height; + vertical.setIncrement(clientHeight / 100); + vertical.setPageIncrement(clientHeight/2); + if (height > clientHeight) { /* image is higher than client area */ vertical.setMinimum(0); vertical.setMaximum(height); vertical.setEnabled(true); - if ( -origin.y > vertical.getMaximum() - clientHeighth) { - origin.y = -vertical.getMaximum() + clientHeighth; + if ( -origin.y > vertical.getMaximum() - clientHeight) { + origin.y = -vertical.getMaximum() + clientHeight; } } else { /* image is less higher than client area */ - vertical.setMaximum(clientHeighth); + vertical.setMaximum(clientHeight); vertical.setEnabled(false); } - vertical.setThumb(clientHeighth); + vertical.setThumb(clientHeight); vertical.setSelection(-origin.y); - redraw(); - fireSelectionEvent(); + } + + private void syncHSb() { + horizontal.setEnabled(wave2painterMap.size()>0); + Rectangle clientArea=getClientArea(); + int clientWidth = clientArea.width; + if(sliderScaleFactor>0) { + int lower = (int) ( ( -origin.x * getScale()) / sliderScaleFactor); + int upper = (int) (((clientWidth-origin.x) * getScale()) / sliderScaleFactor); + lastHorSelection = new int[] {Math.max(lower,0), Math.min(upper, horizontal.getMaximum())}; + horizontal.setSelection(lastHorSelection); + } + long width = maxTime / getScale(); + horizontal.setButtonsEnabled(width > clientWidth); } /* Paint function */ @@ -406,7 +429,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ result.add(entry.getValue().getTrackEntry()); } } else if (p instanceof CursorPainter) { - if (Math.abs(point.x - origin.x - ((CursorPainter) p).getTime()/scaleFactor) < 2) { + if (Math.abs(point.x - origin.x - ((CursorPainter) p).getTime()/getScale()) < 2) { result.add(p); } } @@ -434,11 +457,11 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ } public void reveal(ITx tx) { - int lower = (int) (tx.getBeginTime() / scaleFactor); - int higher = (int) (tx.getEndTime() / scaleFactor); + int lower = (int) (tx.getBeginTime() / getScale()); + int higher = (int) (tx.getEndTime() / getScale()); Point size = getSize(); - size.x -= getVerticalBar().getSize().x + 2; - size.y -= getHorizontalBar().getSize().y; + size.x -= vertical.getSize().x + 2; + size.y -= horizontal.getSize().y; if (lower < -origin.x) { setOrigin(-lower, origin.y); } else if (higher > (size.x - origin.x)) { @@ -467,9 +490,8 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ if(te.waveform == waveform) { Point size = getSize(); size.y -=+rulerHeight; - ScrollBar sb = getHorizontalBar(); - if((sb.getStyle()&SWT.SCROLLBAR_OVERLAY)!=0 && sb.isVisible()) - size.y-= getHorizontalBar().getSize().y; + if((horizontal.getStyle()&SWT.SCROLLBAR_OVERLAY)!=0 && horizontal.isVisible()) + size.y-= horizontal.getSize().y; int top = te.vOffset; int bottom = top + styleProvider.getTrackHeight(); if (top < -origin.y) { @@ -482,10 +504,10 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ } public void reveal(long time) { - int scaledTime = (int) (time / scaleFactor); + int scaledTime = (int) (time / getScale()); Point size = getSize(); - size.x -= getVerticalBar().getSize().x + 2; - size.y -= getHorizontalBar().getSize().y; + size.x -= vertical.getSize().x + 2; + size.y -= horizontal.getSize().y; if (scaledTime < -origin.x) { setOrigin(-scaledTime+10, origin.y); } else if (scaledTime > (size.x - origin.x)) { @@ -495,7 +517,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ @Override public void centerAt(long time) { - int scaledTime = (int) (time / scaleFactor); + int scaledTime = (int) (time / getScale()); int newX = -scaledTime+getWidth()/2; setOrigin(newX>0?0:newX, origin.y); } @@ -532,15 +554,15 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ } } - + @Override public long getMaxVisibleTime() { - return (getClientArea().width-origin.x)*scaleFactor; + return (getClientArea().width-origin.x)*getScale(); } @Override public long getMinVisibleTime() { - return -origin.x * scaleFactor; + return -origin.x * getScale(); } @Override @@ -548,7 +570,7 @@ public class WaveformCanvas extends Canvas implements IWaveformZoom{ long duration = getMaxVisibleTime()-getMinVisibleTime(); if(time>0) { if((time+duration) { + if (hoverImage != null) hoverImage.dispose(); + if (normalImage != null) normalImage.dispose(); + if (pressedImage != null) pressedImage.dispose(); + if (disabledImage != null) disabledImage.dispose(); + }); + addListener(SWT.Paint, event -> { + paintControl(event); + }); + addMouseTrackListener(new MouseTrackAdapter() { + public void mouseEnter(MouseEvent arg0) { + if(isEnabled()) { + hover=true; + redraw(); + } + } + public void mouseExit(MouseEvent arg0) { + if(isEnabled()) { + hover=false; + redraw(); + } + } + }); + addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + if(isEnabled()) { + pressed=true; + notifyListeners(); + if(autoFire) actionTimer.activate(); + redraw(); + } + } + + @Override + public void mouseUp(MouseEvent e) { + pressed=false; + redraw(); + } + }); + } + + private void paintControl(Event event) { + GC gc = event.gc; + if (hoverImage != null) { + if(pressed) + gc.drawImage(pressedImage, 1, 1); + else if(hover) { + gc.drawImage(hoverImage, 1, 1); + } else if(isEnabled()){ + gc.drawImage(normalImage, 1, 1); + } else + gc.drawImage(disabledImage, 1, 1); + } + } + + public void setImage(Image[] imgs) { + assert(imgs.length==3); + Display d = Display.getDefault(); + normalImage = new Image(d, imgs[0], SWT.IMAGE_COPY); + hoverImage = new Image(d, imgs[1], SWT.IMAGE_COPY); + pressedImage = new Image(d, imgs[2], SWT.IMAGE_COPY); + disabledImage = new Image(d, imgs[0], SWT.IMAGE_DISABLE); + width = imgs[0].getBounds().width; + height = imgs[0].getBounds().height; + redraw(); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + int overallWidth = width; + int overallHeight = height; + if (wHint != SWT.DEFAULT && wHint < overallWidth) + overallWidth = wHint; + if (hHint != SWT.DEFAULT && hHint < overallHeight) + overallHeight = hHint; + return new Point(overallWidth + 2, overallHeight + 2); + } + /** + * Adds the listener to the collection of listeners who will be notified when + * the user changes the receiver's value, by sending it one of the messages + * defined in the SelectionListener interface. + *

+ * widgetSelected is called when the user changes the receiver's + * value. widgetDefaultSelected is not called. + *

+ * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException + *
    + *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • + *
+ * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ * + * @see SelectionListener + * @see #removeSelectionListener + */ + public void addSelectionListener(final SelectionListener listener) { + checkWidget(); + SelectionListenerUtil.addSelectionListener(this, listener); + } + + /** + * Removes the listener from the collection of listeners who will be notified + * when the user changes the receiver's value. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException + *
    + *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • + *
+ * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ * + * @see SelectionListener + * @see #addSelectionListener + */ + public void removeSelectionListener(final SelectionListener listener) { + checkWidget(); + SelectionListenerUtil.removeSelectionListener(this, listener); + } + + private void notifyListeners() { + Event e = new Event(); + e.widget=this; + e.type=SWT.Selection; + SelectionListenerUtil.fireSelectionListeners(this,e); + } + + public boolean isAutoFire() { + return autoFire; + } + + public void setAutoFire(boolean autoFire) { + this.autoFire = autoFire; + } +} diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/RangeSlider.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/RangeSlider.java new file mode 100644 index 0000000..2f4964c --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/RangeSlider.java @@ -0,0 +1,631 @@ +package com.minres.scviewer.database.ui.swt.internal.slider; + +import java.text.Format; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackAdapter; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.wb.swt.SWTResourceManager; + +public class RangeSlider extends Canvas { + + private static final int NONE = 0; + private static final int UPPER = 1 << 0; + private static final int LOWER = 1 << 1; + private static final int BOTH = UPPER | LOWER; + + private final int minHeight; + private final int markerWidth; + private final int thumbWidth = 0; + private final Image[] slider, sliderHover, sliderDrag; + + private int minimum; + private int maximum; + private int lowerValue; + private int upperValue; + + private int increment; + private int pageIncrement; + private int selectedElement; + private boolean upperHover, lowerHover; + private int previousUpperValue, previousLowerValue; + private int startDragUpperValue, startDragLowerValue; + private Point startDragPoint; + private final boolean isFullSelection=false; + private final boolean isHighQuality; + private final boolean isOn; + private Format toolTipFormatter; + private String clientToolTipText; + private StringBuffer toolTip; + private Point coordUpper; + private Point coordLower; + + public RangeSlider(final Composite parent, final int style) { + super(parent, SWT.DOUBLE_BUFFERED | ((style & SWT.BORDER) == SWT.BORDER ? SWT.BORDER : SWT.NONE)); + slider = new Image[] { + SWTResourceManager.getImage(this.getClass(), "marker_l.png"), + SWTResourceManager.getImage(this.getClass(), "marker_r.png")}; + sliderHover = new Image[] { + SWTResourceManager.getImage(this.getClass(), "marker_l_hover.png"), + SWTResourceManager.getImage(this.getClass(), "marker_r_hover.png")}; + sliderDrag = new Image[] { + SWTResourceManager.getImage(this.getClass(), "marker_l_pressed.png"), + SWTResourceManager.getImage(this.getClass(), "marker_r_pressed.png")}; + Rectangle imgSize = slider[0].getBounds(); + minHeight =imgSize.height+2; + markerWidth = imgSize.width; + minimum = lowerValue = 0; + maximum = upperValue = 100; + increment = 1; + pageIncrement = 10; + isHighQuality = (style & SWT.HIGH) == SWT.HIGH; + isOn = (style & SWT.ON) == SWT.ON; + selectedElement = NONE; + + addMouseListeners(); + addListener(SWT.Resize, event -> { + }); + addListener(SWT.KeyDown, event -> { + handleKeyDown(event); + }); + addPaintListener(event -> { + drawWidget(event); + }); + } + + @Override + public int getStyle() { + return super.getStyle() | // + (isOn ? SWT.ON : SWT.NONE) | // + (isFullSelection ? SWT.CONTROL : SWT.NONE) | // + (isHighQuality ? SWT.HIGH : SWT.NONE); + } + + private void addMouseListeners() { + addListener(SWT.MouseDown, e -> { + if (e.button == 1 || e.button == 2) { + selectKnobs(e); + selectedElement = (lowerHover ? LOWER : NONE) | (upperHover ? UPPER : NONE); + if (selectedElement!=NONE) { + if((e.stateMask & SWT.CTRL)==0 && e.button != 2) + selectedElement=BOTH; + startDragLowerValue = previousLowerValue = lowerValue; + startDragUpperValue = previousUpperValue = upperValue; + startDragPoint = new Point(e.x, e.y); + } + } + }); + + addListener(SWT.MouseUp, e -> { + if (selectedElement!=NONE) { + startDragPoint = null; + validateNewValues(e); + super.setToolTipText(clientToolTipText); + selectedElement=NONE; + redraw(); + } else if (e.button == 1) { + if(e.xcoordUpper.x+markerWidth) { + translateValues(pageIncrement); + validateNewValues(e); + redraw(); + } + } + }); + + addListener(SWT.MouseDoubleClick, event -> { + handleMouseDoubleClick(event); + }); + + addListener(SWT.MouseMove, event -> { + handleMouseMove(event); + }); + + addListener(SWT.MouseWheel, event -> { + handleMouseWheel(event); + }); + + addListener(SWT.MouseHover, event -> { + handleMouseHover(event); + }); + + addMouseTrackListener(new MouseTrackAdapter() { + public void mouseExit(MouseEvent event) { + lowerHover = upperHover = false; + redraw(); + } + }); + + } + + private void validateNewValues(final Event e) { + if (upperValue != previousUpperValue || lowerValue != previousLowerValue) { + if (!SelectionListenerUtil.fireSelectionListeners(this,e)) { + upperValue = previousUpperValue; + lowerValue = previousLowerValue; + } + previousUpperValue = upperValue; + previousLowerValue = lowerValue; + increment = Math.max(1, (upperValue-lowerValue)/100); + pageIncrement = Math.max(1, (upperValue-lowerValue)/2); + redraw(); + } + } + + private boolean busy = false; + + private void handleMouseMove(final Event e) { + if (selectedElement==NONE) { + final boolean wasUpper = upperHover; + final boolean wasLower = lowerHover; + selectKnobs(e); + if (wasUpper != upperHover || wasLower != lowerHover) { + redraw(); + } + } else { // dragInProgress + final int x = e.x; + if (selectedElement == BOTH) { + final int diff = (int) ((startDragPoint.x - x) / computePixelSizeForSlider()) + minimum; + int newUpper = startDragUpperValue - diff; + int newLower = startDragLowerValue - diff; + if (newUpper > maximum) { + newUpper = maximum; + newLower = maximum - (startDragUpperValue - startDragLowerValue); + } else if (newLower < minimum) { + newLower = minimum; + newUpper = minimum + startDragUpperValue - startDragLowerValue; + } + upperValue = newUpper; + lowerValue = newLower; + handleToolTip(lowerValue, upperValue); + } else if (selectedElement == UPPER) { + upperValue = (int) Math.round((double)(x - markerWidth) / computePixelSizeForSlider()) + minimum; + checkUpperValue(); + handleToolTip(upperValue); + } else if (selectedElement == LOWER){ + lowerValue = (int) Math.round((double)(x - markerWidth) / computePixelSizeForSlider()) + minimum; + checkLowerValue(); + handleToolTip(lowerValue); + } + if (isOn && !busy) { + validateNewValues(e); + busy=true; + getDisplay().timerExec(50, ()->{busy=false;}); + } else { + redraw(); + } + } + } + + private boolean isBetweenKnobs(int x, int y) { + return x < coordUpper.x && x > coordLower.x && y >= minHeight/3 && y <= minHeight/3 + getClientArea().height - 2*minHeight/3; + } + + private void selectKnobs(final Event e) { + if (coordLower != null) { + final Rectangle imgBounds = slider[0].getBounds(); + final int x = e.x, y = e.y; + lowerHover = x >= coordLower.x && x <= coordLower.x + imgBounds.width && y >= coordLower.y && y <= coordLower.y + imgBounds.height; + upperHover = ((e.stateMask & (SWT.CTRL | SWT.SHIFT)) != 0 || !lowerHover) && // + x >= coordUpper.x && x <= coordUpper.x + imgBounds.width && // + y >= coordUpper.y && y <= coordUpper.y + imgBounds.height; + lowerHover &= (e.stateMask & SWT.CTRL) != 0 || !upperHover; + if (!lowerHover && !upperHover && isBetweenKnobs(x, y)) { + lowerHover = upperHover = true; + } + } + } + + private int getCursorValue(int x, int y) { + int value = -1; + final Rectangle clientArea = getClientArea(); + if (x < clientArea.width - 2*markerWidth && x >= markerWidth && y >= minHeight/3 && y <= clientArea.height - minHeight/3) { + value = (int) Math.round((x - 9d) / computePixelSizeForSlider()) + minimum; + } + return value; + } + + private void handleMouseDoubleClick(final Event e) { + final int value = getCursorValue(e.x, e.y); + if (value >= 0) { + if (value > upperValue) { + translateValues(value-upperValue); + } else if (value < lowerValue) { + translateValues(value-lowerValue); + } + validateNewValues(e); + } + } + + private void handleToolTip(int... values) { + if (toolTipFormatter != null) { + try { + if (values.length == 1) { + toolTip.setLength(0); + toolTipFormatter.format(values[0], toolTip, null); + super.setToolTipText(toolTip.toString()); + } else if (values.length == 2) { + toolTip.setLength(0); + toolTipFormatter.format(values[0], toolTip, null); + toolTip.append(" \u2194 "); // LEFT RIGHT ARROW + toolTipFormatter.format(values[1], toolTip, null); + super.setToolTipText(toolTip.toString()); + } + } catch (final IllegalArgumentException ex) { + super.setToolTipText(clientToolTipText); + } + } + } + + private void handleMouseHover(final Event e) { + if (selectedElement!=NONE && toolTipFormatter != null) { + final int value = getCursorValue(e.x, e.y); + if (value >= 0) { + try { + toolTip.setLength(0); + toolTipFormatter.format(value, toolTip, null); + super.setToolTipText(toolTip.toString()); + } catch (final IllegalArgumentException ex) { + super.setToolTipText(clientToolTipText); + } + } else { + super.setToolTipText(clientToolTipText); + } + } + } + + public void setToolTipFormatter(Format formatter) { + toolTip = formatter != null ? new StringBuffer() : null; + toolTipFormatter = formatter; + } + + @Override + public void setToolTipText(String string) { + super.setToolTipText(clientToolTipText = string); + } + + private void handleMouseWheel(final Event e) { + previousLowerValue = lowerValue; + previousUpperValue = upperValue; + final int amount = Math.max(1, ((e.stateMask & SWT.SHIFT) != 0 ? (upperValue-lowerValue)/6 : (upperValue-lowerValue)/15)); + if ((e.stateMask&SWT.CTRL)==0) { + int newLower = lowerValue + e.count * amount; + int newUpper = upperValue + e.count * amount; + if (newUpper > maximum) { + newUpper = maximum; + newLower = maximum - (upperValue - lowerValue); + } else if (newLower < minimum) { + newLower = minimum; + newUpper = minimum + upperValue - lowerValue; + } + upperValue = newUpper; + lowerValue = newLower; + } else { + int newLower = lowerValue + e.count * amount/2; + int newUpper = upperValue - e.count * amount/2; + int dist = newUpper - newLower; + if (newUpper > maximum) { + newUpper = maximum; + newLower = maximum - dist; + } else if (newLower < minimum) { + newLower = minimum; + newUpper = minimum + dist; + } + if(newUpper<=newLower) { + newLower=lowerValue + (upperValue - lowerValue)/2; + newUpper=newLower+1; + } + upperValue = newUpper; + lowerValue = newLower; + } + validateNewValues(e); + e.doit = false; // we are consuming this event + } + + private void checkLowerValue() { + if (lowerValue < minimum) { + lowerValue = minimum; + } else if (lowerValue > (upperValue-thumbWidth)) { + lowerValue = (upperValue-thumbWidth); + } + } + + private void checkUpperValue() { + if (upperValue > maximum) { + upperValue = maximum; + } else if (upperValue < (lowerValue+thumbWidth)) { + upperValue = lowerValue+thumbWidth; + } + } + + private float computePixelSizeForSlider() { + return (getClientArea().width - 2.0f*markerWidth) / (maximum - minimum); + } + + private void drawWidget(final PaintEvent e) { + final Rectangle rect = getClientArea(); + if (rect.width == 0 || rect.height == 0) { + return; + } + e.gc.setAdvanced(true); + e.gc.setAntialias(SWT.ON); + drawBackground(e.gc); + if (lowerHover || (selectedElement & LOWER) != 0) { + coordUpper = drawMarker(e.gc, upperValue, true); + coordLower = drawMarker(e.gc, lowerValue, false); + } else { + coordLower = drawMarker(e.gc, lowerValue, false); + coordUpper = drawMarker(e.gc, upperValue, true); + } + } + + private void drawBackground(final GC gc) { + final Rectangle clientArea = getClientArea(); + gc.setBackground(getBackground()); + gc.fillRectangle(clientArea); + if (isEnabled()) { + gc.setForeground(getForeground()); + } else { + gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY)); + } + gc.drawRoundRectangle(markerWidth, minHeight/3, clientArea.width - 2*markerWidth, clientArea.height - 2*minHeight/3, 3, 3); + + final float pixelSize = computePixelSizeForSlider(); + final int startX = (int) (pixelSize * lowerValue); + final int endX = (int) (pixelSize * upperValue); + if (isEnabled()) { + gc.setBackground(getForeground()); + } else { + gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GRAY)); + } + gc.fillRectangle(markerWidth+startX, minHeight/3, endX - startX, clientArea.height - 2*minHeight/3); + + } + + private Point drawMarker(final GC gc, final int value, final boolean upper) { + final float pixelSize = computePixelSizeForSlider(); + int x = (int) (pixelSize * value); + final int idx = upper?1:0; + Image image; + if (upper) { + if (upperHover) { + image = (selectedElement & UPPER) != 0 ? sliderDrag[idx] : sliderHover[idx]; + } else { + image = slider[idx]; + } + } else { + if (lowerHover) { + image = (selectedElement & LOWER) != 0 ? sliderDrag[idx] : sliderHover[idx]; + } else { + image = slider[idx]; + } + } + if(upper) + x+=slider[idx].getBounds().width; + if (isEnabled()) { + gc.drawImage(image, x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); + } else { + final Image temp = new Image(getDisplay(), image, SWT.IMAGE_DISABLE); + gc.drawImage(temp, x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); + temp.dispose(); + } + return new Point(x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); + } + + private void moveCursorPosition(int xDelta, int yDelta) { + final Point cursorPosition = getDisplay().getCursorLocation(); + cursorPosition.x += xDelta; + cursorPosition.y += yDelta; + getDisplay().setCursorLocation(cursorPosition); + } + + private void handleKeyDown(final Event event) { + int accelerator = (event.stateMask & SWT.SHIFT) != 0 ? 10 : (event.stateMask & SWT.CTRL) != 0 ? 2 : 1; + if (selectedElement != NONE) { + switch (event.keyCode) { + case SWT.ESC: + startDragPoint = null; + upperValue = startDragUpperValue; + lowerValue = startDragLowerValue; + validateNewValues(event); + selectedElement = NONE; + if (!isOn) { + redraw(); + } + event.doit = false; + break; + case SWT.ARROW_UP: + accelerator = -accelerator; + case SWT.ARROW_LEFT: + moveCursorPosition(-accelerator, 0); + event.doit = false; + break; + case SWT.ARROW_DOWN: + accelerator = -accelerator; + case SWT.ARROW_RIGHT: + moveCursorPosition(accelerator, 0); + event.doit = false; + break; + } + return; + } + previousLowerValue = lowerValue; + previousUpperValue = upperValue; + + switch (event.keyCode) { + case SWT.HOME: + if ((event.stateMask & (SWT.SHIFT| SWT.CTRL)) == 0) { + upperValue = minimum + upperValue - lowerValue; + lowerValue = minimum; + } + break; + case SWT.END: + if ((event.stateMask & (SWT.SHIFT| SWT.CTRL)) == 0) { + lowerValue = maximum - (upperValue - lowerValue); + upperValue = maximum; + } + break; + case SWT.PAGE_UP: + translateValues(-accelerator * pageIncrement); + break; + case SWT.PAGE_DOWN: + translateValues( accelerator * pageIncrement); + break; + case SWT.ARROW_DOWN: + case SWT.ARROW_RIGHT: + translateValues( accelerator * increment); + break; + case SWT.ARROW_UP: + case SWT.ARROW_LEFT: + translateValues(-accelerator * increment); + break; + } + if (previousLowerValue != lowerValue || previousUpperValue != upperValue) { + checkLowerValue(); + checkUpperValue(); + validateNewValues(event); + } + } + + private void translateValues(int amount) { + int newLower = lowerValue + amount; + int newUpper = upperValue + amount; + if (newUpper > maximum) { + newUpper = maximum; + newLower = maximum - (upperValue - lowerValue); + } else if (newLower < minimum) { + newLower = minimum; + newUpper = minimum + upperValue - lowerValue; + } + upperValue = newUpper; + lowerValue = newLower; + } + + public void addSelectionListener(final SelectionListener listener) { + checkWidget(); + SelectionListenerUtil.addSelectionListener(this, listener); + } + + public void removeSelectionListener(final SelectionListener listener) { + checkWidget(); + SelectionListenerUtil.removeSelectionListener(this, listener); + } + + @Override + public Point computeSize(final int wHint, final int hHint, final boolean changed) { + checkWidget(); + final int width = Math.max(2*markerWidth+100, wHint); + final int height = Math.max(minHeight, hHint); + return new Point(width, height); + } + + public int[] getSelection() { + checkWidget(); + return new int[] {lowerValue, upperValue}; + } + + public int getIncrement() { + checkWidget(); + return increment; + } + + public int getMaximum() { + checkWidget(); + return maximum; + } + + public int getMinimum() { + checkWidget(); + return minimum; + } + + public int getPageIncrement() { + checkWidget(); + return pageIncrement; + } + + public void setMaximum(final int value) { + setLimits(minimum, value); + } + + public void setMinimum(final int value) { + setLimits(value, maximum); + } + + public void setLimits(final int min, final int max) { + checkWidget(); + if (min >= 0 && min < max && (min != minimum || max != maximum)) { + minimum = min; + maximum = max; + if (lowerValue < minimum) { + lowerValue = minimum; + } else if (lowerValue > maximum) { + lowerValue = maximum; + } + if (upperValue < minimum) { + upperValue = minimum; + } else if (upperValue > maximum) { + upperValue = maximum; + } + redraw(); + } + } + + public int getUpperValue() { + checkWidget(); + return upperValue; + } + + public void setUpperValue(final int value) { + setValues(lowerValue, value); + } + + public int getLowerValue() { + checkWidget(); + return lowerValue; + } + + public void setLowerValue(final int value) { + setValues(value, upperValue); + } + + public void setValues(final int[] values) { + if (values.length == 2) { + setValues(values[0], values[1]); + } + } + + public void setValues(final int lowerValue, final int upperValue) { + setValues(lowerValue, upperValue, false); + } + + public void setValues(final int lowerValue, final int upperValue, boolean update) { + checkWidget(); + if (lowerValue <= upperValue && lowerValue >= minimum && upperValue <= maximum && (this.lowerValue != lowerValue || this.upperValue != upperValue)) { + this.lowerValue = lowerValue; + this.upperValue = upperValue; + if(update) { + Event e = new Event(); + e.type=SWT.Selection; + e.doit=true; + validateNewValues(e); + } else { + increment = Math.max(1, (upperValue-lowerValue)/100); + pageIncrement = Math.max(1, (upperValue-lowerValue)/2); + } + redraw(); + } + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ReflectionUtils.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ReflectionUtils.java new file mode 100644 index 0000000..93e97c6 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ReflectionUtils.java @@ -0,0 +1,48 @@ +package com.minres.scviewer.database.ui.swt.internal.slider; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ReflectionUtils { + /** + * Call a method using introspection (so ones can call a private or protected method) + * @param object object on which the method will be called + * @param methodName method name + * @param args arguments of this method (can be null) + * @return the value returned by this method (if this method returns a value) + */ + public static Object callMethod(final Object object, final String methodName, final Object... args) { + if (object == null) { + return null; + } + final Class[] array = new Class[args == null ? 0 : args.length]; + int index = 0; + if (args != null) { + for (final Object o : args) { + array[index++] = o == null ? Object.class : o.getClass(); + } + } + + return callMethodWithClassType(object, methodName, array, args); + } + + private static Object callMethodWithClassType(final Object object, final String methodName, final Class[] array, final Object... args) { + Class currentClass = object.getClass(); + Method method = null; + while (currentClass != null) { + try { + method = currentClass.getDeclaredMethod(methodName, array); + break; + } catch (final NoSuchMethodException nsme) { + currentClass = currentClass.getSuperclass(); + } + } + + try { + method.setAccessible(true); + return method.invoke(object, args); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/SelectionListenerUtil.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/SelectionListenerUtil.java new file mode 100644 index 0000000..273eca2 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/SelectionListenerUtil.java @@ -0,0 +1,74 @@ +package com.minres.scviewer.database.ui.swt.internal.slider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TypedListener; + +public class SelectionListenerUtil { + /** + * Add a SelectionListener to a given Control + * + * @param control control on which the selection listener is added + * @param listener listener to add + */ + public static void addSelectionListener(final Control control, final SelectionListener listener) { + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + control.addListener(SWT.Selection, typedListener); + } + + /** + * Remove a SelectionListener of a given Control + * + * @param control control on which the selection listener is removed + * @param listener listener to remove + */ + public static void removeSelectionListener(final Control control, final SelectionListener listener) { + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + final Listener[] listeners = control.getListeners(SWT.Selection); + for (Listener l : listeners) { + if (l instanceof TypedListener) { + TypedListener typedListener = (TypedListener) l; + if (typedListener.getEventListener() == listener) { + ReflectionUtils.callMethod(control, "removeListener", SWT.Selection, ((TypedListener) l).getEventListener()); + return; + } + } + } + } + + /** + * Fire the selection listeners of a given control + * + * @param control the control that fires the event + * @param sourceEvent mouse event + * @return true if the selection could be changed, false otherwise + */ + public static boolean fireSelectionListeners(final Control control, final Event sourceEvent) { + for (final Listener listener : control.getListeners(SWT.Selection)) { + final Event event = new Event(); + + event.button = sourceEvent==null?1:sourceEvent.button; + event.display = control.getDisplay(); + event.item = null; + event.widget = control; + event.data = sourceEvent == null ? null : sourceEvent.data; + event.time = sourceEvent == null ? 0 : sourceEvent.time; + event.x = sourceEvent == null ? 0 : sourceEvent.x; + event.y = sourceEvent == null ? 0 : sourceEvent.y; + event.type = SWT.Selection; + + listener.handleEvent(event); + if (!event.doit) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ZoomBar.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ZoomBar.java new file mode 100644 index 0000000..593a5a2 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/ZoomBar.java @@ -0,0 +1,127 @@ +package com.minres.scviewer.database.ui.swt.internal.slider; + +import java.text.Format; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.wb.swt.SWTResourceManager; + +public class ZoomBar extends Composite { + + static public interface IProvider { + ZoomBar getScrollBar(); + } + + final RangeSlider timeSlider; + final ImageButton leftButton; + final ImageButton rightButton; + /** + * Create the composite. + * @param parent + * @param style + */ + public ZoomBar(Composite parent, int style) { + super(parent, SWT.NO_FOCUS); + GridLayout gridLayout = new GridLayout(3, false); + gridLayout.horizontalSpacing = 0; + gridLayout.verticalSpacing = 0; + gridLayout.marginWidth = 0; + gridLayout.marginHeight = 0; + setLayout(gridLayout); + + leftButton = new ImageButton(this, SWT.NONE); + GridData gd_leftButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); + gd_leftButton.widthHint=14; + gd_leftButton.heightHint=18; + leftButton.setLayoutData(gd_leftButton); + leftButton.setImage(new Image[] { + SWTResourceManager.getImage(this.getClass(), "arrow_left.png"), + SWTResourceManager.getImage(this.getClass(), "arrow_left_hover.png"), + SWTResourceManager.getImage(this.getClass(), "arrow_left_pressed.png")}); + leftButton.setAutoFire(true); + + timeSlider = new RangeSlider(this, SWT.ON|SWT.HIGH|SWT.SMOOTH|SWT.CONTROL); + timeSlider.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + rightButton = new ImageButton(this, SWT.NONE); + GridData gd_rightButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); + gd_rightButton.widthHint=18; + gd_rightButton.heightHint=18; + rightButton.setLayoutData(gd_rightButton); + rightButton.setImage(new Image[] { + SWTResourceManager.getImage(this.getClass(), "arrow_right.png"), + SWTResourceManager.getImage(this.getClass(), "arrow_right_hover.png"), + SWTResourceManager.getImage(this.getClass(), "arrow_right_pressed.png")}); + rightButton.setAutoFire(true); + + leftButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int[] value = timeSlider.getSelection(); + int incr=timeSlider.getIncrement(); + int lower = Math.max(timeSlider.getMinimum(), value[0]-incr); + timeSlider.setValues(lower, lower + (value[1]-value[0]), true); + } + }); + rightButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int[] value = timeSlider.getSelection(); + int incr=timeSlider.getIncrement(); + int upper = Math.min(timeSlider.getMaximum(), value[1]+incr); + timeSlider.setValues(upper - (value[1]-value[0]), upper, true); + } + }); + + } + @Override + public void setEnabled (boolean enabled) { + timeSlider.setEnabled(enabled); + leftButton.setEnabled(enabled); + rightButton.setEnabled(enabled); + super.setEnabled(enabled); + redraw(); + } + public void setButtonsEnabled (boolean enabled) { + leftButton.setEnabled(enabled); + rightButton.setEnabled(enabled); + redraw(); + } + public void setToolTipFormatter(Format formatter){ + timeSlider.setToolTipFormatter(formatter); + } + public void setToolTipText(String string) { + timeSlider.setToolTipText(string); + } + public void setSelection(int sel) { + timeSlider.setLowerValue(sel); + } + public void setSelection(int[] sel) { + assert(sel.length==2); + timeSlider.setValues(sel[0], sel[1]); + } + public int[] getSelection() { + return timeSlider.getSelection(); + } + public void addSelectionListener(SelectionListener selectionListener) { + timeSlider.addSelectionListener(selectionListener); + } + public void setMinimum(int value) { + timeSlider.setMinimum(value); + } + public void setMaximum(int value) { + timeSlider.setMaximum(value); + } + public int getMaximum() { + return timeSlider.getMaximum(); + } + public int getMinimum() { + return timeSlider.getMinimum(); + } +} diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left.png new file mode 100644 index 0000000..61e7214 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_hover.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_hover.png new file mode 100644 index 0000000..61156c3 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_hover.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_pressed.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_pressed.png new file mode 100644 index 0000000..61e7214 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_left_pressed.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right.png new file mode 100644 index 0000000..c0c0b9a Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_hover.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_hover.png new file mode 100644 index 0000000..890472f Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_hover.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_pressed.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_pressed.png new file mode 100644 index 0000000..b37d47d Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/arrow_right_pressed.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l.png new file mode 100644 index 0000000..ce0e740 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_hover.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_hover.png new file mode 100644 index 0000000..452b8b3 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_hover.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_pressed.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_pressed.png new file mode 100644 index 0000000..3c41142 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_l_pressed.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r.png new file mode 100644 index 0000000..49f7b14 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_hover.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_hover.png new file mode 100644 index 0000000..8b3696e Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_hover.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_pressed.png b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_pressed.png new file mode 100644 index 0000000..e602b56 Binary files /dev/null and b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/internal/slider/marker_r_pressed.png differ diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ActionScheduler.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ActionScheduler.java new file mode 100644 index 0000000..8207914 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ActionScheduler.java @@ -0,0 +1,18 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.widgets.Display; + +public class ActionScheduler { + + private final Display display; + private final Runnable action; + + public ActionScheduler( Display display, Runnable action ) { + this.display = display; + this.action = action; + } + + public void schedule( int delay ) { + display.timerExec( delay, action ); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ButtonClick.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ButtonClick.java new file mode 100644 index 0000000..fe217a5 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ButtonClick.java @@ -0,0 +1,45 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; + +public class ButtonClick { + + public static final int LEFT_BUTTON = 1; + + private boolean armed; + + public boolean isArmed() { + return armed; + } + + public void arm( MouseEvent event ) { + if( event.button == LEFT_BUTTON ) { + armed = true; + } + } + + public void disarm() { + armed = false; + } + + public void trigger( MouseEvent event, Runnable action ) { + try { + doTrigger( event, action ); + } finally { + disarm(); + } + } + + private void doTrigger( MouseEvent event, Runnable action ) { + if( armed && inRange( event ) ) { + action.run(); + } + } + + private static boolean inRange( MouseEvent event ) { + Point size = ( ( Control )event.widget ).getSize(); + return event.x >= 0 && event.x <= size.x && event.y >= 0 && event.y <= size.y; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ClickControl.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ClickControl.java new file mode 100644 index 0000000..959d20e --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ClickControl.java @@ -0,0 +1,98 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + + +class ClickControl extends ControlAdapter implements ViewComponent, MouseDownActionTimer.TimerAction, MouseListener, MouseTrackListener { + + private final MouseDownActionTimer mouseDownActionTimer; + private final ClickAction clickAction; + private final ButtonClick buttonClick; + private final Label control; + private final ImageUpdate imageUpdate; + + public interface ClickAction extends Runnable { + void setCoordinates( int x, int y ); + } + + ClickControl( Composite parent, ClickAction clickAction, int maxExtension ) { + this.control = new Label( parent, SWT.NONE ); + this.imageUpdate = new ImageUpdate( control, maxExtension ); + this.buttonClick = new ButtonClick(); + this.mouseDownActionTimer = new MouseDownActionTimer( this, buttonClick, control.getDisplay() ); + this.clickAction = clickAction; + this.control.addMouseTrackListener( this ); + this.control.addMouseListener( this ); + this.control.addControlListener( this ); + } + + @Override + public void controlResized( ControlEvent event ) { + imageUpdate.update(); + } + + @Override + public Label getControl() { + return control; + } + + @Override + public void mouseDown( MouseEvent event ) { + buttonClick.arm( event ); + clickAction.setCoordinates( event.x, event.y ); + mouseDownActionTimer.activate(); + } + + @Override + public void mouseUp( MouseEvent event ) { + buttonClick.trigger( event, clickAction ); + } + + @Override + public void run() { + clickAction.run(); + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void mouseExit( MouseEvent event ) { + buttonClick.disarm(); + } + + void setForeground( Color color ) { + imageUpdate.setForeground( color ); + } + + Color getForeground() { + return imageUpdate.getForeground(); + } + + void setBackground( Color color ) { + imageUpdate.setBackground( color ); + } + + Color getBackground() { + return imageUpdate.getBackground(); + } + + @Override + public void mouseEnter( MouseEvent event ) {} + + @Override + public void mouseHover( MouseEvent event ) {} + + @Override + public void mouseDoubleClick( MouseEvent event ) {} +} diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ComponentDistribution.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ComponentDistribution.java new file mode 100644 index 0000000..0111ee1 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ComponentDistribution.java @@ -0,0 +1,105 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static java.lang.Math.max; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +class ComponentDistribution { + + private static final int MIN_DRAG_LENGTH = 17; + + final int upFastLength; + final int dragStart; + final int dragLength; + final int downFastStart; + final int downFastLength; + final int downStart; + final int buttonLen; + + ComponentDistribution( int buttonLen, int len, int range, int pos, int thumb ) { + int slideLen = slideLen( buttonLen, len ); + int relDragLen = relDragLen( slideLen, range, thumb ); + int minDragLength = max( MIN_DRAG_LENGTH, buttonLen ); + int interval = interval( range, relDragLen, minDragLength ); + this.dragLength = dragLen( minDragLength, relDragLen ); + this.upFastLength = upFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength ); + this.downStart = downStart( buttonLen, len ); + this.downFastStart = downFastStart( buttonLen, upFastLength, dragLength ); + this.dragStart = dragStart( buttonLen, upFastLength ); + this.downFastLength = downFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength, upFastLength ); + this.buttonLen = buttonLen; + } + + private static int slideLen( int buttonLen, int len ) { + return len - buttonLen * 2; + } + + private static int relDragLen( int slideLen, int range, int thumb ) { + return divide( slideLen * thumb, range ); + } + + private static int interval( int range, int relDragLen, int minDragLength ) { + int result = range; + if( useMinDragLen( minDragLength, relDragLen ) ) { + result += minDragLength - relDragLen / 2; + } + return result; + } + + private static int dragLen( int buttonLen, int relDragLen ) { + return max( relDragLen, buttonLen ); + } + + private static int upFastLen( int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen ) { + int result = slideLen * pos / range; + if( useMinDragLen( buttonLen, relDragLen ) ) { + result -= divide( ( dragLen - relDragLen ) * pos, range ); + } + return result; + } + + private static int downStart( int buttonLen, int len ) { + return len - buttonLen; + } + + private static int downFastStart( int buttonLen, int upFastLength, int dragLength ) { + return buttonLen + upFastLength + dragLength; + } + + private static int dragStart( int buttonLen, int upFastLen ) { + return buttonLen + upFastLen; + } + + private static int downFastLen( + int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen, int upFastLen ) + { + int result = divide( slideLen * ( range - pos ), range ) - dragLen; + if( useMinDragLen( buttonLen, relDragLen ) ) { + result += divide( ( dragLen - relDragLen ) * pos, range ); + } + return adjustDownFastLen( result, slideLen, dragLen, upFastLen ); + } + + private static boolean useMinDragLen( int buttonLen, int relDragLen ) { + return relDragLen < buttonLen; + } + + static int divide( int dividend, int divisor ) { + BigDecimal bigDividend = new BigDecimal( dividend ); + BigDecimal bigDivisor = new BigDecimal( divisor ); + return bigDividend .divide( bigDivisor, 0, RoundingMode.HALF_EVEN ) .intValue(); + } + + private static int adjustDownFastLen( int tentative, int slideLen, int dragLen, int upFastLen ) { + // TODO [fappel]: Without this there is a flickering of the downFast label of one pixel. + // Check whether this can be resolved by better rounding or whatsoever. + int result = tentative; + if( slideLen < upFastLen + dragLen + result ) { + result--; + } else if( slideLen > upFastLen + dragLen + result ) { + result++; + } + return result; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Decrementer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Decrementer.java new file mode 100644 index 0000000..5627882 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Decrementer.java @@ -0,0 +1,24 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; + +import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; + +class Decrementer implements ClickAction { + + private final FlatScrollBar scrollBar; + + Decrementer( FlatScrollBar scrollBar ) { + this.scrollBar = scrollBar; + } + + @Override + public void run() { + int selection = scrollBar.getSelection() - scrollBar.getIncrement(); + scrollBar.setSelectionInternal( selection, SWT.ARROW_UP ); + } + + @Override + public void setCoordinates( int x, int y ) { + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Direction.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Direction.java new file mode 100644 index 0000000..f2678ae --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Direction.java @@ -0,0 +1,203 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static com.minres.scviewer.database.ui.swt.sb.FlatScrollBar.BAR_BREADTH; +import static java.lang.Math.max; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +enum Direction { + + HORIZONTAL( SWT.HORIZONTAL ) { + + @Override + protected void layout( FlatScrollBar scrollBar, int buttonLength ) { + ComponentDistribution distribution = calculateComponentDistribution( scrollBar, buttonLength ); + Rectangle[] componentBounds = calculateComponentBounds( distribution, scrollBar ); + applyComponentBounds( scrollBar, componentBounds ); + } + + private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) { + return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).width ); + } + + private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) { + int width = getControlBounds( scrollBar ).width; + int height = getControlBounds( scrollBar ).height - FlatScrollBar.BAR_BREADTH + 1; + int balance = getRoundingBalance( distribution, scrollBar ); + return new Rectangle[] { + calcButtons( distribution, width, $( 0, CLEARANCE, distribution.buttonLen, height ) ), + $( distribution.buttonLen, CLEARANCE, distribution.upFastLength, height ), + calcDrag( distribution, $( distribution.dragStart, CLEARANCE, distribution.dragLength + balance, height ) ), + $( distribution.downFastStart, CLEARANCE, distribution.downFastLength - balance, height ), + calcButtons( distribution, width, $( distribution.downStart, CLEARANCE, distribution.buttonLen, height ) ) + }; + } + + private Rectangle calcButtons( ComponentDistribution distribution, int length, Rectangle bounds ) { + Rectangle result = bounds; + if( length <= distribution.buttonLen* 2 ) { + int downStart = calcDownStartForSmallLength( bounds.x, length ); + result = $( downStart, CLEARANCE, length / 2, bounds.height ); + } + return result; + } + + @Override + protected void setDefaultSize( Control control ) { + Point size = control.getSize(); + control.setSize( size.x, FlatScrollBar.BAR_BREADTH ); + } + + @Override + protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) { + int x = wHint == SWT.DEFAULT ? composite.getParent().getClientArea().width : wHint; + return new Point( x, FlatScrollBar.BAR_BREADTH ); + } + + @Override + protected void expand( Control control, int maxExpansion ) { + Rectangle bounds = control.getBounds(); + int expand = expand( bounds.height, maxExpansion ); + control.setBounds( bounds.x, bounds.y - expand, bounds.width, bounds.height + expand ); + } + }, + + VERTICAL( SWT.VERTICAL ) { + + @Override + protected void layout( FlatScrollBar scrollBar, int buttonLength ) { + ComponentDistribution calculation = calculateComponentDistribution( scrollBar, buttonLength ); + applyComponentBounds( scrollBar, calculateComponentBounds( calculation, scrollBar ) ); + } + + private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) { + return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).height ); + } + + private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) { + int width = getControlBounds( scrollBar ).width - FlatScrollBar.BAR_BREADTH + 1; + int height = getControlBounds( scrollBar ).height; + int balance = getRoundingBalance( distribution, scrollBar ); + return new Rectangle[] { + calculateButtons( distribution, height, $( CLEARANCE, 0, width, distribution.buttonLen ) ), + $( CLEARANCE, distribution.buttonLen, width, distribution.upFastLength ), + calcDrag( distribution, $( CLEARANCE, distribution.dragStart, width, distribution.dragLength + balance ) ), + $( CLEARANCE, distribution.downFastStart, width, distribution.downFastLength - balance ), + calculateButtons( distribution, height, $( CLEARANCE, distribution.downStart, width, distribution.buttonLen ) ) + }; + } + + private Rectangle calculateButtons( ComponentDistribution distribution, int length, Rectangle bounds ) { + Rectangle result = bounds; + if( length <= distribution.buttonLen * 2 ) { + int downStart = calcDownStartForSmallLength( bounds.y, length ); + result = $( CLEARANCE, downStart, bounds.width, length / 2 ); + } + return result; + } + + @Override + protected void setDefaultSize( Control control ) { + Point size = control.getSize(); + control.setSize( FlatScrollBar.BAR_BREADTH, size.y ); + } + + @Override + protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) { + int y = hHint == SWT.DEFAULT ? composite.getParent().getClientArea().height : hHint; + return new Point( FlatScrollBar.BAR_BREADTH, y ); + } + + @Override + protected void expand( Control control, int maxExpansion ) { + Rectangle bounds = control.getBounds(); + int expand = expand( bounds.width, maxExpansion ); + control.setBounds( bounds.x - expand, bounds.y, bounds.width + expand, bounds.height ); + } + }; + + static final Rectangle EMPTY_RECTANGLE = $( 0, 0, 0, 0 ); + static final int CLEARANCE = BAR_BREADTH - 2; + + private final int value; + + protected abstract void layout( FlatScrollBar scrollBar, int buttonLength ); + protected abstract void setDefaultSize( Control control ); + protected abstract Point computeSize( Composite comp, int wHint, int hHint, boolean changed ); + protected abstract void expand( Control control, int maxExpansion ); + + Direction( int value ) { + this.value = value; + } + + public int value() { + return value; + } + + private static ComponentDistribution calculateComponentDistribution( + FlatScrollBar scrollBar , int buttonLength , int length ) + { + int range = scrollBar.getMaximum() - scrollBar.getMinimum(); + int position = scrollBar.getSelection() - scrollBar.getMinimum(); + int thumb = scrollBar.getThumb(); + return new ComponentDistribution( buttonLength, length, range, position, thumb ); + } + + private static Rectangle getControlBounds( FlatScrollBar scrollBar ) { + return scrollBar.getClientArea(); + } + + private static void applyComponentBounds( FlatScrollBar scrollBar, Rectangle[] bounds ) { + scrollBar.up.getControl().setBounds( bounds[ 0 ] ); + scrollBar.upFast.getControl().setBounds( bounds[ 1 ] ); + scrollBar.drag.getControl().setBounds( bounds[ 2 ] ); + scrollBar.downFast.getControl().setBounds( bounds[ 3 ] ); + scrollBar.down.getControl().setBounds( bounds[ 4 ] ); + } + + // TODO [fappel]: There is a 1 pixel rounding problem at the seam of drag/downFast with down. + // Seems to work but I would prefer a better solution if possible + private static int getRoundingBalance( ComponentDistribution calculation, FlatScrollBar scrollBar ) { + int result = 0; + int maximumSelection = scrollBar.getMaximum() - scrollBar.getThumb(); + if( scrollBar.getSelection() == maximumSelection && 0 != calculation.downFastLength ) { + result = 1; + } + return result; + } + + private static int expand( int toExpand, int maxExpansion ) { + return max( 0, FlatScrollBar.BAR_BREADTH + maxExpansion - max( FlatScrollBar.BAR_BREADTH, toExpand ) ); + } + + private static Rectangle calcDrag( ComponentDistribution distribution, Rectangle bounds ) { + Rectangle result = bounds; + if( isUndercutOfDragVisibility( distribution ) ) { + result = EMPTY_RECTANGLE; + } + return result; + } + + private static boolean isUndercutOfDragVisibility( ComponentDistribution distribution ) { + return distribution.dragLength + distribution.buttonLen >= distribution.downStart; + } + + private static int calcDownStartForSmallLength( int position, int length ) { + int result = position; + if( isDownStartPosition( position ) ) { + result = length / 2; + } + return result; + } + private static boolean isDownStartPosition( int position ) { + return position > 0 || position < 0; + } + + private static Rectangle $( int x, int y, int width, int height ) { + return new Rectangle( x, y , width , height ); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragControl.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragControl.java new file mode 100644 index 0000000..4ca38eb --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragControl.java @@ -0,0 +1,105 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.DragDetectEvent; +import org.eclipse.swt.events.DragDetectListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + + +class DragControl + extends ControlAdapter + implements ViewComponent, DragDetectListener, MouseListener, MouseMoveListener +{ + + private final DragDetector dragDetector; + private final ImageUpdate imageUpdate; + private final DragAction dragAction; + private final Label control; + + private Point startingPosition; + + public interface DragAction { + void start(); + void run( int startX, int startY, int currentX, int currentY ); + void end(); + } + + DragControl( Composite parent, DragAction dragAction, int maxExpansion ) { + this.control = new Label( parent, SWT.NONE ); + this.imageUpdate = new ImageUpdate( control, maxExpansion ); + this.dragDetector = new DragDetector( control, 0 ); + this.dragAction = dragAction; + initializeControl(); + } + + @Override + public Label getControl() { + return control; + } + + @Override + public void dragDetected( DragDetectEvent event ) { + if( startingPosition != null ) { + dragAction.run( startingPosition.x, startingPosition.y, event.x, event.y ); + } + dragDetector.dragHandled(); + } + + @Override + public void mouseDown( MouseEvent event ) { + startingPosition = new Point( event.x, event.y ); + dragAction.start(); + } + + @Override + public void mouseUp( MouseEvent event ) { + if( startingPosition != null ) { + dragAction.end(); + } + startingPosition = null; + } + + @Override + public void mouseMove( MouseEvent event ) { + dragDetector.mouseMove( event ); + } + + @Override + public void controlResized( ControlEvent event ) { + imageUpdate.update(); + } + + void setForeground( Color color ) { + imageUpdate.setForeground( color ); + } + + Color getForeground() { + return imageUpdate.getForeground(); + } + + Color getBackground() { + return imageUpdate.getBackground(); + } + + void setBackground( Color color ) { + imageUpdate.setBackground( color ); + } + + private void initializeControl( ) { + control.addMouseListener( this ); + control.addMouseMoveListener( this ); + control.addControlListener( this ); + control.addDragDetectListener( this ); + } + + @Override + public void mouseDoubleClick( MouseEvent event ) {} +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragDetector.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragDetector.java new file mode 100644 index 0000000..b3e33a6 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragDetector.java @@ -0,0 +1,60 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; + +// TODO [fappel]: This is a workaround for a problem described here: +// http://stackoverflow.com/questions/3908290/mousedown-events-are-not-delivered-until-mouseup-when-a-drag-source-is-present +// This seems to be related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=328396 +// which is resolved. As it did not work on my setup I adapted the workaround of the last +// stackoverflow answer. + +public class DragDetector { + + int lastMouseX; + int lastMouseY; + boolean dragEventGenerated; + + private final Control control; + private final int sensibility; + + public DragDetector( Control control, int sensibility ) { + this.control = control; + this.sensibility = sensibility; + this.control.setDragDetect( false ); + } + + public void mouseMove( MouseEvent e ) { + if( ( e.stateMask & SWT.BUTTON1 ) > 0 ) { + int deltaX = lastMouseX - e.x; + int deltaY = lastMouseY - e.y; + int dragDistance = deltaX * deltaX + deltaY * deltaY; + if( !dragEventGenerated && dragDistance > sensibility ) { + dragEventGenerated = true; + Event event = createDragEvent( e ); + control.notifyListeners( SWT.DragDetect, event ); + } + lastMouseX = e.x; + lastMouseY = e.y; + } + } + + public void dragHandled() { + dragEventGenerated = false; + } + + private Event createDragEvent( MouseEvent e ) { + Event event = new Event(); + event.type = SWT.DragDetect; + event.display = control.getDisplay(); + event.widget = control; + event.button = e.button; + event.stateMask = e.stateMask; + event.time = e.time; + event.x = e.x; + event.y = e.y; + return event; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragShifter.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragShifter.java new file mode 100644 index 0000000..289223d --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/DragShifter.java @@ -0,0 +1,59 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL; +import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; + +import com.minres.scviewer.database.ui.swt.sb.DragControl.DragAction; + +final class DragShifter implements DragAction { + + private final FlatScrollBar scrollBar; + private final int buttonLength; + + public DragShifter( FlatScrollBar scrollBar, int buttonLength ) { + this.scrollBar = scrollBar; + this.buttonLength = buttonLength; + } + + @Override + public void start() { + scrollBar.notifyListeners( SWT.DRAG ); + } + + @Override + public void run( int startX, int startY, int currentX, int currentY ) { + ShiftData shiftData = newShiftData( startX, startY, currentX, currentY ); + if( shiftData.canShift() ) { + int selectionRange = calculateSelectionRange( scrollBar ); + int selectionDelta = shiftData.calculateSelectionDelta( selectionRange ); + int selection = scrollBar.getSelection() + selectionDelta; + scrollBar.setSelectionInternal( selection, SWT.DRAG ); + } + } + + @Override + public void end() { + scrollBar.notifyListeners( SWT.NONE ); + } + + private ShiftData newShiftData( int startX, int startY, int currentX, int currentY ) { + ShiftData result; + if( scrollBar.direction == HORIZONTAL ) { + result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, currentX - startX ); + } else { + result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, currentY - startY ); + } + return result; + } + + private Point getScrollBarSize() { + return scrollBar.getSize(); + } + + private Point getDragSize() { + return scrollBar.drag.getControl().getSize(); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastDecrementer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastDecrementer.java new file mode 100644 index 0000000..744f522 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastDecrementer.java @@ -0,0 +1,49 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; + +class FastDecrementer implements ClickAction { + + private final FlatScrollBar scrollBar; + + private int x; + private int y; + + FastDecrementer( FlatScrollBar scrollBar ) { + this.scrollBar = scrollBar; + } + + @Override + public void run() { + Rectangle drag = getDragBounds(); + Point mouse = getMouseLocation(); + if( mouse.x <= drag.x || mouse.y <= drag.y ) { + int selection = scrollBar.getSelection() - scrollBar.getPageIncrement(); + scrollBar.setSelectionInternal( selection, SWT.PAGE_UP ); + } + } + + @Override + public void setCoordinates( int x, int y ) { + this.x = x; + this.y = y; + } + + private Point getMouseLocation() { + return getDisplay().map( scrollBar.upFast.getControl(), null, x, y ); + } + + private Rectangle getDragBounds() { + Rectangle dragBounds = scrollBar.drag.getControl().getBounds(); + return getDisplay().map( scrollBar, null, dragBounds ); + } + + private Display getDisplay() { + return scrollBar.getDisplay(); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastIncrementer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastIncrementer.java new file mode 100644 index 0000000..5ce4181 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FastIncrementer.java @@ -0,0 +1,42 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; + +class FastIncrementer implements ClickAction { + + private final FlatScrollBar scrollBar; + + private Point mouse; + + FastIncrementer( FlatScrollBar scrollBar ) { + this.scrollBar = scrollBar; + } + + @Override + public void run() { + Rectangle drag = getDragBounds(); + if( mouse.x > drag.x + drag.width || mouse.y > drag.y + drag.height ) { + int selection = scrollBar.getSelection() + scrollBar.getPageIncrement(); + scrollBar.setSelectionInternal( selection, SWT.PAGE_DOWN ); + } + } + + @Override + public void setCoordinates( int x, int y ) { + mouse = getMouseLocation( x, y ); + } + + private Point getMouseLocation(int x, int y) { + return Display.getCurrent().map( scrollBar.downFast.getControl(), null, x, y ); + } + + private Rectangle getDragBounds() { + Rectangle dragBounds = scrollBar.drag.getControl().getBounds(); + return Display.getCurrent().map( scrollBar, null, dragBounds ); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBar.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBar.java new file mode 100644 index 0000000..802d86a --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBar.java @@ -0,0 +1,295 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static com.minres.scviewer.database.ui.swt.sb.UntypedSelectionAdapter.lookup; + +import java.util.Collection; +import java.util.HashSet; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.Listener; + +public class FlatScrollBar extends Composite { + + public static final int BAR_BREADTH = 6; + + static final int DEFAULT_MINIMUM = 0; + static final int DEFAULT_MAXIMUM = 100; + static final int DEFAULT_INCREMENT = 1; + static final int DEFAULT_THUMB = 10; + static final int DEFAULT_PAGE_INCREMENT = DEFAULT_THUMB; + static final int DEFAULT_SELECTION = 0; + static final int DEFAULT_BUTTON_LENGTH = 0; + static final int DEFAULT_MAX_EXPANSION = Direction.CLEARANCE + 2; + + final ClickControl up; + final ClickControl upFast; + final DragControl drag; + final ClickControl downFast; + final ClickControl down; + final Direction direction; + final MouseWheelShifter mouseWheelHandler; + final Collection listeners; + + private int minimum; + private int maximum; + private int increment; + private int pageIncrement; + private int thumb; + private int selection; + private boolean onDrag; + private int buttonLength; + + public FlatScrollBar( final Composite parent, int style ) { + this( parent, style, DEFAULT_BUTTON_LENGTH, DEFAULT_MAX_EXPANSION ); + } + + FlatScrollBar( Composite parent, int style, int buttonLength, int maxExpansion ) { + super( parent, SWT.NONE ); + super.setLayout( new FlatScrollBarLayout( getDirection( style ) ) ); + this.minimum = DEFAULT_MINIMUM; + this.maximum = DEFAULT_MAXIMUM; + this.increment = DEFAULT_INCREMENT; + this.pageIncrement = DEFAULT_PAGE_INCREMENT; + this.thumb = DEFAULT_THUMB; + this.selection = DEFAULT_SELECTION; + this.buttonLength = buttonLength; + this.direction = getDirection( style ); + this.direction.setDefaultSize( this ); + this.up = new ClickControl( this, new Decrementer( this ), maxExpansion ); + this.upFast = new ClickControl( this, new FastDecrementer( this ), maxExpansion ); + this.drag = new DragControl( this, new DragShifter( this, buttonLength ), maxExpansion ); + this.downFast = new ClickControl( this, new FastIncrementer( this ), maxExpansion ); + this.down = new ClickControl( this, new Incrementer( this ), maxExpansion ); + this.mouseWheelHandler = new MouseWheelShifter( this, parent, buttonLength ); + this.listeners = new HashSet(); + addMouseTrackListener( new MouseTracker( this, maxExpansion ) ); + addControlListener( new ResizeObserver( this ) ); + setDefaultColorScheme(); + } + + @Override + public void setLayout( Layout layout ) { + throw new UnsupportedOperationException( FlatScrollBar.class.getName() + " does not allow to change layout." ); + }; + + @Override + public int getStyle() { + return direction != null ? super.getStyle() | direction.value() : super.getStyle(); + }; + + Direction getDirection() { + return direction; + } + + public void setMinimum( int minimum ) { + if( this.minimum != minimum && minimum >= 0 && minimum < maximum ) { + this.minimum = minimum; + adjustThumb(); + adjustSelection(); + layout(); + } + } + + public int getMinimum() { + return minimum; + } + + public void setMaximum( int maximum ) { + if( this.maximum != maximum && maximum >= 0 && maximum > minimum ) { + this.maximum = maximum; + adjustThumb(); + adjustSelection(); + layout(); + } + } + + public int getMaximum() { + return maximum; + } + + public void setThumb( int thumb ) { + if( this.thumb != thumb && thumb >= 1 ) { + this.thumb = thumb; + adjustThumb(); + adjustSelection(); + layout(); + } + } + + public int getThumb() { + return thumb; + } + + public void setIncrement( int increment ) { + if( this.increment != increment ) { + this.increment = increment; + layout(); + } + } + + public int getIncrement() { + return increment; + } + + public void setPageIncrement( int pageIncrement ) { + this.pageIncrement = pageIncrement; + } + + public int getPageIncrement() { + return pageIncrement; + } + + public void setSelection( int selection ) { + if( !onDrag ) { + updateSelection( selection ); + } + } + + public int getSelection() { + return selection; + } + + public void addSelectionListener( SelectionListener selectionListener ) { + listeners.add( selectionListener ); + } + + public void removeSelectionListener( SelectionListener selectionListener ) { + listeners.remove( selectionListener ); + } + + @Override + public void addListener( int eventType, final Listener listener ) { + if( eventType == SWT.Selection ) { + addSelectionListener( new UntypedSelectionAdapter( listener ) ); + } else { + super.addListener( eventType, listener ); + } + } + + @Override + public void removeListener( int eventType, Listener listener ) { + if( eventType == SWT.Selection ) { + removeSelectionListener( lookup( listeners, listener ) ); + } else { + super.removeListener( eventType, listener ); + } + } + + @Override + public void layout() { + direction.layout( this, buttonLength ); + update(); + } + + public void setIncrementButtonLength( int length ) { + this.buttonLength = length; + layout(); + } + + public int getIncrementButtonLength() { + return buttonLength; + } + + public void setIncrementColor( Color color ) { + up.setForeground( color ); + down.setForeground( color ); + } + + public Color getIncrementColor() { + return up.getForeground(); + } + + public void setPageIncrementColor( Color color ) { + upFast.setForeground( color ); + downFast.setForeground( color ); + } + + public Color getPageIncrementColor() { + return upFast.getForeground(); + } + + public void setThumbColor( Color color ) { + drag.setForeground( color ); + } + + public Color getThumbColor() { + return drag.getForeground(); + } + + @Override + public void setBackground( Color color ) { + up.setBackground( color ); + upFast.setBackground( color ); + drag.setBackground( color ); + downFast.setBackground( color ); + down.setBackground( color ); + super.setBackground( color ); + } + + protected void setSelectionInternal( int selection, int detail ) { + int oldSelection = this.selection; + updateSelection( selection ); + if( oldSelection != this.selection ) { + notifyListeners( detail ); + } + } + + private void updateSelection( int selection ) { + if( this.selection != selection ) { + this.selection = selection; + adjustSelection(); + layout(); + } + } + + public void notifyListeners( int detail ) { + updateOnDrag( detail ); + SelectionEvent selectionEvent = createEvent( detail ); + for( SelectionListener listener : listeners ) { + listener.widgetSelected( selectionEvent ); + } + } + + private void updateOnDrag( int detail ) { + onDrag = ( onDrag || ( SWT.DRAG & detail ) > 0 ) && ( SWT.NONE != detail ); + } + + private SelectionEvent createEvent( int detail ) { + Event event = new Event(); + event.widget = this; + event.detail = detail; + return new SelectionEvent( event ); + } + + private void adjustThumb() { + if( thumb > maximum - minimum ) { + thumb = Math.min( maximum - minimum, thumb ); + thumb = Math.max( 1, thumb ); + } + } + + private void adjustSelection() { + selection = Math.min( selection, maximum - thumb ); + selection = Math.max( selection, minimum ); + } + + private static Direction getDirection( int style ) { + return ( style & SWT.HORIZONTAL ) > 0 ? Direction.HORIZONTAL : Direction.VERTICAL; + } + + private void setDefaultColorScheme() { + up.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) ); + upFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) ); + drag.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_FOREGROUND ) ); + downFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) ); + down.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) ); + setBackground( getBackground() ); + } +} diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBarLayout.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBarLayout.java new file mode 100644 index 0000000..b8106bb --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/FlatScrollBarLayout.java @@ -0,0 +1,23 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Layout; + +class FlatScrollBarLayout extends Layout { + + private final Direction direction; + + public FlatScrollBarLayout( Direction orientation ) { + this.direction = orientation; + } + + @Override + protected void layout( Composite composite, boolean flushCache ) { + } + + @Override + protected Point computeSize( Composite composite, int wHint, int hHint, boolean flushCache ) { + return direction.computeSize( composite, wHint, hHint, flushCache ); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageDrawer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageDrawer.java new file mode 100644 index 0000000..8fb7495 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageDrawer.java @@ -0,0 +1,109 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static java.lang.Math.min; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +class ImageDrawer { + + static final String IMAGE_DRAWER_IS_DISPOSED = "ImageDrawer is disposed."; + + private final int maxExpansion; + + private Color background; + private Color foreground; + + ImageDrawer( int expansion ) { + this( expansion, getSystemColor( SWT.COLOR_WIDGET_DARK_SHADOW ), getSystemColor( SWT.COLOR_LIST_BACKGROUND ) ); + } + + ImageDrawer( int expansion, Color background, Color foreground ) { + this.maxExpansion = expansion; + this.foreground = defensiveCopy( background ); + this.background = defensiveCopy( foreground ); + } + + void setForeground( Color foreground ) { + checkDisposed(); + if( foreground != null ) { + this.foreground = prepareColorAttribute( this.foreground, foreground ); + } + } + + Color getForeground() { + checkDisposed(); + return foreground; + } + + void setBackground( Color background ) { + checkDisposed(); + if( background != null ) { + this.background = prepareColorAttribute( this.background, background ); + } + } + + Color getBackground() { + checkDisposed(); + return background; + } + + Image draw( int width, int height ) { + checkDisposed(); + Image result = new Image( getDisplay(), width, height ); + GC gc = new GC( result ); + try { + draw( gc, width, height ); + } finally { + gc.dispose(); + } + return result; + } + + boolean isDisposed() { + return background.isDisposed(); + } + + void dispose() { + if( !isDisposed() ) { + this.background.dispose(); + this.foreground.dispose(); + } + } + + private void draw( GC gc, int width, int height ) { + gc.setBackground( background ); + gc.fillRectangle( 0, 0, width, height ); + gc.setBackground( foreground ); + gc.setAdvanced( true ); + gc.setAntialias( SWT.ON ); + int arc = min( width, height ) == 1 ? 1 : maxExpansion + 2; + gc.fillRoundRectangle( 0, 0, width, height, arc, arc ); + } + + private void checkDisposed() { + if( isDisposed() ) { + throw new IllegalStateException( IMAGE_DRAWER_IS_DISPOSED ); + } + } + + private static Color getSystemColor( int colorCode ) { + return getDisplay().getSystemColor( colorCode ); + } + + private static Color prepareColorAttribute( Color oldColor, Color newColor ) { + oldColor.dispose(); + return defensiveCopy( newColor ); + } + + private static Color defensiveCopy( Color background ) { + return new Color( getDisplay(), background.getRGB() ); + } + + private static Display getDisplay() { + return Display.getCurrent(); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageUpdate.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageUpdate.java new file mode 100644 index 0000000..73719a9 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ImageUpdate.java @@ -0,0 +1,46 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Label; + +class ImageUpdate { + + private final ImageDrawer imageDrawer; + private final Label control; + + ImageUpdate( Label control, int maxExpansion ) { + this.imageDrawer = new ImageDrawer( maxExpansion ); + this.control = control; + this.control.addListener( SWT.Dispose, evt -> imageDrawer.dispose() ); + } + + void setForeground( Color color ) { + imageDrawer.setForeground( color ); + } + + Color getForeground() { + return imageDrawer.getForeground(); + } + + void setBackground( Color color ) { + imageDrawer.setBackground( color ); + } + + Color getBackground() { + return imageDrawer.getBackground(); + } + + void update() { + if( !control.isDisposed() ) { + if( control.getImage() != null ) { + control.getImage().dispose(); + } + Point size = control.getSize(); + if( size.x > 0 && size.y > 0 ) { + control.setImage( imageDrawer.draw( size.x, size.y ) ); + } + } + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Incrementer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Incrementer.java new file mode 100644 index 0000000..351e058 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/Incrementer.java @@ -0,0 +1,24 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.SWT; + +import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; + +class Incrementer implements ClickAction { + + private final FlatScrollBar scrollBar; + + Incrementer( FlatScrollBar scrollBar ) { + this.scrollBar = scrollBar; + } + + @Override + public void run() { + int selection = scrollBar.getSelection() + scrollBar.getIncrement(); + scrollBar.setSelectionInternal( selection, SWT.ARROW_DOWN ); + } + + @Override + public void setCoordinates( int x, int y ) { + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseDownActionTimer.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseDownActionTimer.java new file mode 100644 index 0000000..1de6295 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseDownActionTimer.java @@ -0,0 +1,37 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.widgets.Display; + +public class MouseDownActionTimer implements Runnable { + + public static final int INITIAL_DELAY = 300; + public static final int FAST_DELAY = 50; + + private final ActionScheduler scheduler; + private final TimerAction timerAction; + private final ButtonClick mouseClick; + + public interface TimerAction extends Runnable { + boolean isEnabled(); + } + + public MouseDownActionTimer( TimerAction timerAction, ButtonClick mouseClick, Display display ) { + this.scheduler = new ActionScheduler( display, this ); + this.timerAction = timerAction; + this.mouseClick = mouseClick; + } + + public void activate() { + if( timerAction.isEnabled() ) { + scheduler.schedule( INITIAL_DELAY ); + } + } + + @Override + public void run() { + if( mouseClick.isArmed() && timerAction.isEnabled() ) { + timerAction.run(); + scheduler.schedule( FAST_DELAY ); + } + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseTracker.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseTracker.java new file mode 100644 index 0000000..f36e825 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseTracker.java @@ -0,0 +1,66 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackAdapter; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +class MouseTracker extends MouseTrackAdapter implements Runnable, DisposeListener { + + static final int DELAY = 500; + + private final FlatScrollBar scrollBar; + private final int maxExpansion; + + private Rectangle expandedBounds; + private Rectangle originBounds; + private boolean mouseOver; + private boolean disposed; + + MouseTracker( FlatScrollBar scrollBar, int maxExpansion ) { + this.scrollBar = scrollBar; + this.maxExpansion = maxExpansion; + this.scrollBar.addDisposeListener( this ); + this.scrollBar.up.getControl().addMouseTrackListener( this ); + this.scrollBar.upFast.getControl().addMouseTrackListener( this ); + this.scrollBar.drag.getControl().addMouseTrackListener( this ); + this.scrollBar.downFast.getControl().addMouseTrackListener( this ); + this.scrollBar.down.getControl().addMouseTrackListener( this ); + } + + @Override + public void mouseEnter( MouseEvent event ) { + mouseOver = true; + if( !disposed && originBounds == null ) { + originBounds = scrollBar.getBounds(); + scrollBar.getDirection().expand( scrollBar, maxExpansion ); + expandedBounds = scrollBar.getBounds(); + } + } + + @Override + public void mouseExit( MouseEvent event ) { + mouseOver = false; + if( !disposed ) { + Display.getCurrent().timerExec( DELAY, this ); + } + } + + @Override + public void run() { + if( !disposed && !mouseOver ) { + if( scrollBar.getBounds().equals( expandedBounds ) ) { + scrollBar.setBounds( originBounds ); + } + originBounds = null; + expandedBounds = null; + } + } + + @Override + public void widgetDisposed( DisposeEvent e ) { + disposed = true; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseWheelShifter.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseWheelShifter.java new file mode 100644 index 0000000..4baa1be --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/MouseWheelShifter.java @@ -0,0 +1,69 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL; +import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +public class MouseWheelShifter implements Listener, DisposeListener { + + private final FlatScrollBar scrollBar; + private final Composite parent; + private final int buttonLength; + + MouseWheelShifter( FlatScrollBar scrollBar, Composite parent, int buttonLength ) { + this.scrollBar = scrollBar; + this.parent = parent; + this.buttonLength = buttonLength; + parent.addListener( getListenerType(), this ); + scrollBar.addDisposeListener( this ); + } + + @Override + public void handleEvent( Event event ) { + handleMouseWheelScroll( event ); + } + + @Override + public void widgetDisposed( DisposeEvent e ) { + parent.removeListener( getListenerType(), this ); + } + + private void handleMouseWheelScroll( Event event ) { + ShiftData shiftData = newShiftData( event.count ); + if( shiftData.canShift() ) { + int selectionRange = calculateSelectionRange( scrollBar ); + int selectionDelta = shiftData.calculateSelectionDelta( selectionRange ); + int selection = scrollBar.getSelection() - selectionDelta; + scrollBar.setSelectionInternal( selection, scrollBar.direction.value() ); + } + } + + private ShiftData newShiftData( int delta ) { + ShiftData result; + if( scrollBar.direction == Direction.HORIZONTAL ) { + result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, delta ); + } else { + result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, delta ); + } + return result; + } + + private Point getScrollBarSize() { + return scrollBar.getSize(); + } + + private Point getDragSize() { + return scrollBar.drag.getControl().getSize(); + } + + private int getListenerType() { + return scrollBar.direction == HORIZONTAL ? SWT.MouseHorizontalWheel: SWT.MouseVerticalWheel; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ResizeObserver.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ResizeObserver.java new file mode 100644 index 0000000..20cb2b3 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ResizeObserver.java @@ -0,0 +1,19 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; + +class ResizeObserver extends ControlAdapter { + + private final FlatScrollBar flatScrollBar; + + public ResizeObserver( FlatScrollBar flatScrollBar ) { + this.flatScrollBar = flatScrollBar; + } + + @Override + public void controlResized( ControlEvent event ) { + flatScrollBar.layout(); + flatScrollBar.moveAbove( null ); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ShiftData.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ShiftData.java new file mode 100644 index 0000000..0bdeccd --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ShiftData.java @@ -0,0 +1,32 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import static com.minres.scviewer.database.ui.swt.sb.ComponentDistribution.divide; + +class ShiftData { + + private final int slidePixels; + private final int movedPixels; + private final int buttonLength; + + ShiftData( int buttonLength, int scrollBarPixels, int dragPixels, int movedPixels ) { + this.buttonLength = buttonLength; + this.slidePixels = calculateSlidePixels( scrollBarPixels, dragPixels ); + this.movedPixels = movedPixels; + } + + boolean canShift( ) { + return slidePixels > 0; + } + + int calculateSelectionDelta( int selectionRange ) { + return divide( movedPixels * selectionRange, slidePixels ); + } + + static int calculateSelectionRange( FlatScrollBar scrollBar ) { + return scrollBar.getMaximum() - scrollBar.getMinimum() - scrollBar.getThumb(); + } + + private int calculateSlidePixels( int scrollBarPixels, int dragPixels ) { + return scrollBarPixels - 2 * buttonLength - dragPixels; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/UntypedSelectionAdapter.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/UntypedSelectionAdapter.java new file mode 100644 index 0000000..d5fffd8 --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/UntypedSelectionAdapter.java @@ -0,0 +1,43 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import java.util.Collection; + +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +class UntypedSelectionAdapter extends SelectionAdapter { + + final Listener listener; + + UntypedSelectionAdapter( Listener listener ) { + this.listener = listener; + } + + @Override + public void widgetSelected( SelectionEvent selectionEvent ) { + Event event = new Event(); + event.widget = selectionEvent.widget; + event.detail = selectionEvent.detail; + listener.handleEvent( event ); + } + + static SelectionListener lookup( Collection listeners, Listener untypedListener ) { + for( SelectionListener listener : listeners ) { + if( isAdapterType( listener ) && matches( untypedListener, listener ) ) { + return listener; + } + } + return null; + } + + private static boolean isAdapterType( SelectionListener listener ) { + return listener instanceof UntypedSelectionAdapter; + } + + private static boolean matches( Listener untypedListener, SelectionListener listener ) { + return ( ( UntypedSelectionAdapter )listener ).listener == untypedListener; + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ViewComponent.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ViewComponent.java new file mode 100644 index 0000000..af1779c --- /dev/null +++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/swt/sb/ViewComponent.java @@ -0,0 +1,7 @@ +package com.minres.scviewer.database.ui.swt.sb; + +import org.eclipse.swt.widgets.Control; + +public interface ViewComponent { + Control getControl(); +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/org/eclipse/wb/swt/SWTResourceManager.java b/plugins/com.minres.scviewer.database.ui.swt/src/org/eclipse/wb/swt/SWTResourceManager.java index 0024a03..d8a2858 100644 --- a/plugins/com.minres.scviewer.database.ui.swt/src/org/eclipse/wb/swt/SWTResourceManager.java +++ b/plugins/com.minres.scviewer.database.ui.swt/src/org/eclipse/wb/swt/SWTResourceManager.java @@ -29,17 +29,14 @@ import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; /** - * Utility class for managing OS resources associated with SWT controls such as - * colors, fonts, images, etc. + * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc. *

- * !!! IMPORTANT !!! Application code must explicitly invoke the - * dispose() method to release the operating system resources - * managed by cached objects when those objects and OS resources are no longer + * !!! IMPORTANT !!! Application code must explicitly invoke the dispose() method to release the + * operating system resources managed by cached objects when those objects and OS resources are no longer * needed (e.g. on application shutdown) *

* This class may be freely distributed as part of any application or plugin. *

- * * @author scheglov_ke * @author Dan Rubel */ @@ -49,54 +46,57 @@ public class SWTResourceManager { // Color // //////////////////////////////////////////////////////////////////////////// - private static Map colorMap = new HashMap<>(); - - private SWTResourceManager() {} - + private static Map m_colorMap = new HashMap(); /** * Returns the system {@link Color} matching the specific ID. * - * @param systemColorID the ID value for the color + * @param systemColorID + * the ID value for the color * @return the system {@link Color} matching the specific ID */ public static Color getColor(int systemColorID) { Display display = Display.getCurrent(); return display.getSystemColor(systemColorID); } - /** * Returns a {@link Color} given its red, green and blue component values. * - * @param r the red component of the color - * @param g the green component of the color - * @param b the blue component of the color - * @return the {@link Color} matching the given red, green and blue component - * values + * @param r + * the red component of the color + * @param g + * the green component of the color + * @param b + * the blue component of the color + * @return the {@link Color} matching the given red, green and blue component values */ public static Color getColor(int r, int g, int b) { return getColor(new RGB(r, g, b)); } - /** * Returns a {@link Color} given its RGB value. * - * @param rgb the {@link RGB} value of the color + * @param rgb + * the {@link RGB} value of the color * @return the {@link Color} matching the RGB value */ public static Color getColor(RGB rgb) { - return colorMap.computeIfAbsent(rgb, k -> new Color(Display.getCurrent(), rgb)); + Color color = m_colorMap.get(rgb); + if (color == null) { + Display display = Display.getCurrent(); + color = new Color(display, rgb); + m_colorMap.put(rgb, color); + } + return color; } - /** * Dispose of all the cached {@link Color}'s. */ public static void disposeColors() { - for (Color color : colorMap.values()) { + for (Color color : m_colorMap.values()) { color.dispose(); } - colorMap.clear(); + m_colorMap.clear(); } - //////////////////////////////////////////////////////////////////////////// // // Image @@ -105,12 +105,12 @@ public class SWTResourceManager { /** * Maps image paths to images. */ - private static Map imageMap = new HashMap<>(); - + private static Map m_imageMap = new HashMap(); /** * Returns an {@link Image} encoded by the specified {@link InputStream}. * - * @param stream the {@link InputStream} encoding the image data + * @param stream + * the {@link InputStream} encoding the image data * @return the {@link Image} encoded by the specified input stream */ protected static Image getImage(InputStream stream) throws IOException { @@ -125,55 +125,52 @@ public class SWTResourceManager { stream.close(); } } - /** * Returns an {@link Image} stored in the file at the specified path. * - * @param path the path to the image file + * @param path + * the path to the image file * @return the {@link Image} stored in the file at the specified path */ public static Image getImage(String path) { - Image image = imageMap.get(path); + Image image = m_imageMap.get(path); if (image == null) { try { image = getImage(new FileInputStream(path)); - imageMap.put(path, image); + m_imageMap.put(path, image); } catch (Exception e) { image = getMissingImage(); - imageMap.put(path, image); + m_imageMap.put(path, image); } } return image; } - /** - * Returns an {@link Image} stored in the file at the specified path relative to - * the specified class. + * Returns an {@link Image} stored in the file at the specified path relative to the specified class. * - * @param clazz the {@link Class} relative to which to find the image - * @param path the path to the image file, if starts with '/' + * @param clazz + * the {@link Class} relative to which to find the image + * @param path + * the path to the image file, if starts with '/' * @return the {@link Image} stored in the file at the specified path */ public static Image getImage(Class clazz, String path) { String key = clazz.getName() + '|' + path; - Image image = imageMap.get(key); + Image image = m_imageMap.get(key); if (image == null) { try { image = getImage(clazz.getResourceAsStream(path)); - imageMap.put(key, image); + m_imageMap.put(key, image); } catch (Exception e) { image = getMissingImage(); - imageMap.put(key, image); + m_imageMap.put(key, image); } } return image; } - private static final int MISSING_IMAGE_SIZE = 10; - /** - * @return the small {@link Image} that can be used as placeholder for missing - * image. + * @return the small {@link Image} that can be used as placeholder for missing image. */ private static Image getMissingImage() { Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); @@ -185,7 +182,6 @@ public class SWTResourceManager { // return image; } - /** * Style constant for placing decorator image in top left corner of base image. */ @@ -195,13 +191,11 @@ public class SWTResourceManager { */ public static final int TOP_RIGHT = 2; /** - * Style constant for placing decorator image in bottom left corner of base - * image. + * Style constant for placing decorator image in bottom left corner of base image. */ public static final int BOTTOM_LEFT = 3; /** - * Style constant for placing decorator image in bottom right corner of base - * image. + * Style constant for placing decorator image in bottom right corner of base image. */ public static final int BOTTOM_RIGHT = 4; /** @@ -212,77 +206,83 @@ public class SWTResourceManager { * Maps images to decorated images. */ @SuppressWarnings("unchecked") - private static Map>[] decoratedImageMap = new Map[LAST_CORNER_KEY]; - + private static Map>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; /** * Returns an {@link Image} composed of a base image decorated by another image. * - * @param baseImage the base {@link Image} that should be decorated - * @param decorator the {@link Image} to decorate the base image + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image * @return {@link Image} The resulting decorated image */ public static Image decorateImage(Image baseImage, Image decorator) { return decorateImage(baseImage, decorator, BOTTOM_RIGHT); } - /** * Returns an {@link Image} composed of a base image decorated by another image. * - * @param baseImage the base {@link Image} that should be decorated - * @param decorator the {@link Image} to decorate the base image - * @param corner the corner to place decorator image + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image + * @param corner + * the corner to place decorator image * @return the resulting decorated {@link Image} */ public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { if (corner <= 0 || corner >= LAST_CORNER_KEY) { throw new IllegalArgumentException("Wrong decorate corner"); } - Map> cornerDecoratedImageMap = decoratedImageMap[corner]; + Map> cornerDecoratedImageMap = m_decoratedImageMap[corner]; if (cornerDecoratedImageMap == null) { - cornerDecoratedImageMap = new HashMap<>(); - decoratedImageMap[corner] = cornerDecoratedImageMap; + cornerDecoratedImageMap = new HashMap>(); + m_decoratedImageMap[corner] = cornerDecoratedImageMap; } - Map decoratedMap = cornerDecoratedImageMap.computeIfAbsent(baseImage, - k -> new HashMap()); - return decoratedMap.computeIfAbsent(decorator, k -> { + Map decoratedMap = cornerDecoratedImageMap.get(baseImage); + if (decoratedMap == null) { + decoratedMap = new HashMap(); + cornerDecoratedImageMap.put(baseImage, decoratedMap); + } + // + Image result = decoratedMap.get(decorator); + if (result == null) { Rectangle bib = baseImage.getBounds(); Rectangle dib = decorator.getBounds(); - Image result = new Image(Display.getCurrent(), bib.width, bib.height); + // + result = new Image(Display.getCurrent(), bib.width, bib.height); + // GC gc = new GC(result); gc.drawImage(baseImage, 0, 0); - switch (corner) { - case TOP_LEFT: + if (corner == TOP_LEFT) { gc.drawImage(decorator, 0, 0); - break; - case TOP_RIGHT: + } else if (corner == TOP_RIGHT) { gc.drawImage(decorator, bib.width - dib.width, 0); - break; - case BOTTOM_LEFT: + } else if (corner == BOTTOM_LEFT) { gc.drawImage(decorator, 0, bib.height - dib.height); - break; - case BOTTOM_RIGHT: + } else if (corner == BOTTOM_RIGHT) { gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); - break; - default: - // do nothing } gc.dispose(); - return result; - }); + // + decoratedMap.put(decorator, result); + } + return result; } - /** * Dispose all of the cached {@link Image}'s. */ public static void disposeImages() { // dispose loaded images - for (Image image : imageMap.values()) { - image.dispose(); + { + for (Image image : m_imageMap.values()) { + image.dispose(); + } + m_imageMap.clear(); } - imageMap.clear(); // dispose decorated images - for (int i = 0; i < decoratedImageMap.length; i++) { - Map> cornerDecoratedImageMap = decoratedImageMap[i]; + for (int i = 0; i < m_decoratedImageMap.length; i++) { + Map> cornerDecoratedImageMap = m_decoratedImageMap[i]; if (cornerDecoratedImageMap != null) { for (Map decoratedMap : cornerDecoratedImageMap.values()) { for (Image image : decoratedMap.values()) { @@ -294,7 +294,6 @@ public class SWTResourceManager { } } } - //////////////////////////////////////////////////////////////////////////// // // Font @@ -303,39 +302,45 @@ public class SWTResourceManager { /** * Maps font names to fonts. */ - private static Map fontMap = new HashMap<>(); + private static Map m_fontMap = new HashMap(); /** * Maps fonts to their bold versions. */ - private static Map fontToBoldFontMap = new HashMap<>(); - + private static Map m_fontToBoldFontMap = new HashMap(); /** * Returns a {@link Font} based on its name, height and style. * - * @param name the name of the font - * @param height the height of the font - * @param style the style of the font + * @param name + * the name of the font + * @param height + * the height of the font + * @param style + * the style of the font * @return {@link Font} The font matching the name, height and style */ public static Font getFont(String name, int height, int style) { return getFont(name, height, style, false, false); } - /** - * Returns a {@link Font} based on its name, height and style. Windows-specific - * strikeout and underline flags are also supported. + * Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline + * flags are also supported. * - * @param name the name of the font - * @param size the size of the font - * @param style the style of the font - * @param strikeout the strikeout flag (warning: Windows only) - * @param underline the underline flag (warning: Windows only) - * @return {@link Font} The font matching the name, height, style, strikeout and - * underline + * @param name + * the name of the font + * @param size + * the size of the font + * @param style + * the style of the font + * @param strikeout + * the strikeout flag (warning: Windows only) + * @param underline + * the underline flag (warning: Windows only) + * @return {@link Font} The font matching the name, height, style, strikeout and underline */ public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) { String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline; - return fontMap.computeIfAbsent(fontName, k -> { + Font font = m_fontMap.get(fontName); + if (font == null) { FontData fontData = new FontData(name, size, style); if (strikeout || underline) { try { @@ -349,45 +354,47 @@ public class SWTResourceManager { logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ } } - } catch (Exception e) { + } catch (Throwable e) { + System.err.println("Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$ } } - return new Font(Display.getCurrent(), fontData); - - }); - + font = new Font(Display.getCurrent(), fontData); + m_fontMap.put(fontName, font); + } + return font; } - /** * Returns a bold version of the given {@link Font}. * - * @param baseFont the {@link Font} for which a bold version is desired + * @param baseFont + * the {@link Font} for which a bold version is desired * @return the bold version of the given {@link Font} */ public static Font getBoldFont(Font baseFont) { - return fontToBoldFontMap.computeIfAbsent(baseFont, k -> { - FontData[] fontDatas = baseFont.getFontData(); + Font font = m_fontToBoldFontMap.get(baseFont); + if (font == null) { + FontData fontDatas[] = baseFont.getFontData(); FontData data = fontDatas[0]; - return new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); - }); + font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); + m_fontToBoldFontMap.put(baseFont, font); + } + return font; } - /** * Dispose all of the cached {@link Font}'s. */ public static void disposeFonts() { // clear fonts - for (Font font : fontMap.values()) { + for (Font font : m_fontMap.values()) { font.dispose(); } - fontMap.clear(); + m_fontMap.clear(); // clear bold fonts - for (Font font : fontToBoldFontMap.values()) { + for (Font font : m_fontToBoldFontMap.values()) { font.dispose(); } - fontToBoldFontMap.clear(); + m_fontToBoldFontMap.clear(); } - //////////////////////////////////////////////////////////////////////////// // // Cursor @@ -396,38 +403,40 @@ public class SWTResourceManager { /** * Maps IDs to cursors. */ - private static Map idToCursorMap = new HashMap<>(); - + private static Map m_idToCursorMap = new HashMap(); /** * Returns the system cursor matching the specific ID. * - * @param id int The ID value for the cursor + * @param id + * int The ID value for the cursor * @return Cursor The system cursor matching the specific ID */ public static Cursor getCursor(int id) { Integer key = Integer.valueOf(id); - return idToCursorMap.computeIfAbsent(key, k -> new Cursor(Display.getDefault(), id)); + Cursor cursor = m_idToCursorMap.get(key); + if (cursor == null) { + cursor = new Cursor(Display.getDefault(), id); + m_idToCursorMap.put(key, cursor); + } + return cursor; } - /** * Dispose all of the cached cursors. */ public static void disposeCursors() { - for (Cursor cursor : idToCursorMap.values()) { + for (Cursor cursor : m_idToCursorMap.values()) { cursor.dispose(); } - idToCursorMap.clear(); + m_idToCursorMap.clear(); } - //////////////////////////////////////////////////////////////////////////// // // General // //////////////////////////////////////////////////////////////////////////// /** - * Dispose of cached objects and their underlying OS resources. This should only - * be called when the cached objects are no longer needed (e.g. on application - * shutdown). + * Dispose of cached objects and their underlying OS resources. This should only be called when the cached + * objects are no longer needed (e.g. on application shutdown). */ public static void dispose() { disposeColors(); diff --git a/plugins/com.minres.scviewer.database.vcd/pom.xml b/plugins/com.minres.scviewer.database.vcd/pom.xml index 133046f..0aa62e5 100644 --- a/plugins/com.minres.scviewer.database.vcd/pom.xml +++ b/plugins/com.minres.scviewer.database.vcd/pom.xml @@ -5,7 +5,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.database/pom.xml b/plugins/com.minres.scviewer.database/pom.xml index 93195ef..431fb60 100644 --- a/plugins/com.minres.scviewer.database/pom.xml +++ b/plugins/com.minres.scviewer.database/pom.xml @@ -4,7 +4,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.e4.application.help/.classpath b/plugins/com.minres.scviewer.e4.application.help/.classpath new file mode 100644 index 0000000..638f5b3 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/plugins/com.minres.scviewer.e4.application.help/.gitignore b/plugins/com.minres.scviewer.e4.application.help/.gitignore new file mode 100644 index 0000000..a734a88 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/.gitignore @@ -0,0 +1,5 @@ +/target/ +/css/ +/images/ +/*.html +/bin \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application.help/.project b/plugins/com.minres.scviewer.e4.application.help/.project new file mode 100644 index 0000000..6204755 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/.project @@ -0,0 +1,28 @@ + + + com.minres.scviewer.e4.application.help + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/com.minres.scviewer.e4.application.help/.settings/org.eclipse.jdt.core.prefs b/plugins/com.minres.scviewer.e4.application.help/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..c9545f0 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/plugins/com.minres.scviewer.e4.application.help/META-INF/MANIFEST.MF b/plugins/com.minres.scviewer.e4.application.help/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ae94659 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/META-INF/MANIFEST.MF @@ -0,0 +1,8 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: SCViewer Help +Bundle-SymbolicName: com.minres.scviewer.e4.application.help;singleton:=true +Bundle-Version: 2.16.0 +Bundle-Vendor: MINRES Technologies GmbH +Automatic-Module-Name: com.minres.scviewer.e4.application.help +Bundle-RequiredExecutionEnvironment: JavaSE-11 diff --git a/plugins/com.minres.scviewer.e4.application.help/OSGI-INF/l10n/bundle.properties b/plugins/com.minres.scviewer.e4.application.help/OSGI-INF/l10n/bundle.properties new file mode 100644 index 0000000..91ef34c --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,5 @@ +#Properties file for com.minres.scviewer.e4.application +Bundle-Vendor = MINRES Technologies GmbH +Bundle-Name = Application Help +product.description = SystemC Transaction and Waveform Viewer +product.name = SCViewer \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application.help/build.properties b/plugins/com.minres.scviewer.e4.application.help/build.properties new file mode 100644 index 0000000..1a5e3ad --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/build.properties @@ -0,0 +1,8 @@ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + images/,\ + css/,\ + *.html,\ + *.xml,\ + OSGI-INF/ diff --git a/plugins/com.minres.scviewer.e4.application.help/index.xml b/plugins/com.minres.scviewer.e4.application.help/index.xml new file mode 100644 index 0000000..1030b6d --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/index.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application.help/plugin.xml b/plugins/com.minres.scviewer.e4.application.help/plugin.xml new file mode 100644 index 0000000..78b73bf --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/plugin.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application.help/pom.xml b/plugins/com.minres.scviewer.e4.application.help/pom.xml new file mode 100644 index 0000000..1b5b923 --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + com.minres.scviewer.e4.application.help + + com.minres.scviewer + com.minres.scviewer.parent + 2.16.0 + ../.. + + eclipse-plugin + diff --git a/plugins/com.minres.scviewer.e4.application.help/src/.gitkeep b/plugins/com.minres.scviewer.e4.application.help/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/com.minres.scviewer.e4.application.help/toc.xml b/plugins/com.minres.scviewer.e4.application.help/toc.xml new file mode 100644 index 0000000..3e9aedd --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application.help/toc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application/Application.e4xmi b/plugins/com.minres.scviewer.e4.application/Application.e4xmi index 56d12d1..b4b56a0 100644 --- a/plugins/com.minres.scviewer.e4.application/Application.e4xmi +++ b/plugins/com.minres.scviewer.e4.application/Application.e4xmi @@ -57,7 +57,8 @@ - + + @@ -113,13 +114,14 @@ - + + type:user - + @@ -248,8 +250,11 @@ - - + + + + + @@ -292,12 +297,13 @@ - - - + + + + diff --git a/plugins/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF b/plugins/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF index 86e2263..e4fd2c3 100644 --- a/plugins/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF +++ b/plugins/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.minres.scviewer.e4.application;singleton:=true -Bundle-Version: 2.15.1 +Bundle-Version: 2.16.0 Bundle-Vendor: %Bundle-Vendor Require-Bundle: javax.inject;bundle-version="1.0.0", org.eclipse.core.runtime;bundle-version="3.11.1", @@ -35,7 +35,11 @@ Require-Bundle: javax.inject;bundle-version="1.0.0", org.eclipse.equinox.p2.core;bundle-version="2.6.300", org.eclipse.equinox.p2.engine;bundle-version="2.6.600", org.eclipse.equinox.p2.operations;bundle-version="2.5.700", - org.eclipse.equinox.p2.metadata.repository;bundle-version="1.3.400" + org.eclipse.equinox.p2.metadata.repository;bundle-version="1.3.400", + org.eclipse.help;bundle-version="3.8.700", + org.eclipse.help.webapp;bundle-version="3.9.800", + org.eclipse.help.base;bundle-version="4.2.900", + com.minres.scviewer.e4.application.help;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-11 Import-Package: com.minres.scviewer.database, javax.annotation;version="1.0.0";resolution:=optional, diff --git a/plugins/com.minres.scviewer.e4.application/pom.xml b/plugins/com.minres.scviewer.e4.application/pom.xml index 5e5b2fc..bf4f124 100644 --- a/plugins/com.minres.scviewer.e4.application/pom.xml +++ b/plugins/com.minres.scviewer.e4.application/pom.xml @@ -6,7 +6,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java index 3d88974..6e683f4 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java @@ -83,16 +83,14 @@ public class Messages extends NLS { public static String cursor; public static String cursor_drag; public static String cursor_text; + public static String HelpBrowser_0; + public static String HelpBrowser_1; + public static String HelpBrowser_2; + public static String HelpBrowser_3; + public static String HelpBrowser_4; + public static String HelpBrowser_5; public static String HelpBrowser_7; public static String HelpBrowser_8; - public static String HelpDialog_0; - public static String HelpDialog_1; - public static String HelpDialog_2; - public static String HelpDialog_3; - public static String HelpDialog_4; - public static String HelpDialog_5; - public static String HelpDialog_6; - public static String HelpDialog_7; public static String marker; public static String marker_text; public static String rel_arrow; diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java index f5494a8..3526b17 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java @@ -17,7 +17,6 @@ import org.osgi.service.prefs.BackingStoreException; import com.minres.scviewer.e4.application.preferences.PreferenceConstants; -@SuppressWarnings("restriction") public class EnableHover { static final String TAG_NAME = "EnableHover"; //$NON-NLS-1$ diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableTxDetails.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableTxDetails.java index 217c1dc..46f9897 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableTxDetails.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableTxDetails.java @@ -18,7 +18,6 @@ import org.osgi.service.prefs.BackingStoreException; import com.minres.scviewer.e4.application.preferences.PreferenceConstants; -@SuppressWarnings("restriction") public class EnableTxDetails { static final String TAG_NAME = "EnableTxDetails"; //$NON-NLS-1$ diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpContentsHandler.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpContentsHandler.java new file mode 100644 index 0000000..fc1969a --- /dev/null +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpContentsHandler.java @@ -0,0 +1,34 @@ +package com.minres.scviewer.e4.application.handlers; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.basic.MWindow; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.help.internal.base.BaseHelpSystem; +import org.eclipse.help.internal.server.WebappManager; + +public class HelpContentsHandler { + + static final String WINDOW_ID="com.minres.scviewer.e4.application.window.help_content"; //$NON-NLS-1$ + + @CanExecute + public boolean canExecute(MApplication app) { + return !app.getChildren().stream().filter(e -> e.getElementId().equals(WINDOW_ID)).findFirst().isPresent(); + } + + @Execute + public void execute(MApplication app, EModelService modelService /*@Named("mdialog01.dialog.0") MDialog dialog*/) { + BaseHelpSystem.ensureWebappRunning(); + String helpURL = "http://" //$NON-NLS-1$ + + WebappManager.getHost() + ":" //$NON-NLS-1$ + + WebappManager.getPort() + "/help/index.jsp"; //$NON-NLS-1$ + // BaseHelpSystem.getHelpBrowser(false).displayURL(helpURL); + MWindow newWin = (MWindow)modelService.cloneSnippet(app, WINDOW_ID, null); + final IEclipseContext ctx=app.getContext(); + if(ctx.containsKey("help_url")) + ctx.remove("help_url"); + ctx.modify("help_url", helpURL); + app.getChildren().add(newWin); + } +} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpHandler.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpHandler.java index 187c7d7..bd6292e 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpHandler.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/HelpHandler.java @@ -10,6 +10,7 @@ *******************************************************************************/ package com.minres.scviewer.e4.application.handlers; +import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.annotations.CanExecute; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.model.application.MApplication; @@ -18,16 +19,20 @@ import org.eclipse.e4.ui.workbench.modeling.EModelService; public class HelpHandler { - static final String WINDOW_ID="com.minres.scviewer.e4.application.window.help"; //$NON-NLS-1$ + static final String WINDOW_ID="com.minres.scviewer.e4.application.window.web_help"; //$NON-NLS-1$ + @CanExecute public boolean canExecute(MApplication app) { return !app.getChildren().stream().filter(e -> e.getElementId().equals(WINDOW_ID)).findFirst().isPresent(); } @Execute - public void execute(MApplication app, MWindow window, EModelService modelService /*@Named("mdialog01.dialog.0") MDialog dialog*/) { + public void execute(MApplication app, EModelService modelService /*@Named("mdialog01.dialog.0") MDialog dialog*/) { MWindow newWin = (MWindow)modelService.cloneSnippet(app, WINDOW_ID, null); + final IEclipseContext ctx=app.getContext(); + if(ctx.containsKey("help_url")) + ctx.remove("help_url"); + ctx.modify("help_url", "https://minres.github.io/SCViewer/#key-shortcuts"); app.getChildren().add(newWin); } - } diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties index 6c98d1c..1266f5a 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties @@ -77,16 +77,14 @@ signal_nan=Signal NaN Value cursor=Cursor cursor_drag=dragged Cursor cursor_text=Cursor Text +HelpBrowser_0=Back +HelpBrowser_1=Forward +HelpBrowser_2=Stop +HelpBrowser_3=Refresh +HelpBrowser_4=Go +HelpBrowser_5=Address HelpBrowser_7=Error initializing help browser HelpBrowser_8=An error occurred while initializing the help browser: -HelpDialog_0=Back -HelpDialog_1=Forward -HelpDialog_2=Stop -HelpDialog_3=Refresh -HelpDialog_4=Go -HelpDialog_5=Address -HelpDialog_6=https://minres.github.io/SCViewer/#key-shortcuts -HelpDialog_7=Could not instantiate Browser: marker=Marker marker_text=Marker TExt rel_arrow=Relation arrow diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/FileBrowserDialog.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/FileBrowserDialog.java index 50e400c..4c24554 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/FileBrowserDialog.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/FileBrowserDialog.java @@ -115,7 +115,7 @@ public class FileBrowserDialog extends TrayDialog { getButton(IDialogConstants.OK_ID).setEnabled(!tableViewer.getSelection().isEmpty()); if(parent instanceof Shell) { Point size = ((Shell)parent).computeSize(SWT.DEFAULT, SWT.DEFAULT); - ((Shell)parent).setSize(size.x, 400); + ((Shell)parent).setSize(Math.max(size.x, 600), Math.max(size.y, 450)); ((Shell)parent).setText("Select database"); } return ret; diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/help/HelpBrowser.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpBrowser.java similarity index 80% rename from plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/help/HelpBrowser.java rename to plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpBrowser.java index d962fbb..ca9eb73 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/help/HelpBrowser.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpBrowser.java @@ -1,9 +1,10 @@ -package com.minres.scviewer.e4.application.parts.help; +package com.minres.scviewer.e4.application.parts; import java.io.File; import javax.annotation.PostConstruct; import javax.inject.Inject; +import javax.inject.Named; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.ui.model.application.ui.MUIElement; @@ -48,32 +49,28 @@ public class HelpBrowser { } @PostConstruct - protected Control createComposite(Composite container) { -// container.getShell().addListener(SWT.Close, e -> { -// e.doit= false; -// element.setVisible(false); -// }); + protected Control createComposite(Composite container, @Named("help_url") String helpUrl) { GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 3; container.setLayout(gridLayout); ToolBar toolbar = new ToolBar(container, SWT.NONE); ToolItem itemBack = new ToolItem(toolbar, SWT.PUSH); - decorateItem(itemBack, Messages.HelpDialog_0, "arrow_undo.png"); //$NON-NLS-1$ + decorateItem(itemBack, Messages.HelpBrowser_0, "arrow_undo.png"); //$NON-NLS-1$ ToolItem itemForward = new ToolItem(toolbar, SWT.PUSH); - decorateItem(itemForward, Messages.HelpDialog_1, "arrow_redo.png"); //$NON-NLS-1$ + decorateItem(itemForward, Messages.HelpBrowser_1, "arrow_redo.png"); //$NON-NLS-1$ ToolItem itemStop = new ToolItem(toolbar, SWT.PUSH); - decorateItem(itemStop, Messages.HelpDialog_2, "cross.png"); //$NON-NLS-1$ + decorateItem(itemStop, Messages.HelpBrowser_2, "cross.png"); //$NON-NLS-1$ ToolItem itemRefresh = new ToolItem(toolbar, SWT.PUSH); - decorateItem(itemRefresh, Messages.HelpDialog_3, "arrow_refresh.png"); //$NON-NLS-1$ + decorateItem(itemRefresh, Messages.HelpBrowser_3, "arrow_refresh.png"); //$NON-NLS-1$ ToolItem itemGo = new ToolItem(toolbar, SWT.PUSH); - decorateItem(itemGo, Messages.HelpDialog_4, "accept.png"); //$NON-NLS-1$ + decorateItem(itemGo, Messages.HelpBrowser_4, "accept.png"); //$NON-NLS-1$ GridData data = new GridData(); data.horizontalSpan = 3; toolbar.setLayoutData(data); Label labelAddress = new Label(container, SWT.NONE); - labelAddress.setText(Messages.HelpDialog_5); + labelAddress.setText(Messages.HelpBrowser_5); final Text location = new Text(container, SWT.BORDER); data = new GridData(); @@ -81,10 +78,8 @@ public class HelpBrowser { data.horizontalSpan = 2; data.grabExcessHorizontalSpace = true; location.setLayoutData(data); - - final Browser browser; try { - browser = new Browser(container, SWT.NONE); + final Browser browser = new Browser(container, SWT.NONE); data = new GridData(); // data.widthHint = 800; // data.heightHint =600; @@ -109,15 +104,15 @@ public class HelpBrowser { Listener listener = event -> { ToolItem item = (ToolItem) event.widget; String string = (String) item.getData(); - if (string.equals(Messages.HelpDialog_0)) + if (string.equals(Messages.HelpBrowser_0)) browser.back(); - else if (string.equals(Messages.HelpDialog_1)) + else if (string.equals(Messages.HelpBrowser_1)) browser.forward(); - else if (string.equals(Messages.HelpDialog_2)) + else if (string.equals(Messages.HelpBrowser_2)) browser.stop(); - else if (string.equals(Messages.HelpDialog_3)) + else if (string.equals(Messages.HelpBrowser_3)) browser.refresh(); - else if (string.equals(Messages.HelpDialog_4)) + else if (string.equals(Messages.HelpBrowser_4)) browser.setUrl(location.getText()); }; browser.addProgressListener(new ProgressListener() { @@ -140,14 +135,10 @@ public class HelpBrowser { itemRefresh.addListener(SWT.Selection, listener); itemGo.addListener(SWT.Selection, listener); location.addListener(SWT.DefaultSelection, e -> browser.setUrl(location.getText())); - browser.setUrl(Messages.HelpDialog_6); + browser.setUrl(helpUrl); } catch (SWTError e) { MessageDialog.openWarning(container.getDisplay().getActiveShell(), Messages.HelpBrowser_7,Messages.HelpBrowser_8+e.getMessage()); } return container; } - - void handleShellCloseEvent(){ - - } } \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpDialog.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpDialog.java deleted file mode 100644 index 749ab42..0000000 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/HelpDialog.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.minres.scviewer.e4.application.parts; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; - -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTError; -import org.eclipse.swt.browser.Browser; -import org.eclipse.swt.browser.LocationListener; -import org.eclipse.swt.browser.ProgressEvent; -import org.eclipse.swt.browser.ProgressListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.ProgressBar; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; - -import com.minres.scviewer.e4.application.Messages; - -public class HelpDialog extends Dialog { - /** - * Create the dialog. - * - * @param parentShell the parent shell - */ - @Inject - public HelpDialog(Shell parentShell) { - super(parentShell); - setShellStyle(getShellStyle() | SWT.MODELESS | SWT.MAX | SWT.BORDER | SWT.TITLE); - setBlockOnOpen(false); - } - - @Override - protected boolean isResizable() { - return true; - } - - @Override - protected Point getInitialSize() { - return new Point(800, 600); - } - - /** - * Create contents of the dialog. - * - * @param parent the parent - * @return the control - */ - @Override - protected Control createDialogArea(Composite parent) { - Composite container = (Composite) super.createDialogArea(parent); - GridLayout gridLayout = new GridLayout(); - gridLayout.numColumns = 3; - container.setLayout(gridLayout); - ToolBar toolbar = new ToolBar(container, SWT.NONE); - ToolItem itemBack = new ToolItem(toolbar, SWT.PUSH); - itemBack.setText(Messages.HelpDialog_0); - ToolItem itemForward = new ToolItem(toolbar, SWT.PUSH); - itemForward.setText(Messages.HelpDialog_1); - ToolItem itemStop = new ToolItem(toolbar, SWT.PUSH); - itemStop.setText(Messages.HelpDialog_2); - ToolItem itemRefresh = new ToolItem(toolbar, SWT.PUSH); - itemRefresh.setText(Messages.HelpDialog_3); - ToolItem itemGo = new ToolItem(toolbar, SWT.PUSH); - itemGo.setText(Messages.HelpDialog_4); - - GridData data = new GridData(); - data.horizontalSpan = 3; - toolbar.setLayoutData(data); - - Label labelAddress = new Label(container, SWT.NONE); - labelAddress.setText(Messages.HelpDialog_5); - - final Text location = new Text(container, SWT.BORDER); - data = new GridData(); - data.horizontalAlignment = GridData.FILL; - data.horizontalSpan = 2; - data.grabExcessHorizontalSpace = true; - location.setLayoutData(data); - - final Browser browser; - try { - browser = new Browser(container, SWT.NONE); - data = new GridData(); - // data.widthHint = 800; - // data.heightHint =600; - data.horizontalAlignment = GridData.FILL; - data.verticalAlignment = GridData.FILL; - data.horizontalSpan = 3; - data.grabExcessHorizontalSpace = true; - data.grabExcessVerticalSpace = true; - browser.setLayoutData(data); - - final Label status = new Label(container, SWT.NONE); - data = new GridData(GridData.FILL_HORIZONTAL); - data.horizontalSpan = 2; - status.setLayoutData(data); - - final ProgressBar progressBar = new ProgressBar(container, SWT.NONE); - data = new GridData(); - data.horizontalAlignment = GridData.END; - progressBar.setLayoutData(data); - - /* event handling */ - Listener listener = event -> { - ToolItem item = (ToolItem) event.widget; - String string = item.getText(); - if (string.equals(Messages.HelpDialog_0)) - browser.back(); - else if (string.equals(Messages.HelpDialog_1)) - browser.forward(); - else if (string.equals(Messages.HelpDialog_2)) - browser.stop(); - else if (string.equals(Messages.HelpDialog_3)) - browser.refresh(); - else if (string.equals(Messages.HelpDialog_4)) - browser.setUrl(location.getText()); - }; - browser.addProgressListener(new ProgressListener() { - @Override - public void changed(ProgressEvent event) { - if (event.total == 0) return; - int ratio = event.current * 100 / event.total; - progressBar.setSelection(ratio); - } - @Override - public void completed(ProgressEvent event) { - progressBar.setSelection(0); - } - }); - browser.addStatusTextListener(event -> status.setText(event.text)); - browser.addLocationListener(LocationListener.changedAdapter(event -> { - if (event.top) location.setText(event.location); - } - )); - itemBack.addListener(SWT.Selection, listener); - itemForward.addListener(SWT.Selection, listener); - itemStop.addListener(SWT.Selection, listener); - itemRefresh.addListener(SWT.Selection, listener); - itemGo.addListener(SWT.Selection, listener); - location.addListener(SWT.DefaultSelection, e -> browser.setUrl(location.getText())); - - browser.setUrl(Messages.HelpDialog_6); - } catch (SWTError e) { - System.out.println(Messages.HelpDialog_7 + e.getMessage()); - } - return container; - } - /* (non-Javadoc) - * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) - */ - @Override - protected void createButtonsForButtonBar(Composite parent) { - // create OK button - createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); - } - - /** - * Open the dialog. - * @return the result - */ - @PostConstruct - @Override - public int open() { - return super.open(); - } - -} \ No newline at end of file diff --git a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java index 269168e..2b280b9 100644 --- a/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java +++ b/plugins/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java @@ -109,7 +109,6 @@ import com.minres.scviewer.e4.application.preferences.PreferenceConstants; /** * The Class WaveformViewerPart. */ -@SuppressWarnings("restriction") public class WaveformViewer implements IFileChangeListener, IPreferenceChangeListener, DisposeListener { /** The Constant ACTIVE_WAVEFORMVIEW. */ @@ -787,18 +786,15 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis protected void restoreWaveformViewerState(Map state) { Integer waves = state.containsKey(SHOWN_WAVEFORM+"S") ? Integer.parseInt(state.get(SHOWN_WAVEFORM + "S")):0; //$NON-NLS-1$ //$NON-NLS-2$ List trackEntries = new LinkedList<>(); + List selectedTrackEntries = new LinkedList<>(); for (int i = 0; i < waves; i++) { IWaveform waveform = database.getStreamByName(state.get(SHOWN_WAVEFORM + i)); if (waveform != null) { TrackEntry trackEntry = waveformPane.addWaveform(waveform, -1); //check if t is selected - boolean isSelected = Boolean.parseBoolean(state.get(SHOWN_WAVEFORM + i + WAVEFORM_SELECTED)); - if(isSelected) { - trackEntry.selected = true; - } else { - trackEntry.selected = false; - } trackEntries.add(trackEntry); + if(Boolean.parseBoolean(state.get(SHOWN_WAVEFORM + i + WAVEFORM_SELECTED))) + selectedTrackEntries.add(trackEntry); String v = state.get(SHOWN_WAVEFORM + i + VALUE_DISPLAY); if(v!=null) trackEntry.valueDisplay=ValueDisplay.valueOf(v); @@ -856,6 +852,8 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis } catch (NumberFormatException e) { } } + ISelection sel = new StructuredSelection(selectedTrackEntries); + waveformPane.setSelection(sel); updateAll(); } diff --git a/plugins/com.minres.scviewer.ui/plugin.xml b/plugins/com.minres.scviewer.ui/plugin.xml index 7861519..4e7ff60 100644 --- a/plugins/com.minres.scviewer.ui/plugin.xml +++ b/plugins/com.minres.scviewer.ui/plugin.xml @@ -5,7 +5,7 @@ diff --git a/plugins/com.minres.scviewer.ui/pom.xml b/plugins/com.minres.scviewer.ui/pom.xml index 0db37e1..30a2580 100644 --- a/plugins/com.minres.scviewer.ui/pom.xml +++ b/plugins/com.minres.scviewer.ui/pom.xml @@ -4,7 +4,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-plugin diff --git a/plugins/com.minres.scviewer.ui/res/images/wave.png b/plugins/com.minres.scviewer.ui/res/images/wave.png new file mode 100644 index 0000000..1ad8f18 Binary files /dev/null and b/plugins/com.minres.scviewer.ui/res/images/wave.png differ diff --git a/pom.xml b/pom.xml index 848bb7d..fa43c77 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,11 @@ 4.0.0 com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 pom releng/com.minres.scviewer.target + doc/com.minres.scviewer.doc plugins/com.minres.scviewer.database plugins/com.minres.scviewer.database.sqlite plugins/com.minres.scviewer.database.text @@ -15,20 +16,20 @@ tests/com.minres.scviewer.database.test plugins/com.minres.scviewer.database.ui.swt plugins/com.minres.scviewer.e4.application + plugins/com.minres.scviewer.e4.application.help plugins/com.minres.scviewer.ui features/com.minres.scviewer.database.feature features/com.minres.scviewer.ui.feature features/com.minres.scviewer.feature features/com.minres.scviewer.e4.platform.feature features/com.minres.scviewer.e4.feature + features/com.minres.scviewer.e4.help.feature releng/com.minres.scviewer.updateSite products/com.minres.scviewer.e4.product - 1.5.0 - 3.6.0-03 - 3.0.3-01 + 2.3.0 ${project.basedir}/../../.. @@ -68,9 +69,12 @@ com.minres.scviewer com.minres.scviewer.target - 2.15.1 + 2.16.0 + org.eclipse.justj.openjdk.hotspot.jre.minimal-15 + org.eclipse.justj.openjdk.hotspot.jre.minimal-15 + true linux @@ -102,24 +106,13 @@ plugin-source - - - - - org.eclipse.tycho.extras - tycho-source-feature-plugin - ${tycho-version} - - - source-feature - package + feature-source - source-feature + feature-source - @@ -129,9 +122,12 @@ + + + org.eclipse.tycho tycho-p2-plugin diff --git a/products/com.minres.scviewer.e4.product/pom.xml b/products/com.minres.scviewer.e4.product/pom.xml index 585b551..38ff11b 100644 --- a/products/com.minres.scviewer.e4.product/pom.xml +++ b/products/com.minres.scviewer.e4.product/pom.xml @@ -6,11 +6,11 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. com.minres.scviewer.e4.product - 2.15.1 + 2.16.0 eclipse-repository com.minres.scviewer diff --git a/products/com.minres.scviewer.e4.product/scviewer.product b/products/com.minres.scviewer.e4.product/scviewer.product index 3e2be35..ba9b8c2 100644 --- a/products/com.minres.scviewer.e4.product/scviewer.product +++ b/products/com.minres.scviewer.e4.product/scviewer.product @@ -1,8 +1,7 @@ - - + @@ -18,7 +17,6 @@ - @@ -35,7 +33,6 @@ - org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11 org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11 @@ -65,6 +62,8 @@ + + @@ -80,7 +79,6 @@ - diff --git a/releng/com.minres.scviewer.target/.settings/org.eclipse.core.resources.prefs b/releng/com.minres.scviewer.target/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 99f26c0..0000000 --- a/releng/com.minres.scviewer.target/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/releng/com.minres.scviewer.target/com.minres.scviewer.target.target b/releng/com.minres.scviewer.target/com.minres.scviewer.target.target index 146343c..e77999c 100644 --- a/releng/com.minres.scviewer.target/com.minres.scviewer.target.target +++ b/releng/com.minres.scviewer.target/com.minres.scviewer.target.target @@ -3,7 +3,7 @@ - + @@ -11,15 +11,12 @@ + - + - - - - @@ -36,9 +33,15 @@ + + + + + + + + + - - - -Xms40m -Xmx2G - + \ No newline at end of file diff --git a/releng/com.minres.scviewer.target/pom.xml b/releng/com.minres.scviewer.target/pom.xml index 63e59e3..39ce240 100644 --- a/releng/com.minres.scviewer.target/pom.xml +++ b/releng/com.minres.scviewer.target/pom.xml @@ -12,7 +12,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. diff --git a/releng/com.minres.scviewer.updateSite/pom.xml b/releng/com.minres.scviewer.updateSite/pom.xml index aeb9809..3de80a2 100644 --- a/releng/com.minres.scviewer.updateSite/pom.xml +++ b/releng/com.minres.scviewer.updateSite/pom.xml @@ -7,7 +7,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. diff --git a/tests/com.minres.scviewer.database.test/pom.xml b/tests/com.minres.scviewer.database.test/pom.xml index d70e6c4..0d29076 100644 --- a/tests/com.minres.scviewer.database.test/pom.xml +++ b/tests/com.minres.scviewer.database.test/pom.xml @@ -6,7 +6,7 @@ com.minres.scviewer com.minres.scviewer.parent - 2.15.1 + 2.16.0 ../.. eclipse-test-plugin