Merge branch 'release/2.16.0'
							
								
								
									
										62
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -30,25 +30,43 @@ Legend: | ||||
| * Mouse Scroll wheel: MScrl | ||||
| * Context any means Name List, Value List or Waveform | ||||
|  | ||||
| | Input     | Modifier | Context  | Action                            | | ||||
| |-----------|----------|----------|-----------------------------------| | ||||
| | LMB klick |          | any      | select                            | | ||||
| | LMB klick | Shift    | Waveform | move selected marker to position  | | ||||
| | LMB klick | Control  | Waveform | move cursor to position           | | ||||
| | LMB drag  |          | Waveform | zoom to range                     | | ||||
| | MMB klick |          | Waveform | move selected marker to position  | | ||||
| | MScrl     |          | any      | scroll window up/down             | | ||||
| | MScrl     | Shift    | any      | scroll window left/right          | | ||||
| | Key left  |          | Waveform | scroll window to the left (slow)  | | ||||
| | Key right |          | Waveform | scroll window to the right (slow) | | ||||
| | Key left  | Shift    | Waveform | scroll window to the left (fast)  | | ||||
| | Key right | Shift    | Waveform | scroll window to the right (fast) | | ||||
| | Key up    |          | Waveform | move selection up                 | | ||||
| | Key down  |          | Waveform | move selection down               | | ||||
| | Key up    | Control  | Waveform | move selected track up            | | ||||
| | Key down  | Control  | Waveform | move selected track down          | | ||||
| | Key +     | Control  | Waveform | zoom in                           | | ||||
| | Key -     | Control  | Waveform | zoom out                          | | ||||
| | Key Pos1  |          | Waveform | jump to selected marker           | | ||||
| | Key End   |          | Waveform | jump to cursor                    | | ||||
| | Key Del   |          | any      | delete selected entries           | | ||||
| | Input      | Modifier | Context  | Action                            | | ||||
| |------------|----------|----------|-----------------------------------| | ||||
| | LMB click  |          | any      | select                            | | ||||
| | LMB click  | Shift    | Waveform | move selected marker to position  | | ||||
| | LMB click  | Control  | Waveform | move cursor to position           | | ||||
| | LMB drag   |          | Waveform | zoom to range                     | | ||||
| | MMB click  |          | Waveform | move selected marker to position  | | ||||
| | MScrl      |          | any      | scroll window up/down             | | ||||
| | MScrl      | Shift    | any      | scroll window left/right          | | ||||
| | MScrl      | Control  | Waveform | zoom in/out                       | | ||||
| | Key left   |          | Waveform | scroll window to the left (slow)  | | ||||
| | Key right  |          | Waveform | scroll window to the right (slow) | | ||||
| | Key left   | Shift    | Waveform | scroll window to the left (fast)  | | ||||
| | Key right  | Shift    | Waveform | scroll window to the right (fast) | | ||||
| | Key up     |          | Waveform | move selection up                 | | ||||
| | Key down   |          | Waveform | move selection down               | | ||||
| | Key up     | Control  | Waveform | move selected track up            | | ||||
| | Key down   | Control  | Waveform | move selected track down          | | ||||
| | Key +      | Control  | Waveform | zoom in                           | | ||||
| | Key -      | Control  | Waveform | zoom out                          | | ||||
| | Key Pos1   |          | Waveform | jump to selected marker           | | ||||
| | Key End    |          | Waveform | jump to cursor                    | | ||||
| | Key Del    |          | any      | delete selected entries           | | ||||
| | LMB click  |          | ZoomBar  | increment/decrement 1 page        | | ||||
| | LMB drag   |          | ZoomBar  | drag both markers (pan)           | | ||||
| | LMB drag   | Control  | ZoomBar  | drag one marker (zoom)            | | ||||
| | MMB drag   |          | ZoomBar  | drag one marker (zoom)            | | ||||
| | xMB dclick |          | ZoomBar  | pan to position                   | | ||||
| | MScrl      |          | ZoomBar  | scroll window left/right          | | ||||
| | MScrl      | Shift    | ZoomBar  | scroll window left/right double speed | | ||||
| | MScrl      | Control  | ZoomBar  | zoom in/out                       | | ||||
| | Key left   |          | ZoomBar  | scroll window to the left (slow)  | | ||||
| | Key right  |          | ZoomBar  | scroll window to the right (slow) | | ||||
| | Key up     |          | ZoomBar  | scroll window to the left (slow)  | | ||||
| | Key down   |          | ZoomBar  | scroll window to the right (slow) | | ||||
| | Key PgUp   |          | ZoomBar  | scroll window to the left (fast)  | | ||||
| | Key PgDown |          | ZoomBar  | scroll window to the right (fast) | | ||||
| | Key Pos1   |          | ZoomBar  | scroll to begin                   | | ||||
| | Key End    |          | ZoomBar  | scroll to end                     | | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								doc/com.minres.scviewer.doc/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /target/ | ||||
							
								
								
									
										11
									
								
								doc/com.minres.scviewer.doc/.project
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										168
									
								
								doc/com.minres.scviewer.doc/pom.xml
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										25
									
								
								doc/com.minres.scviewer.doc/src/asciidoc/Overview.adoc
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										55
									
								
								doc/com.minres.scviewer.doc/src/asciidoc/Reference.adoc
									
									
									
									
									
										Normal 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                      | ||||
| |=== | ||||
							
								
								
									
										39
									
								
								doc/com.minres.scviewer.doc/src/asciidoc/SCViewerHelp.adoc
									
									
									
									
									
										Normal 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[] | ||||
							
								
								
									
										93
									
								
								doc/com.minres.scviewer.doc/src/asciidoc/fonts/OFL.txt
									
									
									
									
									
										Normal 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. | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/com.minres.scviewer.doc/src/asciidoc/images/Minres_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 24 KiB | 
| After Width: | Height: | Size: 35 KiB | 
| After Width: | Height: | Size: 21 KiB | 
| @@ -0,0 +1,55 @@ | ||||
| page: | ||||
|   layout: portrait | ||||
|   margin: [2.3cm, 2cm, 2cm, 2.2cm] | ||||
|   size: A4 | ||||
| base: | ||||
|   font-color: #000000 | ||||
|   font-color-mnrs-grey: #6a747c | ||||
|   font-color-mnrs-blue: #197788 | ||||
|   font-family: titillium | ||||
|   font-size: 12 | ||||
|   line-height-length: 16 | ||||
|   line-height: $base-line-height-length / $base-font-size | ||||
|   align: justify | ||||
|   vertical-spacing: $base-line-height-length | ||||
| heading: | ||||
|   font-color: $base-font-color-mnrs-grey | ||||
|   font-size: $base-font-size * 1.25 | ||||
|   font-style: bold | ||||
|   line-height: $base-line-height * 1.2 | ||||
|   margin-bottom: $vertical-spacing | ||||
| link: | ||||
|   font-color: $base_font-color-mnrs-blue  | ||||
| outline-list: | ||||
|   indent: $base-font-size * 1.5 | ||||
| footer: | ||||
|   height: $base-line-height-length * 3.0 | ||||
|   font-color:  $base-font-color-mnrs-grey | ||||
|   font-size: $base-font-size * 0.9 | ||||
|   line-height: 1 | ||||
|   recto: | ||||
|     left: | ||||
|       content: '{description} v{revision}, © 2021 MINRES' | ||||
|     right: | ||||
|       content: '{page-number}' | ||||
|   verso: | ||||
|     left: | ||||
|       content: $footer_recto_right_content | ||||
|     right: | ||||
|       content: $footer_recto_left_content | ||||
| table: | ||||
|   border_color: $base-font-color | ||||
|   border_width: 0.1 | ||||
| title-page: | ||||
|   align: right | ||||
|   font-color: $base-font-color-mnrs-grey | ||||
|   font-size: $base-font-size * 1.80 | ||||
|   font-style: bold | ||||
| font: | ||||
|    fallbacks: titilliumtext22l002-webfont.ttf | ||||
|    catalog: | ||||
|       titillium: | ||||
|         normal: titilliumtext22l002-webfont.ttf | ||||
|         bold: titilliumtext22l005-webfont.ttf | ||||
|         italic: TitilliumWeb-Italic.ttf | ||||
|         bold_italic: TitilliumWeb-BoldItalic.ttf | ||||
							
								
								
									
										1
									
								
								doc/com.minres.scviewer.doc/src/docbkx/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /SCViewerHelp.xml | ||||
							
								
								
									
										124
									
								
								doc/com.minres.scviewer.doc/src/docbkx/css/narrow_style.css
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										108
									
								
								doc/com.minres.scviewer.doc/src/docbkx/css/style.css
									
									
									
									
									
										Normal 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 } | ||||
							
								
								
									
										1
									
								
								doc/com.minres.scviewer.doc/src/docbkx/images/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /*.png | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
							
								
								
									
										1
									
								
								features/com.minres.scviewer.e4.help.feature/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /target/ | ||||
							
								
								
									
										17
									
								
								features/com.minres.scviewer.e4.help.feature/.project
									
									
									
									
									
										Normal 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> | ||||
| @@ -0,0 +1 @@ | ||||
| bin.includes = feature.xml | ||||
							
								
								
									
										207
									
								
								features/com.minres.scviewer.e4.help.feature/feature.xml
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										12
									
								
								features/com.minres.scviewer.e4.help.feature/pom.xml
									
									
									
									
									
										Normal 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> | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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...")); | ||||
| 	} | ||||
| } | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -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(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -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(); | ||||
| 	} | ||||
| } | ||||
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 326 B | 
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 305 B | 
| After Width: | Height: | Size: 302 B | 
| After Width: | Height: | Size: 339 B | 
| After Width: | Height: | Size: 350 B | 
| After Width: | Height: | Size: 336 B | 
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 329 B | 
| After Width: | Height: | Size: 326 B | 
| After Width: | Height: | Size: 349 B | 
| @@ -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 ); | ||||
|   } | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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 ) {} | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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 ) { | ||||
|   } | ||||
| } | ||||
| @@ -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 ); | ||||
|   } | ||||
| } | ||||
| @@ -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 ) {} | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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(); | ||||
|   } | ||||
| } | ||||
| @@ -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(); | ||||
|   } | ||||
| } | ||||
| @@ -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 ); | ||||
|   } | ||||
| } | ||||
| @@ -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() ); | ||||
|   } | ||||
| } | ||||
| @@ -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 ); | ||||
|   } | ||||
| } | ||||
| @@ -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(); | ||||
|   } | ||||
| } | ||||
| @@ -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 ) ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -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 ) { | ||||
|   } | ||||
| } | ||||
| @@ -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 ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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 ); | ||||
|   } | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -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; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,7 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.widgets.Control; | ||||
|  | ||||
| public interface ViewComponent { | ||||
|   Control getControl(); | ||||
| } | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
							
								
								
									
										10
									
								
								plugins/com.minres.scviewer.e4.application.help/.classpath
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										5
									
								
								plugins/com.minres.scviewer.e4.application.help/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | ||||
| /target/ | ||||
| /css/ | ||||
| /images/ | ||||
| /*.html | ||||
| /bin | ||||