Merge branch 'release/2.16.0'

This commit is contained in:
Eyck Jentzsch 2022-05-16 21:16:31 +02:00
commit fda4c64ac7
134 changed files with 5360 additions and 569 deletions

View File

@ -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 |

View File

@ -0,0 +1 @@
/target/

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.minres.scviewer.doc</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

View File

@ -0,0 +1,168 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>com.minres.scviewer.doc</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<asciidoctor.maven.plugin.version>2.0.0</asciidoctor.maven.plugin.version>
<asciidoctorj.pdf.version>1.6.2</asciidoctorj.pdf.version>
<help.plugin.target.dir>../../plugins/com.minres.scviewer.e4.application.help</help.plugin.target.dir>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>${asciidoctor.maven.plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>${asciidoctorj.pdf.version}</version>
</dependency>
</dependencies>
<configuration>
<sourceDirectory>src/asciidoc</sourceDirectory>
<sourceDocumentName>SCViewerHelp.adoc</sourceDocumentName>
<headerFooter>true</headerFooter>
</configuration>
<executions>
<execution>
<id>output-html</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<sourceHighlighter>coderay</sourceHighlighter>
<backend>html</backend>
<attributes>
<toc />
<linkcss>false</linkcss>
</attributes>
</configuration>
</execution>
<execution>
<id>output-docbook</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>docbook</backend>
</configuration>
</execution>
<execution>
<id>output-pdf</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<sourceHighlighter>coderay</sourceHighlighter>
<attributes>
<icons>font</icons>
<pagenums />
<toc />
<idprefix />
<idseparator>-</idseparator>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-asciidoc-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>target/generated-docs/</directory>
<includes>
<include>SCViewerHelp.xml</include>
<include>**/*.jpg</include>
<include>**/*.png</include>
<include>**/*.svg</include>
</includes>
</resource>
</resources>
<outputDirectory>src/docbkx</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.17</version>
<executions>
<execution>
<!-- <phase>generate-sources</phase> -->
<phase>generate-resources</phase>
<goals>
<goal>generate-eclipse</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.docbook</groupId>
<artifactId>docbook-xml</artifactId>
<version>4.4</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<configuration>
<sourceDirectory>src/docbkx</sourceDirectory>
<targetDirectory>${help.plugin.target.dir}</targetDirectory>
<preProcess>
<copy todir="${help.plugin.target.dir}/images">
<fileset dir="src/docbkx/images" />
</copy>
<copy todir="${help.plugin.target.dir}/css">
<fileset dir="src/docbkx/css" />
</copy>
</preProcess>
<imgSrcPath>./</imgSrcPath>
<useExtensions>1</useExtensions>
<highlightSource>1</highlightSource>
<highlightDefaultLanguage>java</highlightDefaultLanguage>
<calloutsExtension>1</calloutsExtension>
<paperType>A4</paperType>
<!--<fop1Extensions>1</fop1Extensions>
<foCustomization>${basedir}/conf/customization-fopdf.xsl</foCustomization>-->
<!-- This copies content (images, etc) for the HTML version -->
<!-- Any parameters specific to HTML version go here -->
<htmlStylesheet>css/narrow_style.css</htmlStylesheet>
<!-- <includes>titlepage/titlepage.templates.xml</includes> -->
<includes>SCViewerHelp.xml</includes>
<chunkedOutput>true</chunkedOutput>
<xincludeSupported>true</xincludeSupported>
<!-- <foCustomization>src/test/resources/docbook-fo.xsl</foCustomization> -->
<eclipsePluginId>com.minres.scviewer.e4.application.help</eclipsePluginId>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -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

View File

@ -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
|===

View File

@ -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[]

View File

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -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}, &#169; 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

View File

@ -0,0 +1 @@
/SCViewerHelp.xml

View File

@ -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;
}

View File

@ -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 }

View File

@ -0,0 +1 @@
/*.png

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>3.0.0-SNAPSHOT</version>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>1.1.0-SNAPSHOT</version>

View File

@ -0,0 +1 @@
/target/

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.minres.scviewer.e4.help.feature</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.FeatureBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.FeatureNature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1 @@
bin.includes = feature.xml

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="com.minres.scviewer.e4.help.feature"
label="Feature"
version="1.0.0.qualifier"
provider-name="MINRES Technologies GmbH">
<description url="http://www.example.com/description">
[Enter Feature Description here.]
</description>
<copyright url="http://www.example.com/copyright">
[Enter Copyright Description here.]
</copyright>
<license url="http://www.example.com/license">
[Enter License Description here.]
</license>
<plugin
id="org.eclipse.help"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.help.webapp"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.help.base"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.apache.lucene.core"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.apache.lucene.analyzers-common"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.apache.lucene.analyzers-smartcn"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.core.net"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.security"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.security.linux.x86_64"
os="linux"
arch="x86_64"
download-size="0"
install-size="0"
version="0.0.0"
fragment="true"/>
<plugin
id="javax.el"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="javax.servlet"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="javax.servlet.jsp"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.http.jetty"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.http.registry"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.http.servlet"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.jsp.jasper"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.jsp.jasper.registry"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.apache.jasper.glassfish"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.http"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.io"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.security"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.server"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.servlet"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.jetty.util"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="com.minres.scviewer.e4.application.help"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.security.win32.x86_64"
os="win32"
arch="x86_64"
download-size="0"
install-size="0"
version="0.0.0"
fragment="true"
unpack="false"/>
</feature>

View File

@ -0,0 +1,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>com.minres.scviewer.e4.help.feature</artifactId>
<packaging>eclipse-feature</packaging>
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>1.0.0-SNAPSHOT</version>
</project>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>1.0.0-SNAPSHOT</version>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>1.1.0-SNAPSHOT</version>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>1.1.0-SNAPSHOT</version>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<packaging>eclipse-plugin</packaging>

View File

@ -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

View File

@ -6,7 +6,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<packaging>eclipse-plugin</packaging>

View File

@ -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) {

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<version>4.0.0-SNAPSHOT</version>

View File

@ -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..."));
}
}

View File

@ -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();

View File

@ -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<CursorPainter> cursorPainters;
private ZoomBar horizontal;
private int[] lastHorSelection;
private long sliderScaleFactor = 1;
private ScrollBar vertical;
HashMap<IWaveform, IWaveformPainter> 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<CursorPainter> 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
* :<b> transform, image size, client area</b>.
*/
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)<getMaxTime()) {
int scaledTime = (int) (time / scaleFactor);
int scaledTime = (int) (time / getScale());
setOrigin(-scaledTime, origin.y);
}
} else {

View File

@ -91,6 +91,7 @@ import com.minres.scviewer.database.ui.IWaveformStyleProvider;
import com.minres.scviewer.database.ui.IWaveformView;
import com.minres.scviewer.database.ui.IWaveformZoom;
import com.minres.scviewer.database.ui.TrackEntry;
import com.minres.scviewer.database.ui.swt.internal.slider.ZoomBar;
public class WaveformView implements IWaveformView {
@ -112,6 +113,10 @@ public class WaveformView implements IWaveformView {
private final Canvas valueList;
private final Control nameFill;
private final Control valueFill;
final WaveformCanvas waveformCanvas;
final ToolTipHandler toolTipHandler;
@ -204,7 +209,7 @@ public class WaveformView implements IWaveformView {
long endTime = waveformCanvas.getTimeForOffset(end.x);
if(startTime<endTime) {
waveformCanvas.setVisibleRange(startTime, endTime);
} else {
} else if(start.x!=end.x){
long targetTimeRange = startTime-endTime;
long currentTimeRange = waveformCanvas.getMaxVisibleTime() - waveformCanvas.getMinVisibleTime();
long factor = currentTimeRange/targetTimeRange *waveformCanvas.getScale();
@ -266,11 +271,24 @@ public class WaveformView implements IWaveformView {
switch (e.type) {
case SWT.MouseWheel:
if((e.stateMask & SWT.CTRL) != 0) {
if(e.count<0)
if(e.count<0) // up scroll
waveformCanvas.setScale(waveformCanvas.getScale()*11/10);
else
else // down scroll
waveformCanvas.setScale(waveformCanvas.getScale()*10/11);
}
e.doit=false;
} else if((e.stateMask & SWT.SHIFT) != 0) {
long upper = waveformCanvas.getMaxVisibleTime();
long lower = waveformCanvas.getMinVisibleTime();
long duration = upper-lower;
if(e.count<0) { // up scroll
long newLower = Math.min(waveformCanvas.getMaxTime()-duration, lower+duration/10);
waveformCanvas.setMinVisibleTime(newLower);
} else {// down scroll
long newLower = Math.max(0, lower-duration/10);
waveformCanvas.setMinVisibleTime(newLower);
}
e.doit=false;
}
break;
case SWT.MouseDown:
start = new Point(e.x, e.y);
@ -330,8 +348,26 @@ public class WaveformView implements IWaveformView {
rightSash.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY));
Composite valuePane = new Composite(rightSash, SWT.NONE);
waveformCanvas = new WaveformCanvas(rightSash, SWT.NONE, styleProvider);
Composite waveformPane = new Composite(rightSash, SWT.NONE);
GridLayout gl_waveformPane = new GridLayout(1, false);
gl_waveformPane.verticalSpacing = 0;
gl_waveformPane.marginWidth = 0;
gl_waveformPane.marginHeight = 0;
waveformPane.setLayout(gl_waveformPane);
waveformCanvas = new WaveformCanvas(waveformPane, SWT.NONE | SWT.V_SCROLL /*| SWT.H_SCROLL*/, styleProvider, new ZoomBar.IProvider() {
@Override
public ZoomBar getScrollBar() {
ZoomBar timeSliderPane = new ZoomBar(waveformPane, SWT.NONE);
GridData gd_timeSliderPane = new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1);
timeSliderPane.setLayoutData(gd_timeSliderPane);
return timeSliderPane;
}
});
waveformCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
// create the name pane
createTextPane(namePane, "Name");
@ -347,7 +383,10 @@ public class WaveformView implements IWaveformView {
@Override
public void controlResized(ControlEvent e) {
nameListScrolled.getVerticalBar().setVisible(false);
if(nameListScrolled.getSize().y == nameList.getSize().y) {
((GridData)nameFill.getLayoutData()).heightHint=18;
namePane.layout();
}
}
});
nameList = new Canvas(nameListScrolled, SWT.NONE) {
@ -366,7 +405,8 @@ public class WaveformView implements IWaveformView {
});
nameList.addMouseListener(nameValueMouseListener);
nameListScrolled.setContent(nameList);
nameFill = createFill(namePane);
createTextPane(valuePane, "Value");
valuePane.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND));
@ -379,7 +419,10 @@ public class WaveformView implements IWaveformView {
@Override
public void controlResized(ControlEvent e) {
valueListScrolled.getVerticalBar().setVisible(false);
if(valueListScrolled.getSize().y == valueList.getSize().y) {
((GridData)valueFill.getLayoutData()).heightHint=18;
valuePane.layout();
}
}
});
valueList = new Canvas(valueListScrolled, SWT.NONE) {
@ -398,6 +441,7 @@ public class WaveformView implements IWaveformView {
});
valueList.addMouseListener(nameValueMouseListener);
valueListScrolled.setContent(valueList);
valueFill = createFill(valuePane);
waveformCanvas.setMaxTime(1);
waveformCanvas.addPaintListener(waveformMouseListener);
@ -457,6 +501,15 @@ public class WaveformView implements IWaveformView {
});
}
private Control createFill(Composite pane) {
Label cLabel = new Label(pane, SWT.NONE);
cLabel.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND));
GridData gd_cLabel = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
gd_cLabel.heightHint = 0;
cLabel.setLayoutData(gd_cLabel);
return cLabel;
}
private void createTextPane(Composite namePane, String text) {
GridLayout glNamePane = new GridLayout(1, false);
glNamePane.verticalSpacing = 0;
@ -522,7 +575,7 @@ public class WaveformView implements IWaveformView {
tracksVerticalHeight += streamEntry.height;
even = !even;
}
waveformCanvas.syncScrollBars();
waveformCanvas.syncSb();
nameList.setSize(nameMaxWidth + 15, tracksVerticalHeight);
nameListScrolled.setMinSize(nameMaxWidth + 15, tracksVerticalHeight);
nameList.redraw();

View File

@ -0,0 +1,35 @@
package com.minres.scviewer.database.ui.swt.internal.slider;
import org.eclipse.swt.widgets.Display;
public class ActionTimer implements Runnable {
public static final int INITIAL_DELAY = 300;
public static final int FAST_DELAY = 50;
private final Display display;
private final TimerAction timerAction;
public interface TimerAction extends Runnable {
boolean isEnabled();
}
public ActionTimer( TimerAction timerAction, Display display ) {
this.display = display;
this.timerAction = timerAction;
}
public void activate() {
if( timerAction.isEnabled() ) {
display.timerExec( INITIAL_DELAY, this );
}
}
@Override
public void run() {
if( timerAction.isEnabled() ) {
timerAction.run();
display.timerExec( FAST_DELAY, this );
}
}
}

View File

@ -0,0 +1,192 @@
package com.minres.scviewer.database.ui.swt.internal.slider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
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.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
public class ImageButton extends Composite
{
private Image hoverImage;
private Image normalImage;
private Image pressedImage;
private Image disabledImage;
private int width;
private int height;
private boolean hover;
private boolean pressed;
private boolean autoFire;
private ActionTimer actionTimer;
private ActionTimer.TimerAction timerAction;
public ImageButton(Composite parent, int style) {
super(parent, style);
timerAction = new ActionTimer.TimerAction() {
@Override
public void run() {
notifyListeners();
}
@Override
public boolean isEnabled() {
return pressed;
}
};
actionTimer = new ActionTimer(timerAction, this.getDisplay() );
addListener(SWT.Dispose, event -> {
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 <code>SelectionListener</code> interface.
* <p>
* <code>widgetSelected</code> is called when the user changes the receiver's
* value. <code>widgetDefaultSelected</code> is not called.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException
* <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException
* <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
* thread that created the receiver</li>
* </ul>
*
* @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
* <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException
* <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
* thread that created the receiver</li>
* </ul>
*
* @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;
}
}

View File

@ -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.x<coordLower.x) {
translateValues(-pageIncrement);
validateNewValues(e);
redraw();
} else if(e.x>coordUpper.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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 <code>SelectionListener</code> 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 <code>SelectionListener</code> 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;
}
}

View File

@ -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();
}
}

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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 ) {}
}

View File

@ -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;
}
}

View File

@ -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 ) {
}
}

View File

@ -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 );
}
}

View File

@ -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 ) {}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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 );
}
}

View File

@ -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<SelectionListener> 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<SelectionListener>();
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() );
}
}

View File

@ -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 );
}
}

View File

@ -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();
}
}

View File

@ -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 ) );
}
}
}
}

View File

@ -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 ) {
}
}

View File

@ -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 );
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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<SelectionListener> 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;
}
}

View File

@ -0,0 +1,7 @@
package com.minres.scviewer.database.ui.swt.sb;
import org.eclipse.swt.widgets.Control;
public interface ViewComponent {
Control getControl();
}

View File

@ -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.
* <p>
* !!! IMPORTANT !!! Application code must explicitly invoke the
* <code>dispose()</code> 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 <code>dispose()</code> 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)
* <p>
* This class may be freely distributed as part of any application or plugin.
* <p>
*
* @author scheglov_ke
* @author Dan Rubel
*/
@ -49,54 +46,57 @@ public class SWTResourceManager {
// Color
//
////////////////////////////////////////////////////////////////////////////
private static Map<RGB, Color> colorMap = new HashMap<>();
private SWTResourceManager() {}
private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>();
/**
* 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<String, Image> imageMap = new HashMap<>();
private static Map<String, Image> m_imageMap = new HashMap<String, Image>();
/**
* 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 <code>'/'</code>
* @param clazz
* the {@link Class} relative to which to find the image
* @param path
* the path to the image file, if starts with <code>'/'</code>
* @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<Image, Map<Image, Image>>[] decoratedImageMap = new Map[LAST_CORNER_KEY];
private static Map<Image, Map<Image, Image>>[] 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<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[corner];
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
if (cornerDecoratedImageMap == null) {
cornerDecoratedImageMap = new HashMap<>();
decoratedImageMap[corner] = cornerDecoratedImageMap;
cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
m_decoratedImageMap[corner] = cornerDecoratedImageMap;
}
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.computeIfAbsent(baseImage,
k -> new HashMap<Image, Image>());
return decoratedMap.computeIfAbsent(decorator, k -> {
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
if (decoratedMap == null) {
decoratedMap = new HashMap<Image, Image>();
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<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[i];
for (int i = 0; i < m_decoratedImageMap.length; i++) {
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
if (cornerDecoratedImageMap != null) {
for (Map<Image, Image> 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<String, Font> fontMap = new HashMap<>();
private static Map<String, Font> m_fontMap = new HashMap<String, Font>();
/**
* Maps fonts to their bold versions.
*/
private static Map<Font, Font> fontToBoldFontMap = new HashMap<>();
private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>();
/**
* 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<Integer, Cursor> idToCursorMap = new HashMap<>();
private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>();
/**
* 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();

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<packaging>eclipse-plugin</packaging>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>com.minres.scviewer</groupId>
<artifactId>com.minres.scviewer.parent</artifactId>
<version>2.15.1</version>
<version>2.16.0</version>
<relativePath>../..</relativePath>
</parent>
<packaging>eclipse-plugin</packaging>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,5 @@
/target/
/css/
/images/
/*.html
/bin

Some files were not shown because too many files have changed in this diff Show More