diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..41534ed7ba --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: processing +custom: https://processingfoundation.org diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 0000000000..5ed1e8ee84 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,29 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '0 6 * * *' + +permissions: + contents: read + +jobs: + lock: + permissions: + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v2.0.1 + with: + github-token: ${{ github.token }} + issue-lock-inactive-days: '30' + issue-lock-comment: > + This issue has been automatically locked. To avoid confusion + with reports that have already been resolved, closed issues + are automatically locked 30 days after the last comment. + Please open a new issue for related bugs. + pr-lock-comment: > + This pull request has been automatically locked. + Pull requests that have been closed are automatically + locked 30 days after the last comment. diff --git a/.gitignore b/.gitignore index 528a5fbbbc..cd99249298 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,75 @@ ._* *~ /build/shared/reference.zip + +# temporary, until we complete the move to IntelliJ +*.iml +/.idea + +# via https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..afb13c6f19 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +## Welcome to Processing! + +### Bug Report? + +We have a page on [troubleshooting](https://github.com/processing/processing/wiki/Troubleshooting) common problems. Check there first! + +We also host an [online forum](https://forum.processing.org) for coding questions, which is also helpful for general "getting started" queries. + +If you don't find an answer, please let us know by [filing an issue](https://github.com/processing/processing/issues). We can only fix the things we've heard about. + +Please keep the tone polite. This project is volunteer work done in our free time. We give it away at no cost. We do this because we think it's important for the community and enjoy it. Complaints that things *suck* are *annoying* or lectures about things that *must* be fixed are... weird things to hear from strangers at best, demotivating at worst. + +### Want to Help? + +Great! The number of contributors on this project is *tiny*, especially relative to the number of users. There are [only 2 or 3 people](https://github.com/processing/processing/graphs/contributors) who actively work on this repository, for instance. We need help! + +How to start: + +* Issues marked [help](https://github.com/processing/processing/issues?q=is%3Aissue+is%3Aopen+label%3Ahelp) are a good place to start, because they're something that's isolated enough that someone can jump into it without significant reworking of other code. +* Mind the [style guidelines](https://github.com/processing/processing/wiki/Style-Guidelines) when submitting pull requests. Otherwise someone else will have to reformat your code so that it fits everything else (or we'll have to reject it if it'll take us too long to clean it up). + +### Other Details + +This document was hastily thrown together in an attempt to improve the bug reporting process. It needs more detail about our intent with the project, the community behind it, our values, and an explanation of how the code itself is designed. \ No newline at end of file diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..bc9287c602 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + +## Description + + + +## Expected Behavior + + + +## Current Behavior + + +## Steps to Reproduce + + +1. +2. +3. + +## Your Environment + + + +* Processing version: +* Operating System and OS version: +* Other information: + +## Possible Causes / Solutions + diff --git a/README.md b/README.md index 9302220f92..ece7d3ab72 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,48 @@ -Processing + + +>[!WARNING] +> # Development has moved to [a new repository](https://github.com/processing/processing4/). + +Since the release of Processing 3.5.4 in January 2020, development has continued in a new repository: [processing/processing4](https://github.com/processing/processing4/). + +We chose to move to a new repository so that we could clean out old files accumulated over the last 20 years. + +To report bugs or request features, please open a [new issue](https://github.com/processing/processing4/issues/new/choose) on the Processing 4 repository. + + + + +~~Processing~~ ========== -This is the official source code for the [Processing](http://processing.org) Development Environment (PDE), -the “core” and the libraries that are included with the [download](http://processing.org/download). +~~This is the official source code for the [Processing](http://processing.org) Development Environment (PDE), +the “core” and the libraries that are included with the [download](http://processing.org/download).~~ + +~~__I've found a bug!__~~ +~~Let us know [here](https://github.com/processing/processing/issues) (after first checking if someone has already posted a similar problem). +If it's a reference, web site, or examples issue, take that up with folks [here](https://github.com/processing/processing-docs/issues). +There are also separate locations for [Android Mode](https://github.com/processing/processing-android/issues), or the [Video](https://github.com/processing/processing-video/issues) and [Sound](https://github.com/processing/processing-sound/issues) libraries. +The [processing.js](http://processingjs.org) project is not affiliated with us, but you can find their issue tracker [here](https://github.com/processing-js/processing-js/issues).~~ -__I've found a bug!__ -Let us know [here](https://github.com/processing/processing/issues) (after first checking if someone has already posted a similar problem). -If it's a documentation, web site, or examples problem, take that up with folks [here](https://github.com/processing/processing-docs/issues). -There are also separate locations for [Android Mode](https://github.com/processing/processing-android/issues), or the [Video](https://github.com/processing/processing-video/issues) and [Sound](https://github.com/processing/processing-sound/issues) libraries. -The [processing.js](http://processingjs.org) project is not affiliated with us, but you can find their issue tracker [here](https://github.com/processing-js/processing-js/issues). +~~__Locked Issues__ +Where possible, I've started locking issues once resolved. This helps reduce the amount of noise from folks adding to an issue that's been closed for years. Because this project has existed for a long time and we have thousands of closed issues, lots of them may sound similar to an issue you're having. But if there's a new problem, it'll be missed if it's lost in a comment added to an already closed issue. I don't like to lock issues because it cuts off conversation, but it's better than legitimate problems being missed. Once an issue has been resolved for 30 days, it will automatically lock.~~ -__That [processing-bugs](https://github.com/processing-bugs) fella is a damn liar.__ -The issues list has been imported from Google Code, so there are many spurious references -amongst them since the numbering changed. Basically, any time you see references to +~~__That [processing-bugs](https://github.com/processing-bugs) fella is suspicious.__ +The issues list has been imported from Google Code, so there are many spurious references +amongst them since the numbering changed. Basically, any time you see references to changes made by [processing-bugs](https://github.com/processing-bugs), it may be somewhat suspect. -Over time this will clean itself up as bugs are fixed and new issues are added from within Github. -Help speed this process along by helping us! +Over time this will clean itself up as bugs are fixed and new issues are added from within GitHub. +Help speed this process along by helping us!~~ -__Please help.__ -The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions). -Please help us fix problems, and if you're submitting code, following the [style guidelines](https://github.com/processing/processing/wiki/Style-Guidelines) helps save us a lot of time. +~~__Please help.__ +The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions). +Please help us fix problems, and if you're submitting code, following the [style guidelines](https://github.com/processing/processing/wiki/Style-Guidelines) helps save me a lot of time.~~ -__And finally...__ -Someday we'll also fix all these bugs, throw together hundreds of unit tests, and get rich off all this stuff that we're giving away for free. But not today. +~~__And finally...__ +Someday we'll also fix all these bugs, throw together hundreds of unit tests, and get rich off all this stuff that we're giving away for free. But not today.~~ -So in the meantime, I ask for your patience, -[participation](https://github.com/processing/processing/wiki/Project-List), -and [patches](https://github.com/processing/processing/pulls). +~~So in the meantime, I ask for your patience, +[participation](https://github.com/processing/processing/wiki/Project-List), +and [patches](https://github.com/processing/processing/pulls).~~ -Ben Fry, 6 August 2015 +~~Ben Fry, 20 January 2019~~ diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs index 9910337705..af36b24305 100644 --- a/app/.settings/org.eclipse.jdt.core.prefs +++ b/app/.settings/org.eclipse.jdt.core.prefs @@ -94,7 +94,12 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 @@ -103,24 +108,39 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 @@ -129,6 +149,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line @@ -138,32 +159,38 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false org.eclipse.jdt.core.formatter.comment.format_block_comments=true org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=1 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true @@ -176,6 +203,7 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=2 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert @@ -185,6 +213,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -198,11 +227,15 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -229,9 +262,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declar org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -256,13 +294,20 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -306,9 +351,13 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_decla org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -345,9 +394,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -359,20 +411,59 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_decla org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never org.eclipse.jdt.core.formatter.lineSplit=80 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.text_block_indentation=0 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/app/.settings/org.eclipse.jdt.ui.prefs b/app/.settings/org.eclipse.jdt.ui.prefs index 7f5ba1ed84..66aaa0890e 100644 --- a/app/.settings/org.eclipse.jdt.ui.prefs +++ b/app/.settings/org.eclipse.jdt.ui.prefs @@ -1,3 +1,3 @@ eclipse.preferences.version=1 formatter_profile=_processing -formatter_settings_version=12 +formatter_settings_version=18 diff --git a/app/lib/jna.txt b/app/lib/jna.txt index acc3f19fb3..4dbac83c25 100644 --- a/app/lib/jna.txt +++ b/app/lib/jna.txt @@ -1,2 +1,4 @@ -The JAR file is JNA 3.5.2 (presumably) downloaded from -https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/3.5.2/ +The JAR file is JNA 4.2.0 + +You can find the corresponding file for Maven here: +https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/4.2.0/ diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 6088c1d11e..5d9b0a114c 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-16 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -31,6 +31,7 @@ import java.lang.reflect.InvocationTargetException; import java.text.SimpleDateFormat; import java.util.*; +import java.util.Map.Entry; import javax.swing.JFileChooser; import javax.swing.JMenu; @@ -55,14 +56,17 @@ public class Base { // Added accessors for 0218 because the UpdateCheck class was not properly // updating the values, due to javac inlining the static final values. - static private final int REVISION = 253; + static private final int REVISION = 271; /** This might be replaced by main() if there's a lib/version.txt file. */ - static private String VERSION_NAME = "0253"; //$NON-NLS-1$ + static private String VERSION_NAME = "0271"; //$NON-NLS-1$ /** Set true if this a proper release rather than a numbered revision. */ - /** True if heavy debugging error/log messages are enabled */ - static public boolean DEBUG = false; -// static public boolean DEBUG = true; + /** + * True if heavy debugging error/log messages are enabled. Set to true + * if an empty file named 'debug' is found in the settings folder. + * See implementation in createAndShowGUI(). + */ + static public boolean DEBUG; static private boolean commandLine; @@ -112,9 +116,31 @@ static public void main(final String[] args) { public void run() { try { createAndShowGUI(args); + } catch (Throwable t) { - Messages.showTrace("It was not meant to be", - "A serious problem happened during startup. Please report:\n" + + // Windows Defender has been insisting on destroying each new + // release by removing core.jar and other files. Yay! + // https://github.com/processing/processing/issues/5537 + if (Platform.isWindows()) { + String mess = t.getMessage(); + String missing = null; + if (mess.contains("Could not initialize class com.sun.jna.Native")) { + missing = "jnidispatch.dll"; + } else if (mess.contains("NoClassDefFoundError: processing/core/PApplet")) { + missing = "core.jar"; + } + if (missing != null) { + Messages.showError("Necessary files are missing", + "A file required by Processing (" + missing + ") is missing.\n\n" + + "Make sure that you're not trying to run Processing from inside\n" + + "the .zip file you downloaded, and check that Windows Defender\n" + + "hasn't removed files from the Processing folder.\n\n" + + "(It sometimes flags parts of Processing as a trojan or virus.\n" + + "It is neither, but Microsoft has ignored our pleas for help.)", t); + } + } + Messages.showTrace("Unknown Problem", + "A serious error happened during startup. Please report:\n" + "http://github.com/processing/processing/issues/new", t, true); } } @@ -129,7 +155,6 @@ static private void createAndShowGUI(String[] args) { String version = PApplet.loadStrings(versionFile)[0]; if (!version.equals(VERSION_NAME)) { VERSION_NAME = version; -// RELEASE = true; } } } catch (Exception e) { @@ -137,6 +162,19 @@ static private void createAndShowGUI(String[] args) { } Platform.init(); + // call after Platform.init() because we need the settings folder + Console.startup(); + + // Set the debug flag based on a file being present in the settings folder + File debugFile = getSettingsFile("debug.txt"); + /* + if (debugFile.isDirectory()) { + // if it's a directory, it's a leftover from older releases, clear it + Util.removeDir(debugFile); + } else*/ + if (debugFile.exists()) { + DEBUG = true; + } // Use native popups so they don't look so crappy on OS X JPopupMenu.setDefaultLightWeightPopupEnabled(false); @@ -163,6 +201,7 @@ static private void createAndShowGUI(String[] args) { boolean sketchbookPrompt = false; if (Preferences.getBoolean("welcome.show")) { + // only ask once about split sketchbooks if (!Preferences.getBoolean("welcome.seen")) { // Check if there's a 2.0 sketchbook present String oldPath = Preferences.getOldSketchbookPath(); @@ -173,9 +212,9 @@ static private void createAndShowGUI(String[] args) { sketchbookPrompt = true; } else if (oldPath.equals(newPath)) { - // If both exist and are identical, then the user has been using - // alpha releases of 3.x and needs to be warned about the larger - // changes in this release. + // If both exist and are identical, then the user has used + // pre-releases of 3.x and needs to be warned about the + // larger changes in this release. sketchbookPrompt = true; } } @@ -185,7 +224,6 @@ static private void createAndShowGUI(String[] args) { // Get the sketchbook path, and make sure it's set properly locateSketchbookFolder(); - // Create a location for untitled sketches try { untitledFolder = Util.createTempFolder("untitled", "sketches", null); @@ -196,29 +234,28 @@ static private void createAndShowGUI(String[] args) { "That's gonna prevent us from continuing.", e); } - Messages.log("about to create base..."); //$NON-NLS-1$ + Messages.log("About to create Base..."); //$NON-NLS-1$ try { final Base base = new Base(args); + Messages.log("Base() constructor succeeded"); + // Prevent more than one copy of the PDE from running. SingleInstance.startServer(base); // Needs to be shown after the first editor window opens, so that it // shows up on top, and doesn't prevent an editor window from opening. if (Preferences.getBoolean("welcome.show")) { - final boolean prompt = sketchbookPrompt; - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - new Welcome(base, prompt); - } catch (IOException e) { - Messages.showTrace("Unwelcoming", - "Please report this error to\n" + - "https://github.com/processing/processing/issues", e, false); - } - } - }); + try { + new Welcome(base, sketchbookPrompt); + } catch (IOException e) { + Messages.showTrace("Unwelcoming", + "Please report this error to\n" + + "https://github.com/processing/processing/issues", e, false); + } } + checkDriverBug(); + } catch (Throwable t) { // Catch-all to pick up badness during startup. if (t.getCause() != null) { @@ -229,7 +266,53 @@ public void run() { Messages.showTrace("We're off on the wrong foot", "An error occurred during startup.", t, true); } - Messages.log("done creating base..."); //$NON-NLS-1$ + Messages.log("Done creating Base..."); //$NON-NLS-1$ + } + } + + + // Remove this code in a couple months [fry 170211] + // https://github.com/processing/processing/issues/4853 + // Or maybe not, if NVIDIA keeps doing this [fry 170423] + // https://github.com/processing/processing/issues/4997 + static private void checkDriverBug() { + if (System.getProperty("os.name").contains("Windows 10")) { + new Thread(new Runnable() { + public void run() { + try { + Process p = Runtime.getRuntime().exec("powershell Get-WmiObject Win32_PnPSignedDriver| select devicename, driverversion | where {$_.devicename -like \\\"*nvidia*\\\"}"); + BufferedReader reader = PApplet.createReader(p.getInputStream()); + String line = null; + while ((line = reader.readLine()) != null) { + if (line.contains("3.7849")) { + EventQueue.invokeLater(new Runnable() { + public void run() { + Messages.showWarning("NVIDIA screwed up", + "Due to an NVIDIA bug, you need to update your graphics drivers,\n" + + "otherwise you won't be able to run any sketches. Update here:\n" + + "http://nvidia.custhelp.com/app/answers/detail/a_id/4378\n" + + "or read background about the issue at this link:\n" + + "https://github.com/processing/processing/issues/4853"); + } + }); + } else if (line.contains("3.8165")) { + EventQueue.invokeLater(new Runnable() { + public void run() { + Messages.showWarning("NVIDIA screwed up again", + "Due to an NVIDIA bug, you need to update your graphics drivers,\n" + + "otherwise you won't be able to run any sketches. Update here:\n" + + "http://nvidia.custhelp.com/app/answers/detail/a_id/4453/\n" + + "or read background about the issue at this link:\n" + + "https://github.com/processing/processing/issues/4997"); + } + }); + } + } + } catch (Exception e) { + Messages.loge("Problem checking NVIDIA driver", e); + } + } + }).start(); } } @@ -314,6 +397,8 @@ public Base(String[] args) throws Exception { // Check if any files were passed in on the command line for (int i = 0; i < args.length; i++) { + Messages.logf("Parsing command line... args[%d] = '%s'", i, args[i]); + String path = args[i]; // Fix a problem with systems that use a non-ASCII languages. Paths are // being passed in with 8.3 syntax, which makes the sketch loader code @@ -323,6 +408,7 @@ public Base(String[] args) throws Exception { try { File file = new File(args[i]); path = file.getCanonicalPath(); + Messages.logf("Changing %s to canonical %s", i, args[i], path); } catch (IOException e) { e.printStackTrace(); } @@ -334,10 +420,10 @@ public Base(String[] args) throws Exception { // Create a new empty window (will be replaced with any files to be opened) if (!opened) { -// System.out.println("opening a new window"); + Messages.log("Calling handleNew() to open a new window"); handleNew(); -// } else { -// System.out.println("something else was opened"); + } else { + Messages.log("No handleNew(), something passed on the command line"); } // check for updates @@ -378,12 +464,12 @@ void buildCoreModes() { */ void rebuildContribModes() { if (modeContribs == null) { - modeContribs = new ArrayList(); + modeContribs = new ArrayList<>(); } File modesFolder = getSketchbookModesFolder(); List contribModes = getModeContribs(); - Map known = new HashMap(); + Map known = new HashMap<>(); for (ModeContribution contrib : contribModes) { known.put(contrib.getFolder(), contrib); } @@ -427,7 +513,10 @@ void rebuildContribModes() { System.out.println("Attempting to load " + modeClass + " with resources at " + modeResourcePath); ModeContribution mc = ModeContribution.load(this, new File(modeResourcePath), modeClass); contribModes.add(mc); - known.remove(mc); + File key = getFileForContrib(mc, known); + if (key != null) { + known.remove(key); + } } if (known.size() != 0) { for (ModeContribution mc : known.values()) { @@ -437,6 +526,17 @@ void rebuildContribModes() { } + static private File getFileForContrib(ModeContribution contrib, + Map known) { + for (Entry entry : known.entrySet()) { + if (entry.getValue() == contrib) { + return entry.getKey(); + } + } + return null; + } + + /** * Instantiates and adds new contributed modes to the contribModes list. * Checks for duplicates so the same mode isn't instantiates twice. Does not @@ -444,7 +544,7 @@ void rebuildContribModes() { */ void rebuildContribExamples() { if (exampleContribs == null) { - exampleContribs = new ArrayList(); + exampleContribs = new ArrayList<>(); } ExamplesContribution.loadMissing(this); } @@ -570,7 +670,7 @@ public void removeToolContrib(ToolContribution tc) { public void rebuildToolList() { // Only do this once because the list of internal tools will never change if (internalTools == null) { - internalTools = new ArrayList(); + internalTools = new ArrayList<>(); initInternalTool("processing.app.tools.CreateFont"); initInternalTool("processing.app.tools.ColorSelector"); @@ -635,7 +735,8 @@ public void rebuildToolList() { protected void initInternalTool(String className) { try { Class toolClass = Class.forName(className); - final Tool tool = (Tool) toolClass.newInstance(); + final Tool tool = (Tool) + toolClass.getDeclaredConstructor().newInstance(); tool.init(this); internalTools.add(tool); @@ -778,7 +879,7 @@ public List getModeContribs() { public List getModeList() { - List allModes = new ArrayList(); + List allModes = new ArrayList<>(); allModes.addAll(Arrays.asList(coreModes)); if (modeContribs != null) { for (ModeContribution contrib : modeContribs) { @@ -795,14 +896,14 @@ public List getExampleContribs() { private List getInstalledContribs() { - List contributions = new ArrayList(); + List contributions = new ArrayList<>(); List modeContribs = getModeContribs(); contributions.addAll(modeContribs); for (ModeContribution modeContrib : modeContribs) { Mode mode = modeContrib.getMode(); - contributions.addAll(new ArrayList(mode.contribLibraries)); + contributions.addAll(new ArrayList<>(mode.contribLibraries)); } // TODO this duplicates code in Editor, but it's not editor-specific @@ -823,11 +924,11 @@ public byte[] getInstalledContribsInfo() { String entry = c.getTypeName() + "=" + PApplet.urlEncode(String.format("name=%s\nurl=%s\nrevision=%d\nversion=%s", c.getName(), c.getUrl(), - c.getVersion(), c.getPrettyVersion())); + c.getVersion(), c.getBenignVersion())); entries.append(entry); } String joined = - "id=" + Preferences.get("update.id") + "&" + entries.join("&"); + "id=" + UpdateCheck.getUpdateID() + "&" + entries.join("&"); // StringBuilder sb = new StringBuilder(); // try { // // Truly ridiculous attempt to shove everything into a GET request. @@ -966,7 +1067,7 @@ private static ModeInfo modeInfoFor(final File sketch) { private Mode promptForMode(final File sketch, final ModeInfo preferredMode) { final String extension = sketch.getName().substring(sketch.getName().lastIndexOf('.') + 1); - final List possibleModes = new ArrayList(); + final List possibleModes = new ArrayList<>(); for (final Mode mode : getModeList()) { if (mode.canEdit(sketch)) { possibleModes.add(mode); @@ -1457,6 +1558,9 @@ public boolean handleQuit() { // Save out the current prefs state Preferences.save(); + // Finished with this guy + Console.shutdown(); + if (!Platform.isMacOS()) { // If this was fired from the menu or an AppleEvent (the Finder), // then Mac OS X will send the terminate signal itself. @@ -1595,6 +1699,15 @@ protected boolean addSketches(JMenu menu, File folder, return false; // let's not go there } + if (folder.getName().equals("sdk")) { + // This could be Android's SDK folder. Let's double check: + File suspectSDKPath = new File(folder.getParent(), folder.getName()); + File expectedSDKPath = new File(sketchbookFolder, "android" + File.separator + "sdk"); + if (expectedSDKPath.getAbsolutePath().equals(suspectSDKPath.getAbsolutePath())) { + return false; // Most likely the SDK folder, skip it + } + } + String[] list = folder.list(); // If a bad folder or unreadable or whatever, this will come back null if (list == null) { @@ -1806,8 +1919,10 @@ static public File getSettingsFolder() { } } } catch (Exception e) { - Messages.showError("Problem getting the settings folder", - "Error getting the Processing the settings folder.", e); + Messages.showTrace("An rare and unknowable thing happened", + "Could not get the settings folder. Please report:\n" + + "http://github.com/processing/processing/issues/new", + e, true); } return settingsFolder; } diff --git a/app/src/processing/app/BaseSplash.java b/app/src/processing/app/BaseSplash.java index 39848de5ea..5dc125f6a1 100644 --- a/app/src/processing/app/BaseSplash.java +++ b/app/src/processing/app/BaseSplash.java @@ -9,7 +9,7 @@ public class BaseSplash { static public void main(String[] args) { try { - final boolean hidpi = Toolkit.highResDisplay(); + final boolean hidpi = Toolkit.highResImages(); final String filename = "lib/about-" + (hidpi ? 2 : 1) + "x.png"; File splashFile = Platform.getContentFile(filename); SplashWindow.splash(splashFile.toURI().toURL(), hidpi); diff --git a/app/src/processing/app/Console.java b/app/src/processing/app/Console.java new file mode 100644 index 0000000000..73b652f337 --- /dev/null +++ b/app/src/processing/app/Console.java @@ -0,0 +1,261 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012-16 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app; + +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Date; + + +/** + * Non-GUI handling of System.out and System.err redirection. + *

+ * Be careful when debugging this class, because if it's throwing exceptions, + * don't take over System.err, and debug while watching just System.out + * or just call println() or whatever directly to systemOut or systemErr. + *

+ * Also note that encodings will not work properly when run from Eclipse. This + * means that if you use non-ASCII characters in a println() or some such, + * the characters won't print properly in the Processing and/or Eclipse console. + * It seems that Eclipse's console-grabbing and that of Processing don't + * get along with one another. Use 'ant run' to work on encoding-related issues. + */ +public class Console { + // Single static instance shared because there's only one real System.out. + // Within the input handlers, the currentConsole variable will be used to + // echo things to the correct location. + + /** The original System.out */ + static PrintStream systemOut; + /** The original System.err */ + static PrintStream systemErr; + + /** Our replacement System.out */ + static PrintStream consoleOut; + /** Our replacement System.err */ + static PrintStream consoleErr; + + /** All stdout also written to a file */ + static OutputStream stdoutFile; + /** All stderr also written to a file */ + static OutputStream stderrFile; + + /** stdout listener for the currently active Editor */ + static OutputStream editorOut; + /** stderr listener for the currently active Editor */ + static OutputStream editorErr; + + + static public void startup() { + if (systemOut != null) { + // TODO fix this dreadful style choice in how the Console is initialized + // (This is not good code.. startup() should gracefully deal with this. + // It's just a low priority relative to the likelihood of trouble.) + new Exception("startup() called more than once").printStackTrace(systemErr); + return; + } + systemOut = System.out; + systemErr = System.err; + + // placing everything inside a try block because this can be a dangerous + // time for the lights to blink out and crash for and obscure reason. + try { + SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd_HHmmss"); + // Moving away from a random string in 0256 (and adding hms) because + // the random digits looked like times anyway, causing confusion. + //String randy = String.format("%04d", (int) (1000 * Math.random())); + //final String stamp = formatter.format(new Date()) + "_" + randy; + final String stamp = formatter.format(new Date()); + + File consoleDir = Base.getSettingsFile("console"); + if (consoleDir.exists()) { + // clear old debug files + File[] stdFiles = consoleDir.listFiles(new FileFilter() { + final String todayPrefix = stamp.substring(0, 4); + + public boolean accept(File file) { + if (!file.isDirectory()) { + String name = file.getName(); + if (name.endsWith(".err") || name.endsWith(".out")) { + // don't delete any of today's debug messages + return !name.startsWith(todayPrefix); + } + } + return false; + } + }); + // Remove any files that aren't from today + for (File file : stdFiles) { + file.delete(); + } + } else { + consoleDir.mkdirs(); + consoleDir.setWritable(true, false); + } + + File outFile = new File(consoleDir, stamp + ".out"); + outFile.setWritable(true, false); + stdoutFile = new FileOutputStream(outFile); + File errFile = new File(consoleDir, stamp + ".err"); + errFile.setWritable(true, false); + stderrFile = new FileOutputStream(errFile); + + consoleOut = new PrintStream(new ConsoleStream(false)); + consoleErr = new PrintStream(new ConsoleStream(true)); + + System.setOut(consoleOut); + System.setErr(consoleErr); + + } catch (Exception e) { + stdoutFile = null; + stderrFile = null; + + consoleOut = null; + consoleErr = null; + + System.setOut(systemOut); + System.setErr(systemErr); + + e.printStackTrace(); + } + } + + + static public void setEditor(OutputStream out, OutputStream err) { + editorOut = out; + editorErr = err; + } + + + static public void systemOut(String what) { + systemOut.println(what); + } + + + static public void systemErr(String what) { + systemErr.println(what); + } + + + /** + * Close the streams so that the temporary files can be deleted. + *

+ * File.deleteOnExit() cannot be used because the stdout and stderr + * files are inside a folder, and have to be deleted before the + * folder itself is deleted, which can't be guaranteed when using + * the deleteOnExit() method. + */ + static public void shutdown() { + // replace original streams to remove references to console's streams + System.setOut(systemOut); + System.setErr(systemErr); + + cleanup(consoleOut); + cleanup(consoleErr); + + // also have to close the original FileOutputStream + // otherwise it won't be shut down completely + cleanup(stdoutFile); + cleanup(stderrFile); + } + + + static private void cleanup(OutputStream output) { + try { + if (output != null) { + output.flush(); + output.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static class ConsoleStream extends OutputStream { + boolean err; // whether stderr or stdout + byte single[] = new byte[1]; + + public ConsoleStream(boolean err) { + this.err = err; + } + + public void close() { } + + public void flush() { } + + public void write(byte b[]) { // appears never to be used + write(b, 0, b.length); + } + + public void write(byte b[], int offset, int length) { + // First write to the original stdout/stderr + if (err) { + systemErr.write(b, offset, length); + } else { + systemOut.write(b, offset, length); + } + + // Write to the files that are storing this information + writeFile(b, offset, length); + + // Write to the console of the current Editor, if any + try { + if (err) { + if (editorErr != null) { + editorErr.write(b, offset, length); + } + } else { + if (editorOut != null) { + editorOut.write(b, offset, length); + } + } + } catch (IOException e) { + // Avoid this function being called in a recursive, infinite loop + e.printStackTrace(systemErr); + } + } + + public void writeFile(byte b[], int offset, int length) { + final OutputStream echo = err ? stderrFile : stdoutFile; + if (echo != null) { + try { + echo.write(b, offset, length); + echo.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void write(int b) { + single[0] = (byte) b; + write(single, 0, 1); + } + } +} \ No newline at end of file diff --git a/app/src/processing/app/Language.java b/app/src/processing/app/Language.java index 93543d10d3..06be82fc5a 100644 --- a/app/src/processing/app/Language.java +++ b/app/src/processing/app/Language.java @@ -89,15 +89,18 @@ static private String[] listSupported() { // List of languages in alphabetical order. (Add yours here.) // Also remember to add it to build/shared/lib/languages/languages.txt. final String[] SUPPORTED = { + "ar", // Arabic "de", // German, Deutsch "en", // English "el", // Greek "es", // Spanish "fr", // French, Français + "it", // Italiano, Italian "ja", // Japanese "ko", // Korean "nl", // Dutch, Nederlands "pt", // Portuguese + "ru", // Russian "tr", // Turkish "uk", // Ukrainian "zh" // Chinese @@ -146,6 +149,7 @@ static private String loadLanguage() { static public void saveLanguage(String language) { try { Util.saveFile(language, prefFile); + prefFile.setWritable(true, false); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/processing/app/Library.java b/app/src/processing/app/Library.java index 757449a644..34bc6360e1 100644 --- a/app/src/processing/app/Library.java +++ b/app/src/processing/app/Library.java @@ -71,6 +71,7 @@ public boolean accept(File dir, String name) { if (name.equals("linux32")) return false; if (name.equals("linux64")) return false; if (name.equals("linux-armv6hf")) return false; + if (name.equals("linux-arm64")) return false; if (name.equals("android")) return false; } return true; @@ -127,7 +128,7 @@ protected void handle() { StringDict exportTable = exportSettings.exists() ? Util.readSettings(exportSettings) : new StringDict(); - exportList = new HashMap(); + exportList = new HashMap<>(); // get the list of files just in the library root String[] baseList = libraryFolder.list(standardFilter); @@ -173,6 +174,12 @@ protected void handle() { nativeLibraryFolder = hostLibrary; } } + if (hostPlatform.equals("linux") && System.getProperty("os.arch").equals("aarch64")) { + hostLibrary = new File(libraryFolder, "linux-arm64"); + if (hostLibrary.exists()) { + nativeLibraryFolder = hostLibrary; + } + } // save that folder for later use nativeLibraryPath = nativeLibraryFolder.getAbsolutePath(); @@ -182,7 +189,8 @@ protected void handle() { String platformName = platformNames[i]; String platformName32 = platformName + "32"; String platformName64 = platformName + "64"; - String platformNameArmv6hh = platformName + "-armv6hf"; + String platformNameArmv6hf = platformName + "-armv6hf"; + String platformNameArm64 = platformName + "-arm64"; // First check for things like 'application.macosx=' or 'application.windows32' in the export.txt file. // These will override anything in the platform-specific subfolders. @@ -194,6 +202,8 @@ protected void handle() { String[] platformList64 = platform64 == null ? null : PApplet.splitTokens(platform64, ", "); String platformArmv6hf = exportTable.get("application." + platformName + "-armv6hf"); String[] platformListArmv6hf = platformArmv6hf == null ? null : PApplet.splitTokens(platformArmv6hf, ", "); + String platformArm64 = exportTable.get("application." + platformName + "-arm64"); + String[] platformListArm64 = platformArm64 == null ? null : PApplet.splitTokens(platformArm64, ", "); // If nothing specified in the export.txt entries, look for the platform-specific folders. if (platformAll == null) { @@ -206,16 +216,19 @@ protected void handle() { platformList64 = listPlatformEntries(libraryFolder, platformName64, baseList); } if (platformListArmv6hf == null) { - platformListArmv6hf = listPlatformEntries(libraryFolder, platformNameArmv6hh, baseList); + platformListArmv6hf = listPlatformEntries(libraryFolder, platformNameArmv6hf, baseList); + } + if (platformListArm64 == null) { + platformListArm64 = listPlatformEntries(libraryFolder, platformNameArm64, baseList); } - if (platformList32 != null || platformList64 != null || platformListArmv6hf != null) { + if (platformList32 != null || platformList64 != null || platformListArmv6hf != null || platformListArm64 != null) { multipleArch[i] = true; } // if there aren't any relevant imports specified or in their own folders, // then use the baseList (root of the library folder) as the default. - if (platformList == null && platformList32 == null && platformList64 == null && platformListArmv6hf == null) { + if (platformList == null && platformList32 == null && platformList64 == null && platformListArmv6hf == null && platformListArm64 == null) { exportList.put(platformName, baseList); } else { @@ -231,7 +244,10 @@ protected void handle() { exportList.put(platformName64, platformList64); } if (platformListArmv6hf != null) { - exportList.put(platformNameArmv6hh, platformListArmv6hf); + exportList.put(platformNameArmv6hf, platformListArmv6hf); + } + if (platformListArm64 != null) { + exportList.put(platformNameArm64, platformListArm64); } } } @@ -266,7 +282,7 @@ static String[] listPlatformEntries(File libraryFolder, String folderName, Strin } - static protected HashMap packageWarningMap = new HashMap(); + static protected HashMap packageWarningMap = new HashMap<>(); /** * Add the packages provided by this library to the master list that maps @@ -282,7 +298,7 @@ public void addPackageList(Map> importToLibraryTable) { // Library library = importToLibraryTable.get(pkg); List libraries = importToLibraryTable.get(pkg); if (libraries == null) { - libraries = new ArrayList(); + libraries = new ArrayList<>(); importToLibraryTable.put(pkg, libraries); } else { if (Base.DEBUG) { @@ -412,6 +428,9 @@ public String[] getApplicationExportList(int platform, String variant) { } else if (variant.equals("armv6hf")) { String[] pieces = exportList.get(platformName + "-armv6hf"); if (pieces != null) return pieces; + } else if (variant.equals("arm64")) { + String[] pieces = exportList.get(platformName + "-arm64"); + if (pieces != null) return pieces; } return exportList.get(platformName); } @@ -442,12 +461,7 @@ public boolean supportsArch(int platform, String variant) { static public boolean hasMultipleArch(int platform, List libraries) { - for (Library library : libraries) { - if (library.hasMultipleArch(platform)) { - return true; - } - } - return false; + return libraries.stream().anyMatch(library -> library.hasMultipleArch(platform)); } @@ -456,24 +470,26 @@ static public boolean hasMultipleArch(int platform, List libraries) { static protected FilenameFilter junkFolderFilter = new FilenameFilter() { public boolean accept(File dir, String name) { - // skip .DS_Store files, .svn folders, etc + // skip .DS_Store files, .svn and .git folders, etc if (name.charAt(0) == '.') return false; - if (name.equals("CVS")) return false; - return (new File(dir, name).isDirectory()); + if (name.equals("CVS")) return false; // old skool + return new File(dir, name).isDirectory(); } }; static public List discover(File folder) { - List libraries = new ArrayList(); + List libraries = new ArrayList<>(); String[] folderNames = folder.list(junkFolderFilter); - // if a bad folder or something like that, this might come back null + // if a bad folder or unreadable, folderNames might be null if (folderNames != null) { // alphabetize list, since it's not always alpha order // replaced hella slow bubble sort with this feller for 0093 Arrays.sort(folderNames, String.CASE_INSENSITIVE_ORDER); + // TODO some weirdness because ContributionType.LIBRARY.isCandidate() + // handles some, but not all, of this [fry 200116] for (String potentialName : folderNames) { File baseFolder = new File(folder, potentialName); File libraryFolder = new File(baseFolder, "library"); @@ -486,22 +502,13 @@ static public List discover(File folder) { libraries.add(baseFolder); } else { - String mess = "The library \"" - + potentialName - + "\" cannot be used.\n" - + "Library names must contain only basic letters and numbers.\n" - + "(ASCII only and no spaces, and it cannot start with a number)"; + final String mess = + "The library \"" + potentialName + "\" cannot be used.\n" + + "Library names must contain only basic letters and numbers.\n" + + "(ASCII only and no spaces, and it cannot start with a number)"; Messages.showMessage("Ignoring bad library name", mess); continue; } - /* - } else { // maybe it's a JS library - // TODO this should be in a better location - File jsLibrary = new File(libraryFolder, potentialName + ".js"); - if (jsLibrary.exists()) { - libraries.add(baseFolder); - } - */ } } } @@ -510,14 +517,15 @@ static public List discover(File folder) { static public List list(File folder) { - List libraries = new ArrayList(); - List librariesFolders = new ArrayList(); + List libraries = new ArrayList<>(); + List librariesFolders = new ArrayList<>(); librariesFolders.addAll(discover(folder)); for (File baseFolder : librariesFolders) { libraries.add(new Library(baseFolder)); } + /* // Support libraries inside of one level of subfolders? I believe this was // the compromise for supporting library groups, but probably a bad idea // because it's not compatible with the Manager. @@ -534,6 +542,7 @@ static public List list(File folder) { } } } + */ return libraries; } diff --git a/app/src/processing/app/Messages.java b/app/src/processing/app/Messages.java index 07e1a62472..d8c78d43f1 100644 --- a/app/src/processing/app/Messages.java +++ b/app/src/processing/app/Messages.java @@ -156,7 +156,7 @@ static public void showError(String title, String message, Throwable e) { * Testing a new warning window that includes the stack trace. */ static public void showTrace(String title, String message, - Throwable t, boolean fatal) { + Throwable t, boolean fatal) { if (title == null) title = fatal ? "Error" : "Warning"; if (Base.isCommandLine()) { @@ -265,6 +265,34 @@ static public int showYesNoQuestion(Frame editor, String title, "
" + secondary, title, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + } else { + int result = showCustomQuestion(editor, title, primary, secondary, + 0, "Yes", "No"); + if (result == 0) { + return JOptionPane.YES_OPTION; + } else if (result == 1) { + return JOptionPane.NO_OPTION; + } else { + return JOptionPane.CLOSED_OPTION; + } + } + } + + + /** + * @param highlight A valid array index for options[] that specifies the + * default (i.e. safe) choice. + * @return The (zero-based) index of the selected value, -1 otherwise. + */ + static public int showCustomQuestion(Frame editor, String title, + String primary, String secondary, + int highlight, String... options) { + Object result; + if (!Platform.isMacOS()) { + return JOptionPane.showOptionDialog(editor, + "" + primary + "
" + secondary, title, + JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, + options, options[highlight]); } else { // Pane formatting adapted from the Quaqua guide // http://www.randelshofer.ch/quaqua/guide/joptionpane.html @@ -275,29 +303,23 @@ static public int showYesNoQuestion(Frame editor, String title, "p { font: 11pt \"Lucida Grande\"; margin-top: 8px; width: 300px }"+ " " + "" + primary + "" + - "

" + secondary + "

", + "

" + secondary, // + "

", JOptionPane.QUESTION_MESSAGE); - String[] options = new String[] { - "Yes", "No" - }; pane.setOptions(options); // highlight the safest option ala apple hig - pane.setInitialValue(options[0]); + pane.setInitialValue(options[highlight]); JDialog dialog = pane.createDialog(editor, null); dialog.setVisible(true); - Object result = pane.getValue(); - if (result == options[0]) { - return JOptionPane.YES_OPTION; - } else if (result == options[1]) { - return JOptionPane.NO_OPTION; - } else { - return JOptionPane.CLOSED_OPTION; - } + result = pane.getValue(); } + for (int i = 0; i < options.length; i++) { + if (result != null && result.equals(options[i])) return i; + } + return -1; } @@ -327,7 +349,9 @@ static public void logf(String message, Object... args) { static public void loge(String message, Throwable e) { if (Base.DEBUG) { - System.err.println(message); + if (message != null) { + System.err.println(message); + } e.printStackTrace(); } } @@ -335,7 +359,7 @@ static public void loge(String message, Throwable e) { static public void loge(String message) { if (Base.DEBUG) { - System.out.println(message); + System.err.println(message); } } -} \ No newline at end of file +} diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index 3bdbeebc75..9c87f7232b 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -53,8 +53,7 @@ public abstract class Mode { protected File folder; protected TokenMarker tokenMarker; - protected Map keywordToReference = - new HashMap(); + protected Map keywordToReference = new HashMap<>(); protected Settings theme; // protected Formatter formatter; @@ -166,7 +165,13 @@ protected void loadKeywords(File keywordFile, if (htmlFilename.endsWith("_")) { keyword += "_"; } - keywordToReference.put(keyword, htmlFilename); + // Allow the bare size() command to override the lookup + // for StringList.size() and others, but not vice-versa. + // https://github.com/processing/processing/issues/4224 + boolean seen = keywordToReference.containsKey(keyword); + if (!seen || (seen && keyword.equals(htmlFilename))) { + keywordToReference.put(keyword, htmlFilename); + } } } } @@ -206,6 +211,14 @@ public void setupGUI() { theme.load(modeTheme); } + // Against my better judgment, adding the ability to override themes + // https://github.com/processing/processing/issues/5445 + File sketchbookTheme = + new File(Base.getSketchbookFolder(), "theme.txt"); + if (sketchbookTheme.exists()) { + theme.load(sketchbookTheme); + } + // other things that have to be set explicitly for the defaults theme.setColor("run.window.bgcolor", SystemColor.control); @@ -592,7 +605,7 @@ public void actionPerformed(ActionEvent e) { contrib.setEnabled(false); importMenu.add(contrib); - HashMap subfolders = new HashMap(); + HashMap subfolders = new HashMap<>(); for (Library library : contribLibraries) { JMenuItem item = new JMenuItem(library.getName()); @@ -650,6 +663,7 @@ public void rebuildExamplesFrame() { if (visible) { bounds = examplesFrame.getBounds(); examplesFrame.setVisible(false); + examplesFrame.dispose(); } examplesFrame = null; if (visible) { @@ -685,11 +699,19 @@ public DefaultMutableTreeNode buildSketchbookTree() { /** Sketchbook has changed, update it on next viewing. */ public void rebuildSketchbookFrame() { - boolean wasVisible = - (sketchbookFrame == null) ? false : sketchbookFrame.isVisible(); - sketchbookFrame = null; // Force a rebuild - if (wasVisible) { - showSketchbookFrame(); + if (sketchbookFrame != null) { + boolean visible = sketchbookFrame.isVisible(); + Rectangle bounds = null; + if (visible) { + bounds = sketchbookFrame.getBounds(); + sketchbookFrame.setVisible(false); + sketchbookFrame.dispose(); + } + sketchbookFrame = null; + if (visible) { + showSketchbookFrame(); + sketchbookFrame.setBounds(bounds); + } } } @@ -738,7 +760,7 @@ public Image loadImage(String filename) { public Image loadImageX(String filename) { - final int res = Toolkit.highResDisplay() ? 2 : 1; + final int res = Toolkit.highResImages() ? 2 : 1; return loadImage(filename + "-" + res + "x.png"); } @@ -1002,10 +1024,13 @@ public void prepareExportFolder(File targetFolder) { if (targetFolder != null) { // Nuke the old applet/application folder because it can cause trouble if (Preferences.getBoolean("export.delete_target_folder")) { - try { - Platform.deleteFile(targetFolder); - } catch (IOException e) { - e.printStackTrace(); + if (targetFolder.exists()) { + try { + Platform.deleteFile(targetFolder); + } catch (IOException e) { + // ignore errors/continue; likely to be ok + e.printStackTrace(); + } } } // Create a fresh output folder (needed before preproc is run next) diff --git a/app/src/processing/app/Platform.java b/app/src/processing/app/Platform.java index 91ea3c3d12..16a31bf80e 100644 --- a/app/src/processing/app/Platform.java +++ b/app/src/processing/app/Platform.java @@ -41,14 +41,14 @@ public class Platform { static DefaultPlatform inst; - static Map platformNames = new HashMap(); + static Map platformNames = new HashMap<>(); static { platformNames.put(PConstants.WINDOWS, "windows"); //$NON-NLS-1$ platformNames.put(PConstants.MACOSX, "macosx"); //$NON-NLS-1$ platformNames.put(PConstants.LINUX, "linux"); //$NON-NLS-1$ } - static Map platformIndices = new HashMap(); + static Map platformIndices = new HashMap<>(); static { platformIndices.put("windows", PConstants.WINDOWS); //$NON-NLS-1$ platformIndices.put("macosx", PConstants.MACOSX); //$NON-NLS-1$ @@ -86,7 +86,7 @@ static public void init() { } else if (Platform.isLinux()) { platformClass = Class.forName("processing.app.platform.LinuxPlatform"); //$NON-NLS-1$ } - inst = (DefaultPlatform) platformClass.newInstance(); + inst = (DefaultPlatform) platformClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { Messages.showError("Problem Setting the Platform", "An unknown error occurred while trying to load\n" + @@ -150,7 +150,7 @@ static public void openURL(String url) { } catch (Exception e) { Messages.showWarning("Problem Opening URL", - "Could not open the URL\n" + url, e); + "Could not open the URL\n" + url, e); } } @@ -195,6 +195,7 @@ static public int getNativeBits() { * Return the value of the os.arch property */ static public String getNativeArch() { + // This will return "arm" for 32-bit ARM, "aarch64" for 64-bit ARM (both on Linux) return System.getProperty("os.arch"); } @@ -211,8 +212,12 @@ static public String getVariant() { static public String getVariant(int platform, String arch, int bits) { if (platform == PConstants.LINUX && bits == 32 && "arm".equals(Platform.getNativeArch())) { - return "armv6hf"; // assume armv6hf for now + return "armv6hf"; // assume armv6hf + } else if (platform == PConstants.LINUX && + bits == 64 && "aarch64".equals(Platform.getNativeArch())) { + return "arm64"; } + return Integer.toString(bits); // 32 or 64 } @@ -399,4 +404,12 @@ static public String getenv(String variable) { static public int unsetenv(String variable) { return inst.unsetenv(variable); } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public int getSystemDPI() { + return inst.getSystemDPI(); + } } \ No newline at end of file diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 12abb56f4f..1b05083e19 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2014 The Processing Foundation + Copyright (c) 2014-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -53,7 +53,7 @@ public class Preferences { static final String PREFS_FILE = "preferences.txt"; //$NON-NLS-1$ static Map defaults; - static Map table = new HashMap(); + static Map table = new HashMap<>(); static File preferencesFile; @@ -68,12 +68,12 @@ static public void init() { load(Base.getLibStream(DEFAULTS_FILE)); } catch (Exception e) { Messages.showError(null, "Could not read default settings.\n" + - "You'll need to reinstall Processing.", e); + "You'll need to reinstall Processing.", e); } // Clone the defaults, then override any them with the user's preferences. // This ensures that any new/added preference will be present. - defaults = new HashMap(table); + defaults = new HashMap<>(table); // other things that have to be set explicitly for the defaults setColor("run.window.bgcolor", SystemColor.control); //$NON-NLS-1$ @@ -109,9 +109,12 @@ static public void init() { PApplet.useNativeSelect = Preferences.getBoolean("chooser.files.native"); //$NON-NLS-1$ - // Use the system proxy settings by default - // https://github.com/processing/processing/issues/2643 - System.setProperty("java.net.useSystemProxies", "true"); + // Adding option to disable this in case it's getting in the way + if (get("proxy.system").equals("true")) { + // Use the system proxy settings by default + // https://github.com/processing/processing/issues/2643 + System.setProperty("java.net.useSystemProxies", "true"); + } // Set HTTP, HTTPS, and SOCKS proxies for individuals // who want/need to override the system setting @@ -213,6 +216,7 @@ static public void save() { try { File dir = preferencesFile.getParentFile(); File preferencesTemp = File.createTempFile("preferences", ".txt", dir); + preferencesTemp.setWritable(true, false); // Fix for 0163 to properly use Unicode when writing preferences.txt PrintWriter writer = PApplet.createWriter(preferencesTemp); diff --git a/app/src/processing/app/Problem.java b/app/src/processing/app/Problem.java index 7cd93db511..cb12ad5e3e 100644 --- a/app/src/processing/app/Problem.java +++ b/app/src/processing/app/Problem.java @@ -26,7 +26,7 @@ public interface Problem { public boolean isWarning(); public int getTabIndex(); - public int getLineNumber(); + public int getLineNumber(); // 0-indexed public String getMessage(); public int getStartOffset(); diff --git a/app/src/processing/app/RunnerListenerEdtAdapter.java b/app/src/processing/app/RunnerListenerEdtAdapter.java new file mode 100644 index 0000000000..a436eefbca --- /dev/null +++ b/app/src/processing/app/RunnerListenerEdtAdapter.java @@ -0,0 +1,48 @@ +package processing.app; + +import java.awt.EventQueue; + +public class RunnerListenerEdtAdapter implements RunnerListener { + + private RunnerListener wrapped; + + public RunnerListenerEdtAdapter(RunnerListener wrapped) { + this.wrapped = wrapped; + } + + @Override + public void statusError(String message) { + EventQueue.invokeLater(() -> wrapped.statusError(message)); + } + + @Override + public void statusError(Exception exception) { + EventQueue.invokeLater(() -> wrapped.statusError(exception)); + } + + @Override + public void statusNotice(String message) { + EventQueue.invokeLater(() -> wrapped.statusNotice(message)); + } + + @Override + public void startIndeterminate() { + EventQueue.invokeLater(() -> wrapped.startIndeterminate()); + } + + @Override + public void stopIndeterminate() { + EventQueue.invokeLater(() -> wrapped.stopIndeterminate()); + } + + @Override + public void statusHalt() { + EventQueue.invokeLater(() -> wrapped.statusHalt()); + } + + @Override + public boolean isHalted() { + return wrapped.isHalted(); + } +} + diff --git a/app/src/processing/app/Settings.java b/app/src/processing/app/Settings.java index 4b155a5edb..efd016f231 100644 --- a/app/src/processing/app/Settings.java +++ b/app/src/processing/app/Settings.java @@ -205,6 +205,7 @@ public Font getFont(String attr) { style |= Font.ITALIC; } int size = PApplet.parseInt(pieces[2], 12); + size = Toolkit.zoom(size); // replace bad font with the default from lib/preferences.txt if (replace) { diff --git a/app/src/processing/app/SingleInstance.java b/app/src/processing/app/SingleInstance.java index e04678ce67..d9409d1526 100644 --- a/app/src/processing/app/SingleInstance.java +++ b/app/src/processing/app/SingleInstance.java @@ -57,12 +57,15 @@ static boolean alreadyRunning(String[] args) { static void startServer(final Base base) { try { - final ServerSocket ss = new ServerSocket(0, 0, InetAddress.getByName(null)); + Messages.log("Opening SingleInstance socket"); + final ServerSocket ss = + new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); Preferences.set(SERVER_PORT, "" + ss.getLocalPort()); final String key = "" + Math.random(); Preferences.set(SERVER_KEY, key); Preferences.save(); + Messages.log("Starting SingleInstance thread"); new Thread(new Runnable() { public void run() { while (true) { @@ -119,15 +122,17 @@ public void run() { static boolean sendArguments(String[] args) { //, long timeout) { try { + Messages.log("Checking to see if Processing is already running"); int port = Preferences.getInteger(SERVER_PORT); String key = Preferences.get(SERVER_KEY); Socket socket = null; try { - socket = new Socket(InetAddress.getByName(null), port); + socket = new Socket(InetAddress.getLoopbackAddress(), port); } catch (Exception ignored) { } if (socket != null) { + Messages.log("Processing is already running, sending command line"); PrintWriter writer = PApplet.createWriter(socket.getOutputStream()); writer.println(key); for (String arg : args) { @@ -138,9 +143,9 @@ static boolean sendArguments(String[] args) { //, long timeout) { return true; } } catch (IOException e) { - System.err.println("Error sending commands to other instance."); - e.printStackTrace(); + Messages.loge("Error sending commands to other instance", e); } + Messages.log("Processing is not already running (or could not connect)"); return false; } } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 214080f2bb..e686dc1823 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -91,6 +91,8 @@ public class Sketch { /** Moved out of Editor and into here for cleaner access. */ private boolean untitled; + /** true if we've posted a "sketch disappeared" warning */ + private boolean disappearedWarning; /** * Used by the command-line version to create a sketch object. @@ -123,6 +125,7 @@ protected void load(String path) { int suffixLength = mode.getDefaultExtension().length() + 1; name = mainFilename.substring(0, mainFilename.length() - suffixLength); folder = new File(new File(path).getParent()); + disappearedWarning = false; load(); } @@ -227,6 +230,20 @@ public void reload() { } + /** + * Load a tab that the user added to the sketch or modified with an external + * editor. + */ + public void loadNewTab(String filename, String ext, boolean newAddition) { + if (newAddition) { + insertCode(new SketchCode(new File(folder, filename), ext)); + } else { + replaceCode(new SketchCode(new File(folder, filename), ext)); + } + sortCode(); + } + + protected void replaceCode(SketchCode newCode) { for (int i = 0; i < codeCount; i++) { if (code[i].getFileName().equals(newCode.getFileName())) { @@ -556,7 +573,7 @@ protected void nameCode(String newName) { code[i].setFolder(newFolder); } // Update internal state to reflect the new location - updateInternal(sanitaryName, newFolder); + updateInternal(sanitaryName, newFolder, renamingCode); // File newMainFile = new File(newFolder, newName + ".pde"); // String newMainFilePath = newMainFile.getAbsolutePath(); @@ -657,9 +674,10 @@ public void handleDeleteCode() { // get the changes into the sketchbook menu //sketchbook.rebuildMenus(); - // make a new sketch, and i think this will rebuild the sketch menu + // make a new sketch and rebuild the sketch menu //editor.handleNewUnchecked(); //editor.handleClose2(); + editor.getBase().rebuildSketchbookMenus(); editor.getBase().handleClose(editor, false); } else { @@ -685,7 +703,11 @@ public void handleDeleteCode() { } - protected void removeCode(SketchCode which) { + /** + * Remove a SketchCode from the list of files without deleting its file. + * @see #handleDeleteCode() + */ + public void removeCode(SketchCode which) { // remove it from the internal list of files // resort internal list of files for (int i = 0; i < codeCount; i++) { @@ -757,6 +779,16 @@ public boolean isModified() { } + /** + * Ensure that all SketchCodes are up-to-date, so that sc.save() works. + */ + public void updateSketchCodes() { +// if (current.isModified()) { + current.setProgram(editor.getText()); +// } + } + + /** * Save all code in the current sketch. This just forces the files to save * in place, so if it's an untitled (un-saved) sketch, saveAs() should be @@ -767,9 +799,7 @@ public boolean save() throws IOException { ensureExistence(); // first get the contents of the editor text area -// if (current.isModified()) { - current.setProgram(editor.getText()); -// } + updateSketchCodes(); // don't do anything if not actually modified //if (!modified) return false; @@ -911,9 +941,7 @@ public boolean saveAs() throws IOException { // grab the contents of the current tab before saving // first get the contents of the editor text area - if (current.isModified()) { - current.setProgram(editor.getText()); - } + updateSketchCodes(); File[] copyItems = folder.listFiles(new FileFilter() { public boolean accept(File file) { @@ -957,15 +985,17 @@ public boolean accept(File file) { // While the old path to the main .pde is still set, remove the entry from // the Recent menu so that it's not sticking around after the rename. // If untitled, it won't be in the menu, so there's no point. - if (!isUntitled()) { - Recent.remove(editor); - } +// if (!isUntitled()) { +// Recent.remove(editor); +// } + // Folks didn't like this behavior, so shutting it off + // https://github.com/processing/processing/issues/5902 // save the main tab with its new name File newFile = new File(newFolder, newName + "." + mode.getDefaultExtension()); code[0].saveAs(newFile); - updateInternal(newName, newFolder); + updateInternal(newName, newFolder, false); // Make sure that it's not an untitled sketch setUntitled(false); @@ -1163,7 +1193,8 @@ public void done() { /** * Update internal state for new sketch name or folder location. */ - protected void updateInternal(String sketchName, File sketchFolder) { + protected void updateInternal(String sketchName, File sketchFolder, + boolean renaming) { // reset all the state information for the sketch object String oldPath = getMainFilePath(); primaryFile = code[0].getFile(); @@ -1172,6 +1203,7 @@ protected void updateInternal(String sketchName, File sketchFolder) { name = sketchName; folder = sketchFolder; + disappearedWarning = false; codeFolder = new File(folder, "code"); dataFolder = new File(folder, "data"); @@ -1184,7 +1216,11 @@ protected void updateInternal(String sketchName, File sketchFolder) { // System.out.println("modified is now " + modified); editor.updateTitle(); editor.getBase().rebuildSketchbookMenus(); - Recent.rename(editor, oldPath); + if (renaming) { + // only update the Recent menu if it's a rename, not a Save As + // https://github.com/processing/processing/issues/5902 + Recent.rename(editor, oldPath); + } // editor.header.rebuild(); } @@ -1379,8 +1415,8 @@ public void setCurrentCode(int which) { // System.out.println(current.visited); // } // if current is null, then this is the first setCurrent(0) - if (((currentIndex == which) && (current != null)) - || which >= codeCount || which < 0) { + if (which < 0 || which >= codeCount || + ((currentIndex == which) && (current == code[currentIndex]))) { return; } @@ -1473,28 +1509,34 @@ public void prepareBuild(File targetFolder) throws SketchException { /** - * Make sure the sketch hasn't been moved or deleted by some - * nefarious user. If they did, try to re-create it and save. - * Only checks to see if the main folder is still around, - * but not its contents. + * Make sure the sketch hasn't been moved or deleted by a nefarious user. + * If they did, try to re-create it and save. Only checks whether the + * main folder is still around, but not its contents. */ public void ensureExistence() { if (!folder.exists()) { - // Disaster recovery, try to salvage what's there already. - Messages.showWarning(Language.text("ensure_exist.messages.missing_sketch"), - Language.text("ensure_exist.messages.missing_sketch.description")); - try { - folder.mkdirs(); - modified = true; + // Avoid an infinite loop if we've already warned about this + // https://github.com/processing/processing/issues/4805 + if (!disappearedWarning) { + disappearedWarning = true; + + // Disaster recovery, try to salvage what's there already. + Messages.showWarning(Language.text("ensure_exist.messages.missing_sketch"), + Language.text("ensure_exist.messages.missing_sketch.description")); + try { + folder.mkdirs(); + modified = true; + + for (int i = 0; i < codeCount; i++) { + code[i].save(); // this will force a save + } + calcModified(); - for (int i = 0; i < codeCount; i++) { - code[i].save(); // this will force a save + } catch (Exception e) { + // disappearedWarning prevents infinite loop in this scenario + Messages.showWarning(Language.text("ensure_exist.messages.unrecoverable"), + Language.text("ensure_exist.messages.unrecoverable.description"), e); } - calcModified(); - - } catch (Exception e) { - Messages.showWarning(Language.text("ensure_exist.messages.unrecoverable"), - Language.text("ensure_exist.messages.unrecoverable.description"), e); } } } diff --git a/app/src/processing/app/SketchCode.java b/app/src/processing/app/SketchCode.java index 1a52bfb9e7..59ed06652e 100644 --- a/app/src/processing/app/SketchCode.java +++ b/app/src/processing/app/SketchCode.java @@ -283,6 +283,12 @@ public long lastVisited() { public void load() throws IOException { program = Util.loadFile(file); + if (program == null) { + System.err.println("There was a problem loading " + file); + System.err.println("This may happen because you don't have permissions to read the file, or the file has gone missing."); + throw new IOException("Cannot read or access " + file); + } + // Remove NUL characters because they'll cause problems, // and their presence is very difficult to debug. // https://github.com/processing/processing/issues/1973 @@ -292,7 +298,7 @@ public void load() throws IOException { savedProgram = program; // This used to be the "Fix Encoding and Reload" warning, but since that - // tool has been removed, it just rambles about text editors and encodings. + // tool has been removed, let's ramble about text editors and encodings. if (program.indexOf('\uFFFD') != -1) { System.err.println(file.getName() + " contains unrecognized characters."); System.err.println("You should re-open " + file.getName() + diff --git a/app/src/processing/app/SketchException.java b/app/src/processing/app/SketchException.java index ccf8b924e6..4a32d2e79d 100644 --- a/app/src/processing/app/SketchException.java +++ b/app/src/processing/app/SketchException.java @@ -130,6 +130,11 @@ public void hideStackTrace() { } + public boolean isStackTraceEnabled() { + return showStackTrace; + } + + /** * Nix the java.lang crap out of an exception message * because it scares the children. diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java index fd43088ab9..5103f5d856 100644 --- a/app/src/processing/app/UpdateCheck.java +++ b/app/src/processing/app/UpdateCheck.java @@ -83,7 +83,12 @@ public void run() { } - public void updateCheck() throws IOException, InterruptedException { + /** + * Turned into a separate method so that anyone needed update.id will get + * a legit answer. Had a problem with the contribs script where the id + * wouldn't be set so a null id would be sent to the contribs server. + */ + static public long getUpdateID() { // generate a random id in case none exists yet Random r = new Random(); long id = r.nextLong(); @@ -94,8 +99,12 @@ public void updateCheck() throws IOException, InterruptedException { } else { Preferences.set("update.id", String.valueOf(id)); } + return id; + } - String info = PApplet.urlEncode(id + "\t" + + + public void updateCheck() throws IOException, InterruptedException { + String info = PApplet.urlEncode(getUpdateID() + "\t" + PApplet.nf(Base.getRevision(), 4) + "\t" + System.getProperty("java.version") + "\t" + System.getProperty("java.vendor") + "\t" + diff --git a/app/src/processing/app/Util.java b/app/src/processing/app/Util.java index 8016ba3113..fefc3b8b71 100644 --- a/app/src/processing/app/Util.java +++ b/app/src/processing/app/Util.java @@ -74,7 +74,7 @@ static public byte[] loadBytesRaw(File file) throws IOException { */ static public StringDict readSettings(File inputFile) { if (!inputFile.exists()) { - if (Base.DEBUG) System.err.println(inputFile + " does not exist."); + Messages.loge(inputFile + " does not exist inside readSettings()"); return null; } String lines[] = PApplet.loadStrings(inputFile); @@ -162,12 +162,11 @@ static public String loadFile(File file) throws IOException { * Spew the contents of a String object out to a file. As of 3.0 beta 2, * this will replace and write \r\n for newlines on Windows. * https://github.com/processing/processing/issues/3455 + * As of 3.3.7, this puts a newline at the end of the file, + * per good practice/POSIX: https://stackoverflow.com/a/729795 */ - static public void saveFile(String str, File file) throws IOException { - if (Platform.isWindows()) { - String[] lines = str.split("\\r?\\n"); - str = PApplet.join(lines, "\r\n"); - } + static public void saveFile(String text, File file) throws IOException { + String[] lines = text.split("\\r?\\n"); File temp = File.createTempFile(file.getName(), null, file.getParentFile()); try { // fix from cjwant to prevent symlinks from being destroyed. @@ -178,9 +177,11 @@ static public void saveFile(String str, File file) throws IOException { throw new IOException("Could not resolve canonical representation of " + file.getAbsolutePath()); } - // Can't use saveStrings() here b/c Windows will add a ^M to the file + // Could use saveStrings(), but the we wouldn't be able to checkError() PrintWriter writer = PApplet.createWriter(temp); - writer.print(str); + for (String line : lines) { + writer.println(line); + } boolean error = writer.checkError(); // calls flush() writer.close(); // attempt to close regardless if (error) { @@ -558,15 +559,14 @@ static private void packageListFromZip(String filename, StringList list) { if (!entry.isDirectory()) { String name = entry.getName(); - if (name.endsWith(".class")) { + // Avoid META-INF because some jokers but .class files in there + // https://github.com/processing/processing/issues/5778 + if (name.endsWith(".class") && !name.startsWith("META-INF/")) { int slash = name.lastIndexOf('/'); - if (slash == -1) continue; - - String pname = name.substring(0, slash); -// if (map.get(pname) == null) { -// map.put(pname, new Object()); -// } - list.appendUnique(pname); + if (slash != -1) { + String packageName = name.substring(0, slash); + list.appendUnique(packageName); + } } } } @@ -614,24 +614,31 @@ static private void packageListFromFolder(File dir, String sofar, } + /** + * Extract the contents of a .zip archive into a folder. + * Ignores (does not extract) any __MACOSX files from macOS archives. + */ static public void unzip(File zipFile, File dest) { try { FileInputStream fis = new FileInputStream(zipFile); CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32()); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum)); - ZipEntry next = null; - while ((next = zis.getNextEntry()) != null) { - File currentFile = new File(dest, next.getName()); - if (next.isDirectory()) { - currentFile.mkdirs(); - } else { - File parentDir = currentFile.getParentFile(); - // Sometimes the directory entries aren't already created - if (!parentDir.exists()) { - parentDir.mkdirs(); + ZipEntry entry = null; + while ((entry = zis.getNextEntry()) != null) { + final String name = entry.getName(); + if (!name.startsWith(("__MACOSX"))) { + File currentFile = new File(dest, name); + if (entry.isDirectory()) { + currentFile.mkdirs(); + } else { + File parentDir = currentFile.getParentFile(); + // Sometimes the directory entries aren't already created + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + currentFile.createNewFile(); + unzipEntry(zis, currentFile); } - currentFile.createNewFile(); - unzipEntry(zis, currentFile); } } } catch (Exception e) { diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java index 7d15eafb3d..4d5240c451 100644 --- a/app/src/processing/app/contrib/AvailableContribution.java +++ b/app/src/processing/app/contrib/AvailableContribution.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -49,9 +49,9 @@ public AvailableContribution(ContributionType type, StringDict params) { imports = parseImports(params); name = params.get("name"); authors = params.get("authors"); - if (authors == null) { - authors = params.get("authorList"); - } +// if (authors == null) { +// authors = params.get("authorList"); +// } url = params.get("url"); sentence = params.get("sentence"); paragraph = params.get("paragraph"); @@ -61,7 +61,7 @@ public AvailableContribution(ContributionType type, StringDict params) { version = PApplet.parseInt(versionStr, 0); } - prettyVersion = params.get("prettyVersion"); + setPrettyVersion(params.get("prettyVersion")); String lastUpdatedStr = params.get("lastUpdated"); if (lastUpdatedStr != null) { @@ -99,7 +99,6 @@ public LocalContribution install(Base base, File contribArchive, // Unzip the file into the modes, tools, or libraries folder inside the // sketchbook. Unzipping to /tmp is problematic because it may be on // another file system, so move/rename operations will break. -// File sketchbookContribFolder = type.getSketchbookFolder(); File tempFolder = null; try { @@ -110,84 +109,61 @@ public LocalContribution install(Base base, File contribArchive, return null; } Util.unzip(contribArchive, tempFolder); -// System.out.println("temp folder is " + tempFolder); -// Base.openFolder(tempFolder); // Now go looking for a legit contrib inside what's been unpacked. File contribFolder = null; - // Sometimes contrib authors place all their folders in the base directory - // of the .zip file instead of in single folder as the guidelines suggest. - if (type.isCandidate(tempFolder)) { - /* - // Can't just rename the temp folder, because a contrib with this name - // may already exist. Instead, create a new temp folder, and rename the - // old one to be the correct folder. - File enclosingFolder = null; - try { - enclosingFolder = Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder); - } catch (IOException e) { - status.setErrorMessage("Could not create a secondary folder to install."); - return null; - } - contribFolder = new File(enclosingFolder, getName()); - tempFolder.renameTo(contribFolder); - tempFolder = enclosingFolder; - */ + /* + if (!type.isCandidate(tempFolder)) { if (status != null) { status.setErrorMessage(Language.interpolate("contrib.errors.needs_repackage", getName(), type.getTitle())); } return null; } + */ -// if (contribFolder == null) { - // Find the first legitimate looking folder in what we just unzipped - contribFolder = type.findCandidate(tempFolder); -// } LocalContribution installedContrib = null; - + // Find the first legitimate folder in what we just unzipped + contribFolder = type.findCandidate(tempFolder); if (contribFolder == null) { if (status != null) { status.setErrorMessage(Language.interpolate("contrib.errors.no_contribution_found", type)); } - } else { File propFile = new File(contribFolder, type + ".properties"); - if (writePropertiesFile(propFile)) { - // 1. contribFolder now has a legit contribution, load it to get info. + if (!propFile.exists()) { + status.setErrorMessage("This contribution is missing " + + propFile.getName() + + ", please contact the author for a fix."); + + } else if (writePropertiesFile(propFile)) { + // contribFolder now has a legit contribution, load it to get info. LocalContribution newContrib = type.load(base, contribFolder); - // 1.1. get info we need to delete the newContrib folder later + // get info we need to delete the newContrib folder later File newContribFolder = newContrib.getFolder(); - // 2. Check to make sure nothing has the same name already, + // Check to make sure nothing has the same name already, // backup old if needed, then move things into place and reload. installedContrib = newContrib.copyAndLoad(base, confirmReplace, status); - // Restart no longer needed. Yay! -// if (newContrib != null && type.requiresRestart()) { -// installedContrib.setRestartFlag(); -// //status.setMessage("Restart Processing to finish the installation."); -// } - - // 3.1 Unlock all the jars if it is a mode or tool + // Unlock all the jars if it is a mode or tool if (newContrib.getType() == ContributionType.MODE) { ((ModeContribution) newContrib).clearClassLoader(base); - } - else if (newContrib.getType() == ContributionType.TOOL) { + + } else if (newContrib.getType() == ContributionType.TOOL) { ((ToolContribution) newContrib).clearClassLoader(); } - // 3.2 Delete the newContrib, do a garbage collection, hope and pray + // Delete the newContrib, do a garbage collection, hope and pray // that Java will unlock the temp folder on Windows now newContrib = null; System.gc(); - if (Platform.isWindows()) { - // we'll even give it a second to finish up ... because file ops are - // just that flaky on Windows. + // we'll even give it a second to finish up, + // because file ops are just that flaky on Windows. try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -195,7 +171,7 @@ else if (newContrib.getType() == ContributionType.TOOL) { } } - // 4. Okay, now actually delete that temp folder + // delete the contrib folder inside the libraryXXXXXXtmp folder Util.removeDir(newContribFolder, false); } else { @@ -231,9 +207,6 @@ public ContributionType getType() { * manager. However, it also ensures that valid fields in the properties file * aren't overwritten, since the properties file may be more recent than the * contributions.txt file. - * - * @param propFile - * @return */ public boolean writePropertiesFile(File propFile) { try { @@ -256,9 +229,9 @@ public boolean writePropertiesFile(File propFile) { StringList importsList = parseImports(properties); String authors = properties.get(AUTHORS_PROPERTY); - if (authors == null) { - authors = properties.get("authorList"); // before 3.0a11 - } +// if (authors == null) { +// authors = properties.get("authorList"); // before 3.0a11 +// } if (authors == null || authors.isEmpty()) { authors = getAuthorList(); } @@ -283,13 +256,14 @@ public boolean writePropertiesFile(File propFile) { version = Integer.parseInt(properties.get("version")); } catch (NumberFormatException e) { version = getVersion(); - System.err.println("The version number for “" + name + "” is not set properly."); + System.err.println("The version number for “" + name + "” is not a number."); System.err.println("Please contact the author to fix it according to the guidelines."); } String prettyVersion = properties.get("prettyVersion"); - if (prettyVersion == null || prettyVersion.isEmpty()) - prettyVersion = getPrettyVersion(); + if (prettyVersion != null && prettyVersion.isEmpty()) { + prettyVersion = null; + } String compatibleContribsList = null; if (getType() == ContributionType.EXAMPLES) { @@ -336,7 +310,9 @@ public boolean writePropertiesFile(File propFile) { writer.println("sentence=" + sentence); writer.println("paragraph=" + paragraph); writer.println("version=" + version); - writer.println("prettyVersion=" + prettyVersion); + if (prettyVersion != null) { + writer.println("prettyVersion=" + prettyVersion); + } writer.println("lastUpdated=" + lastUpdated); writer.println("minRevision=" + minRev); writer.println("maxRevision=" + maxRev); diff --git a/app/src/processing/app/contrib/ContribProgressBar.java b/app/src/processing/app/contrib/ContribProgressBar.java index c86cb16ae4..8a0d41c3b6 100644 --- a/app/src/processing/app/contrib/ContribProgressBar.java +++ b/app/src/processing/app/contrib/ContribProgressBar.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java index 4b01c106e1..aa401375e6 100644 --- a/app/src/processing/app/contrib/Contribution.java +++ b/app/src/processing/app/contrib/Contribution.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-16 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -158,21 +158,41 @@ public int getVersion() { } - // "1.0.2" + public void setPrettyVersion(String pretty) { + if (pretty != null) { + // some entries were written as "null", causing that to show in the ui + if (pretty.equals("null") || pretty.length() == 0) { + pretty = null; + } + } + prettyVersion = pretty; + } + + + // "1.0.2" or null if not present public String getPrettyVersion() { return prettyVersion; } + + // returns prettyVersion, or "" if null + public String getBenignVersion() { + return (prettyVersion != null) ? prettyVersion : ""; + } + + // 1402805757 public long getLastUpdated() { return lastUpdated; } + // 0 public int getMinRevision() { return minRevision; } + // 227 public int getMaxRevision() { return maxRevision; @@ -347,6 +367,27 @@ static private String translateCategory(String cat) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o instanceof Contribution) { + Contribution that = (Contribution) o; + return name.toLowerCase().equals(that.name.toLowerCase()); + } + return false; + } + + + @Override + public int hashCode() { + return name.toLowerCase().hashCode(); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + public interface Filter { boolean matches(Contribution contrib); } diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index cf35ff628c..6f35ca3fd7 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-16 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -51,23 +51,25 @@ public class ContributionListing { List advertisedContributions; Map> librariesByCategory; Map librariesByImportHeader; - List allContributions; + // TODO: Every contribution is getting added twice + // and nothing is replaced ever. + Set allContributions; boolean listDownloaded; boolean listDownloadFailed; ReentrantLock downloadingListingLock; private ContributionListing() { - listeners = new ArrayList(); - advertisedContributions = new ArrayList(); - librariesByCategory = new HashMap>(); - librariesByImportHeader = new HashMap(); - allContributions = new ArrayList(); + listeners = new ArrayList<>(); + advertisedContributions = new ArrayList<>(); + librariesByCategory = new HashMap<>(); + librariesByImportHeader = new HashMap<>(); + allContributions = new LinkedHashSet<>(); downloadingListingLock = new ReentrantLock(); //listingFile = Base.getSettingsFile("contributions.txt"); listingFile = Base.getSettingsFile(LOCAL_FILENAME); - listingFile.setWritable(true); + listingFile.setWritable(true, false); if (listingFile.exists()) { setAdvertisedList(listingFile); } @@ -94,7 +96,6 @@ private void setAdvertisedList(File file) { for (Contribution contribution : advertisedContributions) { addContribution(contribution); } - Collections.sort(allContributions, COMPARATOR); } @@ -137,11 +138,8 @@ protected void replaceContribution(Contribution oldLib, Contribution newLib) { } } - for (int i = 0; i < allContributions.size(); i++) { - if (allContributions.get(i) == oldLib) { - allContributions.set(i, newLib); - } - } + allContributions.remove(oldLib); + allContributions.add(newLib); notifyChange(oldLib, newLib); } @@ -161,13 +159,12 @@ private void addContribution(Contribution contribution) { Collections.sort(list, COMPARATOR); } else { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); list.add(contribution); librariesByCategory.put(category, list); } allContributions.add(contribution); notifyAdd(contribution); - Collections.sort(allContributions, COMPARATOR); } } @@ -213,7 +210,7 @@ protected AvailableContribution getAvailableContribution(Contribution info) { protected Set getCategories(Contribution.Filter filter) { - Set outgoing = new HashSet(); + Set outgoing = new HashSet<>(); Set categorySet = librariesByCategory.keySet(); for (String categoryName : categorySet) { @@ -232,43 +229,7 @@ protected Set getCategories(Contribution.Filter filter) { } -// public List getAllContributions() { -// return new ArrayList(allContributions); -// } - - -// public List getLibararies(String category) { -// ArrayList libinfos = -// new ArrayList(librariesByCategory.get(category)); -// Collections.sort(libinfos, nameComparator); -// return libinfos; -// } - - - protected List getFilteredLibraryList(String category, List filters) { - ArrayList filteredList = - new ArrayList(allContributions); - - Iterator it = filteredList.iterator(); - while (it.hasNext()) { - Contribution libInfo = it.next(); - //if (category != null && !category.equals(libInfo.getCategory())) { - if (category != null && !libInfo.hasCategory(category)) { - it.remove(); - } else { - for (String filter : filters) { - if (!matches(libInfo, filter)) { - it.remove(); - break; - } - } - } - } - return filteredList; - } - - - private boolean matches(Contribution contrib, String typed) { + public boolean matches(Contribution contrib, String typed) { int colon = typed.indexOf(":"); if (colon != -1) { String isText = typed.substring(0, colon); @@ -420,7 +381,7 @@ public void run() { // System.out.println(contribInfo.length() + " " + contribInfo); File tempContribFile = Base.getSettingsFile("contribs.tmp"); - tempContribFile.setWritable(true); + tempContribFile.setWritable(true, false); ContributionManager.download(url, base.getInstalledContribsInfo(), tempContribFile, progress); if (!progress.isCanceled() && !progress.isError()) { @@ -465,28 +426,6 @@ public void run() { } - /* - boolean hasUpdates(Base base) { - for (ModeContribution mc : base.getModeContribs()) { - if (hasUpdates(mc)) { - return true; - } - } - for (Library lib : base.getActiveEditor().getMode().contribLibraries) { - if (hasUpdates(lib)) { - return true; - } - } - for (ToolContribution tc : base.getToolContribs()) { - if (hasUpdates(tc)) { - return true; - } - } - return false; - } - */ - - protected boolean hasUpdates(Contribution contribution) { if (contribution.isInstalled()) { Contribution advertised = getAvailableContribution(contribution); @@ -500,7 +439,7 @@ protected boolean hasUpdates(Contribution contribution) { } - protected String getLatestVersion(Contribution contribution) { + protected String getLatestPrettyVersion(Contribution contribution) { Contribution newestContrib = getAvailableContribution(contribution); if (newestContrib == null) { return null; @@ -509,7 +448,6 @@ protected String getLatestVersion(Contribution contribution) { } - protected boolean hasDownloadedLatestList() { return listDownloaded; } @@ -522,7 +460,7 @@ protected boolean hasListDownloadFailed() { private List parseContribList(File file) { List outgoing = - new ArrayList(); + new ArrayList<>(); if (file != null && file.exists()) { String[] lines = PApplet.loadStrings(file); @@ -580,6 +518,11 @@ public int countUpdates(Base base) { count++; } } + for (Library lib : base.getActiveEditor().getMode().coreLibraries) { + if (hasUpdates(lib)) { + count++; + } + } for (ToolContribution tc : base.getToolContribs()) { if (hasUpdates(tc)) { count++; @@ -600,11 +543,7 @@ public Map getLibrariesByImportHeader() { } - static public Comparator COMPARATOR = new Comparator() { - public int compare(Contribution o1, Contribution o2) { - return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); - } - }; + static public Comparator COMPARATOR = Comparator.comparing(o -> o.getName().toLowerCase()); public interface ChangeListener { diff --git a/app/src/processing/app/contrib/ContributionManager.java b/app/src/processing/app/contrib/ContributionManager.java index 4a6bbf4d96..af9c4d8995 100644 --- a/app/src/processing/app/contrib/ContributionManager.java +++ b/app/src/processing/app/contrib/ContributionManager.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -39,7 +39,7 @@ public class ContributionManager { - static final ContributionListing listing = ContributionListing.getInstance(); + static ContributionListing listing; /** @@ -61,6 +61,7 @@ static boolean download(URL source, byte[] post, boolean success = false; try { HttpURLConnection conn = (HttpURLConnection) source.openConnection(); + // Will not handle a protocol change (see below) HttpURLConnection.setFollowRedirects(true); conn.setConnectTimeout(15 * 1000); conn.setReadTimeout(60 * 1000); @@ -89,27 +90,37 @@ static boolean download(URL source, byte[] post, progress.startTask(Language.text("contrib.progress.downloading"), fileSize); } - InputStream in = conn.getInputStream(); - FileOutputStream out = new FileOutputStream(dest); + int response = conn.getResponseCode(); + // Default won't follow HTTP -> HTTPS redirects for security reasons + // http://stackoverflow.com/a/1884427 + if (response >= 300 && response < 400) { + // Handle SSL redirects from HTTP sources + // https://github.com/processing/processing/issues/5554 + String newLocation = conn.getHeaderField("Location"); + return download(new URL(newLocation), post, dest, progress); - byte[] b = new byte[8192]; - int amount; - if (progress != null) { - int total = 0; - while (!progress.isCanceled() && (amount = in.read(b)) != -1) { - out.write(b, 0, amount); - total += amount; - progress.setProgress(total); - } } else { - while ((amount = in.read(b)) != -1) { - out.write(b, 0, amount); + InputStream in = conn.getInputStream(); + FileOutputStream out = new FileOutputStream(dest); + + byte[] b = new byte[8192]; + int amount; + if (progress != null) { + int total = 0; + while (!progress.isCanceled() && (amount = in.read(b)) != -1) { + out.write(b, 0, amount); + total += amount; + progress.setProgress(total); + } + } else { + while ((amount = in.read(b)) != -1) { + out.write(b, 0, amount); + } } + out.flush(); + out.close(); + success = true; } - out.flush(); - out.close(); - success = true; - } catch (SocketTimeoutException ste) { if (progress != null) { progress.error(ste); @@ -120,8 +131,6 @@ static boolean download(URL source, byte[] post, progress.error(ioe); progress.cancel(); } - // Hiding stack trace. An error has been shown where needed. -// ioe.printStackTrace(); } if (progress != null) { progress.finished(); @@ -190,8 +199,8 @@ public void run() { } } installProgress.finished(); - } - else { + + } else { if (downloadProgress.exception instanceof SocketTimeoutException) { status.setErrorMessage(Language .interpolate("contrib.errors.contrib_download.timeout", @@ -204,7 +213,6 @@ public void run() { } contribZip.delete(); - //} catch (NoClassDefFoundError ncdfe) { } catch (Exception e) { String msg = null; if (e instanceof RuntimeException) { @@ -220,6 +228,8 @@ public void run() { if (msg == null) { msg = Language.interpolate("contrib.errors.download_and_install", ad.getName()); + // Something unexpected, so print the trace + e.printStackTrace(); } status.setErrorMessage(msg); downloadProgress.cancel(); @@ -361,7 +371,7 @@ static public void downloadAndInstallOnImport(final Base base, editor.getTextArea().setEditable(false); // base.getActiveEditor().getConsole().clear(); - List installedLibList = new ArrayList(); + List installedLibList = new ArrayList<>(); // boolean variable to check if previous lib was installed successfully, // to give the user an idea about progress being made. @@ -543,6 +553,8 @@ static private void cleanup(final Base base) throws Exception { @Override protected Void doInBackground() throws Exception { try { + // TODO: pls explain the sleep and why this runs on a worker thread, + // but a couple of lines above on EDT [jv] Thread.sleep(1000); installPreviouslyFailed(base, Base.getSketchbookToolsFolder()); } catch (InterruptedException e) { @@ -588,8 +600,10 @@ public boolean accept(File folder) { LocalContribution.isDeletionFlagged(folder)); } }); - for (File folder : markedForDeletion) { - Util.removeDir(folder); + if (markedForDeletion != null) { + for (File folder : markedForDeletion) { + Util.removeDir(folder); + } } } @@ -605,14 +619,21 @@ public boolean accept(File folder) { } }); - for (File file : installList) { - for (AvailableContribution contrib : listing.advertisedContributions) { - if (file.getName().equals(contrib.getName())) { - file.delete(); - installOnStartUp(base, contrib); - listing.replaceContribution(contrib, contrib); + // https://github.com/processing/processing/issues/5823 + if (installList != null) { + for (File file : installList) { + for (AvailableContribution contrib : listing.advertisedContributions) { + if (file.getName().equals(contrib.getName())) { + file.delete(); + installOnStartUp(base, contrib); + EventQueue.invokeAndWait(() -> { + listing.replaceContribution(contrib, contrib); + }); + } } } + } else { + System.err.println("Could not read " + root); } } @@ -628,8 +649,14 @@ public boolean accept(File folder) { } }); - ArrayList updateContribsNames = new ArrayList(); - LinkedList updateContribsList = new LinkedList(); + List updateContribsNames = new ArrayList<>(); + List updateContribsList = new LinkedList<>(); + + // TODO This is bad code... This root.getName() stuff to get the folder + // type, plus "libraries.properties" (not the correct file name), + // and I have no idea what "putting this here, in just in case" means. + // Not sure the function here so I'm not fixing it at the moment, + // but this whole function could use some cleaning. [fry 180105] String type = root.getName().substring(root.getName().lastIndexOf('/') + 1); String propFileName = null; @@ -700,6 +727,7 @@ public boolean accept(File folder) { static public void init(Base base) throws Exception { + listing = ContributionListing.getInstance(); // Moved here to make sure it runs on EDT [jv 170121] managerDialog = new ManagerFrame(base); cleanup(base); } diff --git a/app/src/processing/app/contrib/ContributionTab.java b/app/src/processing/app/contrib/ContributionTab.java index 1a0ab72a1e..9028e0644d 100644 --- a/app/src/processing/app/contrib/ContributionTab.java +++ b/app/src/processing/app/contrib/ContributionTab.java @@ -23,14 +23,13 @@ package processing.app.contrib; import java.awt.Color; +import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Font; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; -import javax.swing.text.*; import processing.app.*; import processing.app.ui.Editor; @@ -39,7 +38,7 @@ public class ContributionTab extends JPanel { static final String ANY_CATEGORY = Language.text("contrib.all"); - static final int FILTER_WIDTH = 180; + static final int FILTER_WIDTH = Toolkit.zoom(180); ContributionType contribType; ManagerFrame contribDialog; @@ -74,36 +73,14 @@ public ContributionTab(ManagerFrame dialog, ContributionType type) { this.contribDialog = dialog; this.contribType = type; - /* - if (type == ContributionType.MODE) { - title = Language.text("contrib.manager_title.mode"); - } else if (type == ContributionType.TOOL) { - title = Language.text("contrib.manager_title.tool"); - } else if (type == ContributionType.LIBRARY) { - title = Language.text("contrib.manager_title.library"); - } else if (type == ContributionType.EXAMPLES) { - title = Language.text("contrib.manager_title.examples"); - } - */ - - filter = new Contribution.Filter() { - public boolean matches(Contribution contrib) { - return contrib.getType() == contribType; - } - }; + filter = contrib -> contrib.getType() == contribType; contribListing = ContributionListing.getInstance(); statusPanel = new StatusPanel(this, 650); - contributionListPanel = new ListPanel(this, filter); + contributionListPanel = new ListPanel(this, filter, false); contribListing.addListener(contributionListPanel); } - -// public boolean hasUpdates(Base base) { -// return contribListing.hasUpdates(base); -// } - - public void showFrame(final Editor editor, boolean error, boolean loading) { this.editor = editor; @@ -184,7 +161,7 @@ private void createComponents() { categoryChooser = new JComboBox(); categoryChooser.setMaximumRowCount(20); - categoryChooser.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + categoryChooser.setFont(ManagerFrame.NORMAL_PLAIN); updateCategoryChooser(); @@ -212,23 +189,26 @@ protected void buildErrorPanel() { layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); errorPanel.setLayout(layout); -// errorPanel.setBorder(BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK)); errorMessage = new JTextPane(); errorMessage.setEditable(false); errorMessage.setContentType("text/html"); - errorMessage.setText("Could not connect to the Processing server.
" + errorMessage.setText("
Could not connect to the Processing server.
" + "Contributions cannot be installed or updated without an Internet connection.
" - + "Please verify your network connection again, then try connecting again."); - errorMessage.setFont(Toolkit.getSansFont(14, Font.PLAIN)); - errorMessage.setMaximumSize(new Dimension(550, 50)); + + "Please verify your network connection again, then try connecting again.
"); + DetailPanel.setTextStyle(errorMessage, "1em"); + Dimension dim = new Dimension(550, 60); + errorMessage.setMaximumSize(dim); + errorMessage.setMinimumSize(dim); errorMessage.setOpaque(false); + /* StyledDocument doc = errorMessage.getStyledDocument(); SimpleAttributeSet center = new SimpleAttributeSet(); StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); doc.setParagraphAttributes(0, doc.getLength(), center, false); + */ - closeButton = new JButton(Toolkit.getLibIconX("manager/close")); + closeButton = Toolkit.createIconButton("manager/close"); closeButton.setContentAreaFilled(false); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -236,7 +216,7 @@ public void actionPerformed(ActionEvent e) { } }); tryAgainButton = new JButton("Try Again"); - tryAgainButton.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + tryAgainButton.setFont(ManagerFrame.NORMAL_PLAIN); tryAgainButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { contribDialog.makeAndShowTab(false, true); @@ -287,9 +267,7 @@ protected void updateCategoryChooser() { protected void filterLibraries(String category, List filters) { - List filteredLibraries = - contribListing.getFilteredLibraryList(category, filters); - contributionListPanel.filterLibraries(filteredLibraries); + contributionListPanel.filterLibraries(category, filters); } @@ -352,62 +330,79 @@ protected void setFilterText(String filter) { } - //TODO: this is causing a lot of bugs as the hint is wrongly firing applyFilter() class FilterField extends JTextField { - Icon searchIcon; List filters; - JLabel filterLabel; public FilterField () { super(""); - filterLabel = new JLabel("Filter"); - filterLabel.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + JLabel filterLabel = new JLabel("Filter"); + filterLabel.setFont(ManagerFrame.NORMAL_PLAIN); filterLabel.setOpaque(false); - setFont(Toolkit.getSansFont(14, Font.PLAIN)); - searchIcon = Toolkit.getLibIconX("manager/search"); - filterLabel.setIcon(searchIcon); + setFont(ManagerFrame.NORMAL_PLAIN); + filterLabel.setIcon(Toolkit.getLibIconX("manager/search")); + JButton removeFilter = Toolkit.createIconButton("manager/remove"); + removeFilter.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); + removeFilter.setBorderPainted(false); + removeFilter.setContentAreaFilled(false); + removeFilter.setCursor(Cursor.getDefaultCursor()); + removeFilter.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setText(""); + filterField.requestFocusInWindow(); + } + }); //searchIcon = new ImageIcon(java.awt.Toolkit.getDefaultToolkit().getImage("NSImage://NSComputerTemplate")); setOpaque(false); - //setBorder(BorderFactory.createMatteBorder(0, 33, 0, 0, searchIcon)); GroupLayout fl = new GroupLayout(this); setLayout(fl); - fl.setHorizontalGroup(fl.createSequentialGroup().addComponent(filterLabel)); + fl.setHorizontalGroup(fl + .createSequentialGroup() + .addComponent(filterLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, + GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) + .addComponent(removeFilter)); + fl.setVerticalGroup(fl.createSequentialGroup() .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) + .addGroup(fl.createParallelGroup() .addComponent(filterLabel) + .addComponent(removeFilter)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)); + removeFilter.setVisible(false); filters = new ArrayList(); addFocusListener(new FocusListener() { public void focusLost(FocusEvent focusEvent) { if (getText().isEmpty()) { -// setBorder(BorderFactory.createMatteBorder(0, 33, 0, 0, searchIcon)); filterLabel.setVisible(true); } } public void focusGained(FocusEvent focusEvent) { -// setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0)); filterLabel.setVisible(false); } }); getDocument().addDocumentListener(new DocumentListener() { public void removeUpdate(DocumentEvent e) { + removeFilter.setVisible(!getText().isEmpty()); applyFilter(); } public void insertUpdate(DocumentEvent e) { + removeFilter.setVisible(!getText().isEmpty()); applyFilter(); } public void changedUpdate(DocumentEvent e) { + removeFilter.setVisible(!getText().isEmpty()); applyFilter(); } }); @@ -442,15 +437,16 @@ protected void updateAll() { contributionListPanel.panelByContribution.values(); for (DetailPanel detailPanel : collection) { detailPanel.update(); - - // Refreshing the ContributionUpdateTab's status icons - contributionListPanel.updatePanelOrdering(contributionListPanel - .panelByContribution.keySet()); } + contributionListPanel.model.fireTableDataChanged(); } protected boolean hasUpdates() { return contributionListPanel.getRowCount() > 0; } + + public boolean filterHasFocus() { + return filterField != null && filterField.hasFocus(); + } } diff --git a/app/src/processing/app/contrib/ContributionType.java b/app/src/processing/app/contrib/ContributionType.java index 197aaa4f5c..2ea1dd2d78 100644 --- a/app/src/processing/app/contrib/ContributionType.java +++ b/app/src/processing/app/contrib/ContributionType.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -172,7 +172,7 @@ public File getSketchbookFolder() { } - boolean isCandidate(File potential) { + public boolean isCandidate(File potential) { return (potential.isDirectory() && new File(potential, toString()).exists() && !isTempFolderName(potential.getName())); @@ -237,7 +237,7 @@ LocalContribution load(Base base, File folder) { ArrayList listContributions(Editor editor) { - ArrayList contribs = new ArrayList(); + ArrayList contribs = new ArrayList<>(); switch (this) { case LIBRARY: contribs.addAll(editor.getMode().contribLibraries); diff --git a/app/src/processing/app/contrib/DetailPanel.java b/app/src/processing/app/contrib/DetailPanel.java index 4cf327165d..e36978e114 100644 --- a/app/src/processing/app/contrib/DetailPanel.java +++ b/app/src/processing/app/contrib/DetailPanel.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-16 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -48,16 +48,6 @@ import processing.app.ui.Toolkit; -// TODO clean up accessors (too many cases of several de-references for basic tasks -// TODO hyperlink listener seems far too complicated for what it does, -// and why have a 'null' version rather than detecting whether selected or not -// TODO don't add/remove listeners for install/remove/undo based on function, -// just keep track of current behavior and call that. too many things can go wrong. -// TODO get rid of huge actionPerformed() blocks with anonymous classes, -// just make handleInstall(), etc methods and a single actionPerformed -// for the button that calls the necessary behavior (see prev note) -// TODO switch to the built-in fonts (available from Toolkit) rather than verdana et al - /** * Panel that expands and gives a brief overview of a library when clicked. */ @@ -81,7 +71,7 @@ class DetailPanel extends JPanel { private final ListPanel listPanel; private final ContributionListing contribListing = ContributionListing.getInstance(); - static final int BUTTON_WIDTH = 100; + static final int BUTTON_WIDTH = Toolkit.zoom(100); static Icon foundationIcon; /** @@ -94,9 +84,13 @@ public Contribution getContrib() { return contrib; } + private LocalContribution getLocalContrib() { + return (LocalContribution) contrib; + } + private boolean alreadySelected; private boolean enableHyperlinks; - private HyperlinkListener conditionalHyperlinkOpener; + //private HyperlinkListener conditionalHyperlinkOpener; private JTextPane descriptionPane; private JLabel notificationLabel; private JButton updateButton; @@ -104,11 +98,13 @@ public Contribution getContrib() { private JButton installRemoveButton; private JPopupMenu contextMenu; private JMenuItem openFolder; + private JPanel barButtonCardPane; + private CardLayout barButtonCardLayout; - private ActionListener removeActionListener; - private ActionListener installActionListener; - private ActionListener undoActionListener; + static private final String installText = Language.text("contrib.install"); + static private final String removeText = Language.text("contrib.remove"); + static private final String undoText = Language.text("contrib.undo"); boolean updateInProgress; boolean installInProgress; @@ -125,57 +121,6 @@ public Contribution getContrib() { listPanel = contributionListPanel; barButtonCardPane = new JPanel(); - enableHyperlinks = false; - alreadySelected = false; - conditionalHyperlinkOpener = new HyperlinkListener() { - public void hyperlinkUpdate(HyperlinkEvent e) { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - if (enableHyperlinks) { - if (e.getURL() != null) { - Platform.openURL(e.getURL().toString()); - } - } - } - } - }; - - installActionListener = new ActionListener() { - public void actionPerformed(ActionEvent e) { - install(); - } - }; - - undoActionListener = new ActionListener() { - public void actionPerformed(ActionEvent e) { - listPanel.contributionTab.statusPanel.clearMessage(); - if (contrib instanceof LocalContribution) { - LocalContribution installed = (LocalContribution) contrib; - installed.setDeletionFlag(false); - contribListing.replaceContribution(contrib, contrib); // ?? - Iterator contribsListIter = contribListing.allContributions.iterator(); - boolean toBeRestarted = false; - while (contribsListIter.hasNext()) { - Contribution contribElement = contribsListIter.next(); - if (contrib.getType().equals(contribElement.getType())) { - if (contribElement.isDeletionFlagged() || - contribElement.isUpdateFlagged()) { - toBeRestarted = !toBeRestarted; - break; - } - } - } - // TODO: remove or uncomment if the button was added - //listPanel.contributionTab.restartButton.setVisible(toBeRestarted); - } - } - }; - - removeActionListener = new ActionListener() { - public void actionPerformed(ActionEvent arg) { - remove(); - } - }; - contextMenu = new JPopupMenu(); openFolder = new JMenuItem("Open Folder"); openFolder.addActionListener(new ActionListener() { @@ -200,9 +145,8 @@ public void mousePressed(MouseEvent e) { if (contrib.isCompatible(Base.getRevision())) { listPanel.setSelectedPanel(DetailPanel.this); } else { - final String msg = contrib.getName() - + " is not compatible with this version of Processing"; - listPanel.contributionTab.statusPanel.setErrorMessage(msg); + setErrorMessage(contrib.getName() + + " cannot be used with this version of Processing"); } } }); @@ -223,31 +167,38 @@ private void addPaneComponents() { margin.bottom = 0; descriptionPane.setMargin(margin); descriptionPane.setContentType("text/html"); - setTextStyle(descriptionPane); + setTextStyle(descriptionPane, "0.95em"); descriptionPane.setOpaque(false); if (UIManager.getLookAndFeel().getID().equals("Nimbus")) { descriptionPane.setBackground(new Color(0, 0, 0, 0)); } -// stripTextSelectionListeners(descriptionBlock); descriptionPane.setBorder(new EmptyBorder(4, 7, 7, 7)); descriptionPane.setHighlighter(null); + descriptionPane.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + // for 3.2.3, added the isSelected() prompt here, rather than + // adding/removing the listener repeatedly + if (isSelected()) { + if (enableHyperlinks && e.getURL() != null) { + Platform.openURL(e.getURL().toString()); + } + } + } + } + }); + add(descriptionPane, BorderLayout.CENTER); - JPanel updateBox = new JPanel(); //new BoxLayout(filterPanel, BoxLayout.X_AXIS) + JPanel updateBox = new JPanel(); updateBox.setLayout(new BorderLayout()); notificationLabel = new JLabel(); notificationLabel.setInheritsPopupMenu(true); notificationLabel.setVisible(false); notificationLabel.setOpaque(false); - // not needed after changing to JLabel -// notificationBlock.setContentType("text/html"); -// notificationBlock.setHighlighter(null); -// setTextStyle(notificationBlock); -// notificationLabel.setFont(new Font("Verdana", Font.ITALIC, 10)); - notificationLabel.setFont(Toolkit.getSansFont(12, Font.PLAIN)); -// stripTextSelectionListeners(notificationBlock); + notificationLabel.setFont(ManagerFrame.SMALL_PLAIN); { updateButton = new JButton("Update"); @@ -276,13 +227,14 @@ public void actionPerformed(ActionEvent e) { rightPane.setInheritsPopupMenu(true); rightPane.setOpaque(false); rightPane.setLayout(new BoxLayout(rightPane, BoxLayout.Y_AXIS)); - rightPane.setMinimumSize(new Dimension(DetailPanel.BUTTON_WIDTH, 1)); + rightPane.setMinimumSize(new Dimension(BUTTON_WIDTH, 1)); add(rightPane, BorderLayout.EAST); - barButtonCardPane.setLayout(new CardLayout()); + barButtonCardLayout = new CardLayout(); + barButtonCardPane.setLayout(barButtonCardLayout); barButtonCardPane.setInheritsPopupMenu(true); barButtonCardPane.setOpaque(false); - barButtonCardPane.setMinimumSize(new Dimension(DetailPanel.BUTTON_WIDTH, 1)); + barButtonCardPane.setMinimumSize(new Dimension(BUTTON_WIDTH, 1)); { installProgressBar = new JProgressBar(); @@ -290,7 +242,7 @@ public void actionPerformed(ActionEvent e) { installProgressBar.setStringPainted(true); resetInstallProgressBarState(); Dimension dim = - new Dimension(DetailPanel.BUTTON_WIDTH, + new Dimension(BUTTON_WIDTH, installProgressBar.getPreferredSize().height); installProgressBar.setPreferredSize(dim); installProgressBar.setMaximumSize(dim); @@ -301,9 +253,21 @@ public void actionPerformed(ActionEvent e) { installRemoveButton = new JButton(" "); installRemoveButton.setInheritsPopupMenu(true); + installRemoveButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + String mode = installRemoveButton.getText(); + if (mode.equals(installText)) { + install(); + } else if (mode.equals(removeText)) { + remove(); + } else if (mode.equals(undoText)) { + undo(); + } + } + }); Dimension installButtonDimensions = installRemoveButton.getPreferredSize(); - installButtonDimensions.width = DetailPanel.BUTTON_WIDTH; + installButtonDimensions.width = BUTTON_WIDTH; installRemoveButton.setPreferredSize(installButtonDimensions); installRemoveButton.setMaximumSize(installButtonDimensions); installRemoveButton.setMinimumSize(installButtonDimensions); @@ -312,7 +276,6 @@ public void actionPerformed(ActionEvent e) { JPanel barPane = new JPanel(); barPane.setOpaque(false); -// barPane.add(installProgressBar); JPanel buttonPane = new JPanel(); buttonPane.setOpaque(false); @@ -320,15 +283,14 @@ public void actionPerformed(ActionEvent e) { barButtonCardPane.add(buttonPane, BUTTON_CONSTRAINT); barButtonCardPane.add(barPane, PROGRESS_BAR_CONSTRAINT); - - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, BUTTON_CONSTRAINT); + barButtonCardLayout.show(barButtonCardPane, BUTTON_CONSTRAINT); rightPane.add(barButtonCardPane); // Set the minimum size of this pane to be the sum of the height of the // progress bar and install button Dimension dim = - new Dimension(DetailPanel.BUTTON_WIDTH, + new Dimension(BUTTON_WIDTH, installRemoveButton.getPreferredSize().height); rightPane.setMinimumSize(dim); rightPane.setPreferredSize(dim); @@ -352,10 +314,9 @@ private void reorganizePaneComponents() { rightPane.setInheritsPopupMenu(true); rightPane.setOpaque(false); rightPane.setLayout(new BoxLayout(rightPane, BoxLayout.Y_AXIS)); - rightPane.setMinimumSize(new Dimension(DetailPanel.BUTTON_WIDTH, 1)); + rightPane.setMinimumSize(new Dimension(BUTTON_WIDTH, 1)); add(rightPane, BorderLayout.EAST); - if (updateButton.isVisible() && !removeInProgress && !contrib.isDeletionFlagged()) { JPanel updateRemovePanel = new JPanel(); updateRemovePanel.setLayout(new FlowLayout()); @@ -368,21 +329,18 @@ private void reorganizePaneComponents() { JPanel barPane = new JPanel(); barPane.setOpaque(false); barPane.setInheritsPopupMenu(true); -// barPane.add(installProgressBar); rightPane.add(barPane); - if (updateInProgress) - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); - - } - else { + if (updateInProgress) { + barButtonCardLayout.show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); + } + } else { updateBox.add(updateButton, BorderLayout.EAST); barButtonCardPane.removeAll(); JPanel barPane = new JPanel(); barPane.setOpaque(false); barPane.setInheritsPopupMenu(true); -// barPane.add(installProgressBar); JPanel buttonPane = new JPanel(); buttonPane.setOpaque(false); @@ -391,34 +349,33 @@ private void reorganizePaneComponents() { barButtonCardPane.add(buttonPane, BUTTON_CONSTRAINT); barButtonCardPane.add(barPane, PROGRESS_BAR_CONSTRAINT); - if (installInProgress || removeInProgress || updateInProgress) - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); - else - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, BUTTON_CONSTRAINT); - + if (installInProgress || removeInProgress || updateInProgress) { + barButtonCardLayout.show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); + } else { + barButtonCardLayout.show(barButtonCardPane, BUTTON_CONSTRAINT); + } rightPane.add(barButtonCardPane); } - Dimension d = installProgressBar.getPreferredSize(); - Dimension d2 = installRemoveButton.getPreferredSize(); - d.width = DetailPanel.BUTTON_WIDTH; - d.height = Math.max(d.height,d2.height); - rightPane.setMinimumSize(d); - rightPane.setPreferredSize(d); + Dimension progressDim = installProgressBar.getPreferredSize(); + Dimension installDim = installRemoveButton.getPreferredSize(); + progressDim.width = BUTTON_WIDTH; + progressDim.height = Math.max(progressDim.height, installDim.height); + rightPane.setMinimumSize(progressDim); + rightPane.setPreferredSize(progressDim); } private void setExpandListener(Component component, MouseListener expandListener) { - if (component instanceof JButton) { - // This will confuse the button, causing it to stick on OS X - // https://github.com/processing/processing/issues/3172 - return; - } - component.addMouseListener(expandListener); - if (component instanceof Container) { - for (Component child : ((Container) component).getComponents()) { - setExpandListener(child, expandListener); + // If it's a JButton, adding the listener will make this stick on OS X + // https://github.com/processing/processing/issues/3172 + if (!(component instanceof JButton)) { + component.addMouseListener(expandListener); + if (component instanceof Container) { + for (Component child : ((Container) component).getComponents()) { + setExpandListener(child, expandListener); + } } } } @@ -427,8 +384,9 @@ private void setExpandListener(Component component, private void blurContributionPanel(Component component) { component.setFocusable(false); component.setEnabled(false); - if (component instanceof JComponent) + if (component instanceof JComponent) { ((JComponent) component).setToolTipText(INCOMPATIBILITY_BLUR); + } if (component instanceof Container) { for (Component child : ((Container) component).getComponents()) { blurContributionPanel(child); @@ -448,7 +406,7 @@ public void setContribution(Contribution contrib) { } // Avoid ugly synthesized bold - Font boldFont = Toolkit.getSansFont(12, Font.BOLD); + Font boldFont = ManagerFrame.SMALL_BOLD; String fontFace = ""; StringBuilder desc = new StringBuilder(); @@ -460,9 +418,9 @@ public void setContribution(Contribution contrib) { } desc.append(" "); - String version = contrib.getPrettyVersion(); - if (version != null) { - desc.append(version); + String prettyVersion = contrib.getPrettyVersion(); + if (prettyVersion != null) { + desc.append(prettyVersion); } desc.append("
"); @@ -493,8 +451,9 @@ public void setContribution(Contribution contrib) { if (lastUpdatedUTC != 0) { DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.MEDIUM); Date lastUpdatedDate = new Date(lastUpdatedUTC); - if (version != null && !version.isEmpty()) + if (prettyVersion != null) { desc.append(", "); + } desc.append("Last Updated on " + dateFormatter.format(lastUpdatedDate)); } @@ -510,7 +469,7 @@ public void setContribution(Contribution contrib) { // versionText.append("To finish an update, reinstall this contribution after restarting."); ; } else { - String latestVersion = contribListing.getLatestVersion(contrib); + String latestVersion = contribListing.getLatestPrettyVersion(contrib); if (latestVersion != null) { versionText.append("New version (" + latestVersion + ") available."); } else { @@ -530,26 +489,19 @@ public void setContribution(Contribution contrib) { updateButton.setVisible((contribListing.hasUpdates(contrib) && !contrib.isUpdateFlagged() && !contrib.isDeletionFlagged()) || updateInProgress); } - installRemoveButton.removeActionListener(installActionListener); - installRemoveButton.removeActionListener(removeActionListener); - installRemoveButton.removeActionListener(undoActionListener); - if (contrib.isDeletionFlagged()) { - installRemoveButton.addActionListener(undoActionListener); - installRemoveButton.setText(Language.text("contrib.undo")); + installRemoveButton.setText(undoText); + } else if (contrib.isInstalled()) { - installRemoveButton.addActionListener(removeActionListener); - installRemoveButton.setText(Language.text("contrib.remove")); + installRemoveButton.setText(removeText); installRemoveButton.setVisible(true); installRemoveButton.setEnabled(!contrib.isUpdateFlagged()); reorganizePaneComponents(); } else { - installRemoveButton.addActionListener(installActionListener); - installRemoveButton.setText(Language.text("contrib.install")); + installRemoveButton.setText(installText); } contextMenu.removeAll(); - if (contrib.isInstalled()) { contextMenu.add(openFolder); setComponentPopupMenu(contextMenu); @@ -562,15 +514,33 @@ public void setContribution(Contribution contrib) { } } + private void installContribution(AvailableContribution info) { if (info.link == null) { - listPanel.contributionTab.statusPanel.setErrorMessage(Language.interpolate("contrib.unsupported_operating_system", info.getType())); + setErrorMessage(Language.interpolate("contrib.unsupported_operating_system", info.getType())); } else { installContribution(info, info.link); } } + private void finishInstall(boolean error) { + resetInstallProgressBarState(); + installRemoveButton.setEnabled(!contrib.isUpdateFlagged()); + + if (error) { + setErrorMessage(Language.text("contrib.download_error")); + } + barButtonCardLayout.show(barButtonCardPane, BUTTON_CONSTRAINT); + installInProgress = false; + if (updateInProgress) { + updateInProgress = false; + } + updateButton.setVisible(contribListing.hasUpdates(contrib) && !contrib.isUpdateFlagged()); + setSelected(true); + } + + private void installContribution(AvailableContribution ad, String url) { installRemoveButton.setEnabled(false); @@ -580,38 +550,17 @@ private void installContribution(AvailableContribution ad, String url) { ContribProgressBar downloadProgress = new ContribProgressBar(installProgressBar) { public void finishedAction() { - // Finished downloading library + // nothing? } public void cancelAction() { - // Finished installing library - resetInstallProgressBarState(); - installRemoveButton.setEnabled(!contrib.isUpdateFlagged()); - - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, BUTTON_CONSTRAINT); - installInProgress = false; - if(updateInProgress) - updateInProgress = !updateInProgress; - updateButton.setVisible(contribListing.hasUpdates(contrib) && !contrib.isUpdateFlagged()); - setSelected(true); + finishInstall(false); } }; ContribProgressBar installProgress = new ContribProgressBar(installProgressBar) { public void finishedAction() { - // Finished installing library - resetInstallProgressBarState(); - installRemoveButton.setEnabled(!contrib.isUpdateFlagged()); - - if (isError()) { - listPanel.contributionTab.statusPanel.setErrorMessage(Language.text("contrib.download_error")); - } - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, BUTTON_CONSTRAINT); - installInProgress = false; - if(updateInProgress) - updateInProgress = !updateInProgress; - updateButton.setVisible(contribListing.hasUpdates(contrib) && !contrib.isUpdateFlagged()); - setSelected(true); + finishInstall(isError()); } public void cancelAction() { @@ -619,35 +568,19 @@ public void cancelAction() { } }; - ContributionManager.downloadAndInstall(listPanel.contributionTab.editor.getBase(), - downloadUrl, ad, + ContributionManager.downloadAndInstall(getBase(), downloadUrl, ad, downloadProgress, installProgress, - listPanel.contributionTab.statusPanel); + getStatusPanel()); } catch (MalformedURLException e) { Messages.showWarning(Language.text("contrib.errors.install_failed"), Language.text("contrib.errors.malformed_url"), e); // not sure why we'd re-enable the button if it had an error... -// installRemoveButton.setEnabled(true); + //installRemoveButton.setEnabled(true); } } - // This doesn't actually seem to work? - /* - static void stripTextSelectionListeners(JEditorPane editorPane) { - for (MouseListener listener : editorPane.getMouseListeners()) { - String className = listener.getClass().getName(); - if (className.endsWith("MutableCaretEvent") || - className.endsWith("DragListener") || - className.endsWith("BasicCaret")) { - editorPane.removeMouseListener(listener); - } - } - } - */ - - protected void resetInstallProgressBarState() { installProgressBar.setString(Language.text("contrib.progress.starting")); installProgressBar.setIndeterminate(false); @@ -656,9 +589,11 @@ protected void resetInstallProgressBarState() { } + /* static final HyperlinkListener NULL_HYPERLINK_LISTENER = new HyperlinkListener() { public void hyperlinkUpdate(HyperlinkEvent e) { } }; + */ /** @@ -679,6 +614,7 @@ public void setSelected(boolean isSelected) { installRemoveButton.setEnabled(installRemoveButton.getText().equals(Language.text("contrib.remove")) ||!contribListing.hasListDownloadFailed()); reorganizePaneComponents(); + /* descriptionPane.removeHyperlinkListener(NULL_HYPERLINK_LISTENER); descriptionPane.removeHyperlinkListener(conditionalHyperlinkOpener); if (isSelected()) { @@ -688,6 +624,7 @@ public void setSelected(boolean isSelected) { descriptionPane.addHyperlinkListener(NULL_HYPERLINK_LISTENER); // descriptionPane.setEditable(true); } + */ // Update style of hyperlinks setSelectionStyle(descriptionPane, isSelected()); @@ -762,29 +699,30 @@ static String toHtmlLinks(String stringIn) { * Sets coloring based on whether installed or not; * also makes ugly blue HTML links into the specified color (black). */ - static void setForegroundStyle(JTextPane textPane, boolean installed, boolean selected) { + static void setForegroundStyle(JTextPane textPane, + boolean installed, boolean selected) { Document doc = textPane.getDocument(); if (doc instanceof HTMLDocument) { HTMLDocument html = (HTMLDocument) doc; StyleSheet stylesheet = html.getStyleSheet(); - String c = (installed && !selected) ? "#555555" : "#000000"; // slightly grayed when installed -// String c = "#000000"; // just make them both black + // slightly grayed when installed + String c = (installed && !selected) ? "#555555" : "#000000"; stylesheet.addRule("body { color:" + c + "; }"); stylesheet.addRule("a { color:" + c + "; }"); } } - static void setTextStyle(JTextPane textPane) { + static void setTextStyle(JTextPane textPane, String fontSize) { Document doc = textPane.getDocument(); if (doc instanceof HTMLDocument) { HTMLDocument html = (HTMLDocument) doc; StyleSheet stylesheet = html.getStyleSheet(); stylesheet.addRule("body { " + " margin: 0; padding: 0;" + - " font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" + - " font-size: 100%;" + "font-size: 0.95em; " + + " font-family: " + Toolkit.getSansFontName() + ", Arial, Helvetica, sans-serif;" + + " font-size: 100%;" + "font-size: " + fontSize + "; " + "}"); } } @@ -805,9 +743,9 @@ static void setSelectionStyle(JTextPane textPane, boolean selected) { public void install() { - listPanel.contributionTab.statusPanel.clearMessage(); + clearStatusMessage(); installInProgress = true; - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); + barButtonCardLayout.show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); if (contrib instanceof AvailableContribution) { installContribution((AvailableContribution) contrib); contribListing.replaceContribution(contrib, contrib); @@ -816,131 +754,169 @@ public void install() { public void update() { - - listPanel.contributionTab.statusPanel.clearMessage(); + clearStatusMessage(); updateInProgress = true; if (contrib.getType().requiresRestart()) { installRemoveButton.setEnabled(false); installProgressBar.setVisible(true); installProgressBar.setIndeterminate(true); - ContribProgressBar progress = new ContribProgressBar(installProgressBar) { - public void finishedAction() { - // Finished uninstalling the library - resetInstallProgressBarState(); - updateButton.setEnabled(false); - AvailableContribution ad = - contribListing.getAvailableContribution(contrib); - String url = ad.link; - installContribution(ad, url); - } - - @Override - public void cancelAction() { - resetInstallProgressBarState(); - listPanel.contributionTab.statusPanel.setMessage(""); - updateInProgress = false; - installRemoveButton.setEnabled(true); - if (contrib.isDeletionFlagged()) { - ((LocalContribution)contrib).setUpdateFlag(true); - ((LocalContribution)contrib).setDeletionFlag(false); - contribListing.replaceContribution(contrib,contrib); - } - - boolean isModeActive = false; - if (contrib.getType() == ContributionType.MODE) { - ModeContribution m = (ModeContribution) contrib; - //Iterator iter = listPanel.contribManager.editor.getBase().getEditors().iterator(); - //while (iter.hasNext()) { - // TODO there's gotta be a cleaner way to do this accessor - Base base = listPanel.contributionTab.editor.getBase(); - for (Editor e : base.getEditors()) { - //Editor e = iter.next(); - if (e.getMode().equals(m.getMode())) { - isModeActive = true; - break; - } - } - } - if (isModeActive) { - updateButton.setEnabled(true); - } else { - // TODO: remove or uncomment if the button was added - //listPanel.contributionTab.restartButton.setVisible(true); - } - } - }; - ((LocalContribution) contrib) - .removeContribution(listPanel.contributionTab.editor.getBase(), - progress, listPanel.contributionTab.statusPanel); + ContribProgressBar progress = new UpdateProgressBar(installProgressBar); + getLocalContrib().removeContribution(getBase(), progress, getStatusPanel()); } else { updateButton.setEnabled(false); installRemoveButton.setEnabled(false); - AvailableContribution ad = contribListing.getAvailableContribution(contrib); + AvailableContribution ad = + contribListing.getAvailableContribution(contrib); + installContribution(ad, ad.link); + } + } + + + class UpdateProgressBar extends ContribProgressBar { + public UpdateProgressBar(JProgressBar progressBar) { + super(progressBar); + } + + public void finishedAction() { + resetInstallProgressBarState(); + updateButton.setEnabled(false); + AvailableContribution ad = + contribListing.getAvailableContribution(contrib); String url = ad.link; installContribution(ad, url); } + @Override + public void cancelAction() { + resetInstallProgressBarState(); + //listPanel.contributionTab.statusPanel.setMessage(""); // same as clear? + clearStatusMessage(); + updateInProgress = false; + installRemoveButton.setEnabled(true); + if (contrib.isDeletionFlagged()) { + getLocalContrib().setUpdateFlag(true); + getLocalContrib().setDeletionFlag(false); + contribListing.replaceContribution(contrib, contrib); + } + + if (isModeActive(contrib)) { + updateButton.setEnabled(true); + } else { + // TODO: remove or uncomment if the button was added + //listPanel.contributionTab.restartButton.setVisible(true); + } + } } public void remove() { - - listPanel.contributionTab.statusPanel.clearMessage(); + clearStatusMessage(); if (contrib.isInstalled() && contrib instanceof LocalContribution) { removeInProgress = true; - ((CardLayout) barButtonCardPane.getLayout()).show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); + barButtonCardLayout.show(barButtonCardPane, PROGRESS_BAR_CONSTRAINT); updateButton.setEnabled(false); installRemoveButton.setEnabled(false); installProgressBar.setVisible(true); installProgressBar.setIndeterminate(true); - ContribProgressBar monitor = new ContribProgressBar(installProgressBar) { - public void finishedAction() { - // Finished uninstalling the library - resetInstallProgressBarState(); - removeInProgress = false; - installRemoveButton.setEnabled(true); + ContribProgressBar monitor = new RemoveProgressBar(installProgressBar); + getLocalContrib().removeContribution(getBase(), monitor, getStatusPanel()); + } + } - reorganizePaneComponents(); - setSelected(true); // Needed for smooth working. Dunno why, though... - } - public void cancelAction() { - resetInstallProgressBarState(); - removeInProgress = false; - installRemoveButton.setEnabled(true); - - reorganizePaneComponents(); - setSelected(true); - - ContributionTab contributionTab = listPanel.contributionTab; - boolean isModeActive = false; - if (contrib.getType() == ContributionType.MODE) { - ModeContribution m = (ModeContribution) contrib; - // TODO there's gotta be a cleaner way to do this accessor - for (Editor e : contributionTab.editor.getBase().getEditors()) { - //Iterator iter = listPanel.contribManager.editor.getBase().getEditors().iterator(); - //while (iter.hasNext()) { - //Editor e = iter.next(); - if (e.getMode().equals(m.getMode())) { - isModeActive = true; - break; - } - } - } - if (isModeActive) { - updateButton.setEnabled(true); - } else { - // TODO: remove or uncomment if the button was added - //contributionTab.restartButton.setVisible(true); + class RemoveProgressBar extends ContribProgressBar { + public RemoveProgressBar(JProgressBar progressBar) { + super(progressBar); + } + + private void preAction() { + resetInstallProgressBarState(); + removeInProgress = false; + installRemoveButton.setEnabled(true); + reorganizePaneComponents(); + setSelected(true); // Needed for smooth working. Dunno why, though... + } + + public void finishedAction() { + // Finished uninstalling the library + preAction(); + } + + public void cancelAction() { + preAction(); + + if (isModeActive(contrib)) { + updateButton.setEnabled(true); + } else { + // TODO: remove or uncomment if the button was added + //contributionTab.restartButton.setVisible(true); + } + } + } + + + private void undo() { + clearStatusMessage(); + if (contrib instanceof LocalContribution) { + LocalContribution installed = getLocalContrib(); + installed.setDeletionFlag(false); + contribListing.replaceContribution(contrib, contrib); // ?? + Iterator contribsListIter = contribListing.allContributions.iterator(); + boolean toBeRestarted = false; + while (contribsListIter.hasNext()) { + Contribution contribElement = contribsListIter.next(); + if (contrib.getType().equals(contribElement.getType())) { + if (contribElement.isDeletionFlagged() || + contribElement.isUpdateFlagged()) { + toBeRestarted = !toBeRestarted; + break; } } - }; - ContributionTab contributionTab = listPanel.contributionTab; - LocalContribution localContrib = (LocalContribution) contrib; - localContrib.removeContribution(contributionTab.editor.getBase(), monitor, contributionTab.statusPanel); + } + // TODO: remove or uncomment if the button was added + //listPanel.contributionTab.restartButton.setVisible(toBeRestarted); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + // Can't be called from the constructor because the path isn't set all the + // way down. However, it's not Base changes over time. More importantly, + // though, is that the functions being called in Base are somewhat suspect + // since they're contribution-related, and should perhaps live closer. + private Base getBase() { + return listPanel.contributionTab.editor.getBase(); + } + + + private boolean isModeActive(Contribution contrib) { + if (contrib.getType() == ContributionType.MODE) { + ModeContribution m = (ModeContribution) contrib; + for (Editor e : getBase().getEditors()) { + if (e.getMode().equals(m.getMode())) { + return true; + } + } } + return false; + } + + + private StatusPanel getStatusPanel() { + return listPanel.contributionTab.statusPanel; // TODO this is gross [fry] + } + + + private void clearStatusMessage() { + getStatusPanel().clearMessage(); + } + + private void setErrorMessage(String message) { + getStatusPanel().setErrorMessage(message); } } diff --git a/app/src/processing/app/contrib/ListPanel.java b/app/src/processing/app/contrib/ListPanel.java index 70001cf0ef..845b7178d4 100644 --- a/app/src/processing/app/contrib/ListPanel.java +++ b/app/src/processing/app/contrib/ListPanel.java @@ -45,14 +45,13 @@ public class ListPanel extends JPanel implements Scrollable, ContributionListing.ChangeListener { ContributionTab contributionTab; - TreeMap panelByContribution = new TreeMap(ContributionListing.COMPARATOR); - Set visibleContributions = new TreeSet(ContributionListing.COMPARATOR); + TreeMap panelByContribution = new TreeMap<>(ContributionListing.COMPARATOR); private DetailPanel selectedPanel; - protected Contribution.Filter filter; - protected ContributionListing contribListing = ContributionListing.getInstance(); + protected ContributionRowFilter filter; protected JTable table; - DefaultTableModel model; + protected TableRowSorter sorter; + ContributionTableModel model; JScrollPane scrollPane; static Icon upToDateIcon; @@ -61,13 +60,17 @@ public class ListPanel extends JPanel static Icon foundationIcon; static Icon downloadingIcon; - static Font plainFont; - static Font boldFont; - static Font headerFont; - // Should this be in theme.txt? Of course! Is it? No. static final Color HEADER_BGCOLOR = new Color(0xffEBEBEB); + static final Color SECTION_COLOR = new Color(0xFFf8f8f8); + static final Color SELECTION_COLOR = new Color(0xffe0fffd); + static final SectionHeaderContribution[] sections = { + new SectionHeaderContribution(ContributionType.LIBRARY), + new SectionHeaderContribution(ContributionType.MODE), + new SectionHeaderContribution(ContributionType.TOOL), + new SectionHeaderContribution(ContributionType.EXAMPLES) + }; public ListPanel() { if (upToDateIcon == null) { @@ -76,47 +79,55 @@ public ListPanel() { incompatibleIcon = Toolkit.getLibIconX("manager/incompatible"); foundationIcon = Toolkit.getLibIconX("icons/foundation", 16); downloadingIcon = Toolkit.getLibIconX("manager/downloading"); - - plainFont = Toolkit.getSansFont(14, Font.PLAIN); - boldFont = Toolkit.getSansFont(14, Font.BOLD); - headerFont = Toolkit.getSansFont(12, Font.PLAIN); } } public ListPanel(final ContributionTab contributionTab, - Contribution.Filter filter) { + final Contribution.Filter filter, + final boolean enableSections, + final ContributionColumn... columns) { + this(); this.contributionTab = contributionTab; - this.filter = filter; + this.filter = new ContributionRowFilter(filter); setLayout(new GridBagLayout()); setOpaque(true); setBackground(Color.WHITE); - model = new ContribTableModel(); + model = new ContributionTableModel(columns); + model.enableSections(enableSections); table = new JTable(model) { @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); - if (isRowSelected(row)) { - c.setBackground(new Color(0xe0fffd)); + Object rowValue = getValueAt(row, column); + if (rowValue instanceof SectionHeaderContribution) { + c.setBackground(SECTION_COLOR); + } else if (isRowSelected(row)) { + c.setBackground(SELECTION_COLOR); } else { c.setBackground(Color.white); } return c; } + + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + if (!(getValueAt(rowIndex, columnIndex) instanceof SectionHeaderContribution)) { + super.changeSelection(rowIndex, columnIndex, toggle, extend); + } + } }; // There is a space before Status - String[] colName = { " Status", "Name", "Author" }; - model.setColumnIdentifiers(colName); scrollPane = new JScrollPane(table); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setBorder(BorderFactory.createEmptyBorder()); table.setFillsViewportHeight(true); table.setDefaultRenderer(Contribution.class, new ContribStatusRenderer()); - table.setFont(plainFont); - table.setRowHeight(28); - table.setRowMargin(6); + table.setFont(ManagerFrame.NORMAL_PLAIN); + table.setRowHeight(Toolkit.zoom(28)); + table.setRowMargin(Toolkit.zoom(6)); table.getColumnModel().setColumnMargin(0); table.getColumnModel().getColumn(0).setMaxWidth(ManagerFrame.STATUS_WIDTH); table.getColumnModel().getColumn(2).setMinWidth(ManagerFrame.AUTHOR_WIDTH); @@ -136,55 +147,22 @@ public void valueChanged(ListSelectionEvent event) { setSelectedPanel(panelByContribution.get(table.getValueAt(table .getSelectedRow(), 0))); // Preventing the focus to move out of filterField after typing every character - if (!contributionTab.filterField.hasFocus()) { + if (!contributionTab.filterHasFocus()) { table.requestFocusInWindow(); } } } }); - TableRowSorter sorter = new TableRowSorter(table.getModel()); + sorter = new TableRowSorter<>(model); table.setRowSorter(sorter); - sorter.setComparator(1, ContributionListing.COMPARATOR); - sorter.setComparator(2, new Comparator() { - - @Override - public int compare(Contribution o1, Contribution o2) { - return getAuthorNameWithoutMarkup(o1.getAuthorList()) - .compareTo(getAuthorNameWithoutMarkup(o2.getAuthorList())); + sorter.setRowFilter(this.filter); + for (int i=0; i < model.getColumnCount(); i++) { + if (model.columns[i] == ContributionColumn.NAME) { + sorter.setSortKeys(Collections.singletonList(new SortKey(i, SortOrder.ASCENDING))); } - }); - sorter.setComparator(0, new Comparator() { - - @Override - public int compare(Contribution o1, Contribution o2) { - int pos1 = 0; - if (o1.isInstalled()) { - pos1 = 1; - if (contribListing.hasUpdates(o1)) { - pos1 = 2; - } - if (!o1.isCompatible(Base.getRevision())) { - pos1 = 3; - } - } else { - pos1 = 4; - } - int pos2 = 0; - if (o2.isInstalled()) { - pos2 = 1; - if (contribListing.hasUpdates(o2)) { - pos2 = 2; - } - if (!o2.isCompatible(Base.getRevision())) { - pos2 = 3; - } - } else { - pos2 = 4; - } - return pos1 - pos2; - } - }); + sorter.setComparator(i, model.columns[i].getComparator()); + } table.getTableHeader().setDefaultRenderer(new ContribHeaderRenderer()); GroupLayout layout = new GroupLayout(this); @@ -195,6 +173,19 @@ public int compare(Contribution o1, Contribution o2) { table.setVisible(true); } + private static int getContributionStatusRank(Contribution c) { + int pos = 4; + if (c.isInstalled()) { + pos = 1; + if (ContributionListing.getInstance().hasUpdates(c)) { + pos = 2; + } + if (!c.isCompatible(Base.getRevision())) { + pos = 3; + } + } + return pos; + } class ContribHeaderRenderer extends DefaultTableCellRenderer { @@ -231,7 +222,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, if (tableHeader != null) { setForeground(tableHeader.getForeground()); } - setFont(headerFont); + setFont(ManagerFrame.SMALL_PLAIN); setIcon(getSortIcon(table, column)); setBackground(HEADER_BGCOLOR); // if (column % 2 == 0) { @@ -272,16 +263,11 @@ protected Icon getSortIcon(JTable table, int column) { * @return the SortKey, or null if the column is unsorted */ protected SortKey getSortKey(JTable table, int column) { - RowSorter rowSorter = table.getRowSorter(); - if (rowSorter == null) { - return null; - } + return Optional.ofNullable(table.getRowSorter()) + .map(RowSorter::getSortKeys) + .map(columns -> columns.isEmpty() ? null : columns.get(0)) + .orElse(null); - List sortedColumns = rowSorter.getSortKeys(); - if (sortedColumns.size() > 0) { - return (SortKey) sortedColumns.get(0); - } - return null; } } @@ -300,129 +286,269 @@ public Component getTableCellRendererComponent(JTable table, Object value, int column) { Contribution contribution = (Contribution) value; JLabel label = new JLabel(); + ContributionColumn col = model.columns[column]; if (value == null) { // Working on https://github.com/processing/processing/issues/3667 //System.err.println("null value seen in getTableCellRendererComponent()"); // TODO this is now working, but the underlying issue is not fixed return label; } - if (column == 0) { - Icon icon = null; - label.setFont(plainFont); - if (contribution.isInstalled()) { - icon = upToDateIcon; - if (contribListing.hasUpdates(contribution)) { - icon = updateAvailableIcon; - } - if (!contribution.isCompatible(Base.getRevision())) { - icon = incompatibleIcon; - } - } - if ((panelByContribution.get(contribution)).updateInProgress || - (panelByContribution.get(contribution)).installInProgress) { - // Display "Loading icon" if download/install in progress - label.setIcon(downloadingIcon); - } else { - label.setIcon(icon); - } - label.setHorizontalAlignment(SwingConstants.CENTER); - if (isSelected) { - label.setBackground(new Color(0xe0fffd)); - } - label.setOpaque(true); -// return table.getDefaultRenderer(Icon.class).getTableCellRendererComponent(table, icon, isSelected, false, row, column); - - } else if (column == 1) { - // Generating ellipses based on fontMetrics - String fontFace = ""; - FontMetrics fontMetrics = table.getFontMetrics(boldFont); //table.getFont()); - int colSize = table.getColumnModel().getColumn(1).getWidth(); - String sentence = contribution.getSentence(); - //int currentWidth = table.getFontMetrics(table.getFont().deriveFont(Font.BOLD)).stringWidth(contribution.getName() + " | "); - int currentWidth = table.getFontMetrics(boldFont).stringWidth(contribution.getName() + " | "); - int ellipsesWidth = fontMetrics.stringWidth("..."); - //String name = "" + contribution.getName(); - String name = "" + fontFace + contribution.getName(); - if (sentence == null) { - label.setText(name + ""); - } else { - sentence = " | " + sentence; - currentWidth += ellipsesWidth; - int i = 0; - for (i = 0; i < sentence.length(); i++) { - currentWidth += fontMetrics.charWidth(sentence.charAt(i)); - if (currentWidth >= colSize) { - break; - } - } - // Adding ellipses only if text doesn't fits into the column - if(i != sentence.length()){ - label.setText(name + sentence.substring(0, i) + "..."); - }else { - label.setText(name + sentence + ""); - } - } + + label.setOpaque(true); + + if (value instanceof SectionHeaderContribution && col != ContributionColumn.NAME) { + return label; + } + switch (col) { + case STATUS: + case STATUS_NO_HEADER: + configureStatusColumnLabel(label, contribution); + break; + case NAME: + configureNameColumnLabel(table, label, contribution); + break; + case AUTHOR: + configureAuthorsColumnLabel(label, contribution); + break; + case INSTALLED_VERSION: + label.setText(contribution.getBenignVersion()); + break; + case AVAILABLE_VERSION: + label.setText(ContributionListing.getInstance().getLatestPrettyVersion(contribution)); + break; + } + + if(!contribution.isCompatible(Base.getRevision())){ + label.setForeground(Color.LIGHT_GRAY); + } + return label; + } + + private void configureStatusColumnLabel(JLabel label, Contribution contribution) { + Icon icon = null; + label.setFont(ManagerFrame.NORMAL_PLAIN); + if ((panelByContribution.get(contribution)).updateInProgress || + (panelByContribution.get(contribution)).installInProgress) { + // Display "Loading icon" if download/install in progress + icon = downloadingIcon; + } else if (contribution.isInstalled()) { if (!contribution.isCompatible(Base.getRevision())) { - label.setForeground(Color.LIGHT_GRAY); - } - if (table.isRowSelected(row)) { - label.setBackground(new Color(0xe0fffd)); - } - label.setFont(plainFont); - label.setOpaque(true); - } else { - if (contribution.isSpecial()) { - label = new JLabel(foundationIcon); + icon = incompatibleIcon; + } else if (ContributionListing.getInstance().hasUpdates(contribution)) { + icon = updateAvailableIcon; + } else if (panelByContribution.get(contribution).installInProgress + || panelByContribution.get(contribution).updateInProgress) { + icon = downloadingIcon; } else { - label = new JLabel(); + icon = upToDateIcon; } - String authorList = contribution.getAuthorList(); - String name = getAuthorNameWithoutMarkup(authorList); - label.setText(name.toString()); - label.setHorizontalAlignment(SwingConstants.LEFT); - if(!contribution.isCompatible(Base.getRevision())){ - label.setForeground(Color.LIGHT_GRAY); - }else{ - label.setForeground(Color.BLACK); + } + + label.setIcon(icon); + label.setHorizontalAlignment(SwingConstants.CENTER); + } + + private void configureNameColumnLabel(JTable table, JLabel label, Contribution contribution) { + // Generating ellipses based on fontMetrics + final Font boldFont = ManagerFrame.NORMAL_BOLD; + FontMetrics fontMetrics = table.getFontMetrics(boldFont); //table.getFont()); + int colSize = table.getColumnModel().getColumn(1).getWidth(); + int currentWidth = fontMetrics.stringWidth(contribution.getName() + " | ..."); + String sentence = contribution.getSentence(); + StringBuilder text = new StringBuilder("") + .append(contribution.getName()); + + if (sentence == null) { + text.append(""); + } else { + int i = 0; + for (i = 0; i < sentence.length(); i++) { + currentWidth += fontMetrics.charWidth(sentence.charAt(i)); + if (currentWidth >= colSize) { + break; + } } - if (table.isRowSelected(row)) { - label.setBackground(new Color(0xe0fffd)); + text.append(" | ").append(sentence, 0, i); + // Adding ellipses only if text doesn't fits into the column + if(i != sentence.length()) { + text.append("..."); } - label.setFont(Toolkit.getSansFont(14, Font.BOLD)); - label.setOpaque(true); } - return label; + text.append(""); + label.setText(text.toString()); + label.setFont(ManagerFrame.NORMAL_PLAIN); + } + + private void configureAuthorsColumnLabel(JLabel label, Contribution contribution) { + if (contribution.isSpecial()) { + label.setIcon(foundationIcon); + } + String authorList = contribution.getAuthorList(); + String name = getAuthorNameWithoutMarkup(authorList); + label.setText(name); + label.setHorizontalAlignment(SwingConstants.LEFT); + label.setForeground(Color.BLACK); + label.setFont(ManagerFrame.NORMAL_BOLD); } } + protected enum ContributionColumn { + STATUS(" Status"), + NAME("Name"), + AUTHOR("Author"), + INSTALLED_VERSION("Installed"), + AVAILABLE_VERSION("Available"), + STATUS_NO_HEADER(""); + + final String name; + + ContributionColumn(String name) { + this.name = name; + } + + Comparator getComparator() { + Comparator comparator = Comparator.comparing(Contribution::getType) + .thenComparingInt(contribution -> contribution instanceof SectionHeaderContribution ? 0 : 1); + switch (this) { + case STATUS: + case STATUS_NO_HEADER: + return comparator.thenComparingInt(ListPanel::getContributionStatusRank); + case AUTHOR: + return comparator.thenComparing(contribution -> getAuthorNameWithoutMarkup(contribution.getAuthorList())); + case NAME: + default: + return comparator.thenComparing(Contribution::getName, String.CASE_INSENSITIVE_ORDER); + } + } + } + + protected class ContributionTableModel extends AbstractTableModel { + + ContributionColumn[] columns = { ContributionColumn.STATUS, ContributionColumn.NAME, ContributionColumn.AUTHOR }; + boolean sectionsEnabled; + + ContributionTableModel(ContributionColumn... columns) { + if (columns.length > 0) { + this.columns = columns; + } + } - static private class ContribTableModel extends DefaultTableModel { @Override - public boolean isCellEditable(int row, int column) { - return false; + public int getRowCount() { + return ContributionListing.getInstance().allContributions.size() + (sectionsEnabled ? 4 : 0); + } + + @Override + public int getColumnCount() { + return columns.length; + } + + @Override + public String getColumnName(int column) { + if (column < 0 || column > columns.length) { + return ""; + } + + return columns[column].name; } @Override public Class getColumnClass(int columnIndex) { return Contribution.class; } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (rowIndex >= ContributionListing.getInstance().allContributions.size()) { + return sections[rowIndex - ContributionListing.getInstance().allContributions.size()]; + } + + return ContributionListing.getInstance().allContributions.stream().skip(rowIndex).findFirst().orElse(null); + } + + public void setColumns(ContributionColumn[] columns) { + this.columns = columns; + } + + public void enableSections(boolean enable) { + this.sectionsEnabled = enable; + } + } + + protected class ContributionRowFilter extends RowFilter { + Contribution.Filter contributionFilter; + Optional categoryFilter = Optional.empty(); + List stringFilters = Collections.emptyList(); + + ContributionRowFilter(Contribution.Filter contributionFilter) { + this.contributionFilter = contributionFilter; + } + + public void setCategoryFilter(String categoryFilter) { + this.categoryFilter = Optional.ofNullable(categoryFilter); + } + + public void setStringFilters(List filters) { + this.stringFilters = filters; + } + + @Override + public boolean include(Entry entry) { + Contribution contribution = (Contribution) entry.getValue(0); + if (contribution instanceof SectionHeaderContribution) { + return includeSection((SectionHeaderContribution) contribution); + } + return includeContribution(contribution); + } + + private boolean includeContribution(Contribution contribution) { + return contributionFilter.matches(contribution) + && categoryFilter.map(contribution::hasCategory).orElse(true) + && stringFilters.stream().allMatch(pattern -> ContributionListing.getInstance().matches(contribution, pattern)); + } + + private boolean includeSection(SectionHeaderContribution section) { + return ContributionListing.getInstance().allContributions.stream() + .filter(contribution -> contribution.getType() == section.getType()) + .anyMatch(this::includeContribution); + } } + protected static class SectionHeaderContribution extends Contribution { + ContributionType type; + + SectionHeaderContribution(ContributionType type) { + this.type = type; + this.name = getTypeName(); + } - String getAuthorNameWithoutMarkup(String authorList) { - StringBuilder name = new StringBuilder(""); + @Override + public ContributionType getType() { + return type; + } + + @Override + public boolean isInstalled() { + return false; + } + } + + static String getAuthorNameWithoutMarkup(String authorList) { + StringBuilder name = new StringBuilder(); if (authorList != null) { + int parentheses = 0; for (int i = 0; i < authorList.length(); i++) { if (authorList.charAt(i) == '[' || authorList.charAt(i) == ']') { continue; } if (authorList.charAt(i) == '(') { - i++; - while (authorList.charAt(i) != ')') { - i++; - } - } else { + parentheses++; + } else if (authorList.charAt(i) == ')') { + parentheses--; + } else if (parentheses == 0) { name.append(authorList.charAt(i)); } } @@ -430,113 +556,57 @@ String getAuthorNameWithoutMarkup(String authorList) { return name.toString(); } - - void updatePanelOrdering(Set contributionsSet) { - model.getDataVector().removeAllElements(); - model.fireTableDataChanged(); - int rowCount = 0; - synchronized (contributionsSet) { - for (Contribution entry : contributionsSet) { - model.addRow(new Object[]{entry, entry, entry}); - if (selectedPanel != null && - entry.getName().equals(selectedPanel.getContrib().getName())) { - table.setRowSelectionInterval(rowCount, rowCount); - } - rowCount++; - } - } - } - - + // Thread: EDT public void contributionAdded(final Contribution contribution) { - if (filter.matches(contribution)) { - // TODO: this should already be on EDT, check it [jv] - EventQueue.invokeLater(new Runnable() { - public void run() { - if (!panelByContribution.containsKey(contribution)) { - DetailPanel newPanel = - new DetailPanel(ListPanel.this); - synchronized (panelByContribution) { - panelByContribution.put(contribution, newPanel); - } - synchronized (visibleContributions) { - visibleContributions.add(contribution); - } - if (newPanel != null) { - newPanel.setContribution(contribution); - add(newPanel); - updatePanelOrdering(visibleContributions); - updateColors(); // XXX this is the place - } - } - } - }); + if (!panelByContribution.containsKey(contribution)) { + DetailPanel newPanel = + new DetailPanel(this); + panelByContribution.put(contribution, newPanel); + newPanel.setContribution(contribution); + add(newPanel); + model.fireTableDataChanged(); + updateColors(); // XXX this is the place } } + // Thread: EDT public void contributionRemoved(final Contribution contribution) { - // TODO: this should already be on EDT, check it [jv] - EventQueue.invokeLater(new Runnable() { - public void run() { - synchronized (panelByContribution) { - DetailPanel panel = panelByContribution.get(contribution); - if (panel != null) { - remove(panel); - panelByContribution.remove(contribution); - } - } - synchronized (visibleContributions) { - visibleContributions.remove(contribution); - } - updatePanelOrdering(visibleContributions); - updateColors(); - updateUI(); + DetailPanel panel = panelByContribution.get(contribution); + if (panel != null) { + remove(panel); + panelByContribution.remove(contribution); } - }); + model.fireTableDataChanged(); + updateColors(); + updateUI(); } + // Thread: EDT public void contributionChanged(final Contribution oldContrib, final Contribution newContrib) { - // TODO: this should already be on EDT, check it [jv] - EventQueue.invokeLater(new Runnable() { - public void run() { - synchronized (panelByContribution) { - DetailPanel panel = panelByContribution.get(oldContrib); - if (panel == null) { - contributionAdded(newContrib); - } else { - panelByContribution.remove(oldContrib); - panel.setContribution(newContrib); - panelByContribution.put(newContrib, panel); - } - } - synchronized (visibleContributions) { - if (visibleContributions.contains(oldContrib)) { - visibleContributions.remove(oldContrib); - visibleContributions.add(newContrib); - } - updatePanelOrdering(visibleContributions); - } + DetailPanel panel = panelByContribution.get(oldContrib); + if (panel == null) { + contributionAdded(newContrib); + } else { + panelByContribution.remove(oldContrib); + panel.setContribution(newContrib); + panelByContribution.put(newContrib, panel); + model.fireTableDataChanged(); } - }); } - public void filterLibraries(List filteredContributions) { - synchronized (visibleContributions) { - visibleContributions.clear(); - for (Contribution contribution : filteredContributions) { - if (contribution.getType() == contributionTab.contribType) { - visibleContributions.add(contribution); - } - } - updatePanelOrdering(visibleContributions); - } + // Thread: EDT + public void filterLibraries(String category, List filters) { + filter.setCategoryFilter(category); + filter.setStringFilters(filters); + model.fireTableDataChanged(); } + // Thread: EDT protected void setSelectedPanel(DetailPanel contributionPanel) { contributionTab.updateStatusPanel(contributionPanel); @@ -563,47 +633,43 @@ protected DetailPanel getSelectedPanel() { } + // Thread: EDT /** * Updates the colors of all library panels that are visible. */ protected void updateColors() { int count = 0; - synchronized (panelByContribution) { - for (Entry entry : panelByContribution.entrySet()) { - DetailPanel panel = entry.getValue(); - - if (panel.isVisible() && panel.isSelected()) { - panel.setBackground(UIManager.getColor("List.selectionBackground")); - panel.setForeground(UIManager.getColor("List.selectionForeground")); - panel.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); - count++; - + for (Entry entry : panelByContribution.entrySet()) { + DetailPanel panel = entry.getValue(); + Border border = BorderFactory.createEmptyBorder(1, 1, 1, 1); + + if (panel.isVisible()) { + boolean oddRow = count % 2 == 1; + Color bgColor = null; + Color fgColor = UIManager.getColor("List.foreground"); + + if (panel.isSelected()) { + bgColor = UIManager.getColor("List.selectionBackground"); + fgColor = UIManager.getColor("List.selectionForeground"); + border = UIManager.getBorder("List.focusCellHighlightBorder"); + } else if (Platform.isMacOS()) { + border = oddRow + ? UIManager.getBorder("List.oddRowBackgroundPainter") + : UIManager.getBorder("List.evenRowBackgroundPainter"); } else { - Border border = null; - if (panel.isVisible()) { - if (Platform.isMacOS()) { - if (count % 2 == 1) { - border = UIManager.getBorder("List.oddRowBackgroundPainter"); - } else { - border = UIManager.getBorder("List.evenRowBackgroundPainter"); - } - } else { - if (count % 2 == 1) { - panel.setBackground(new Color(219, 224, 229)); - } else { - panel.setBackground(new Color(241, 241, 241)); - } - } - count++; - } + bgColor = oddRow + ? new Color(219, 224, 229) + : new Color(241, 241, 241); + } - if (border == null) { - border = BorderFactory.createEmptyBorder(1, 1, 1, 1); - } - panel.setBorder(border); - panel.setForeground(UIManager.getColor("List.foreground")); + panel.setForeground(fgColor); + if (bgColor != null) { + panel.setBackground(bgColor); } + count++; } + + panel.setBorder(border); } } @@ -641,39 +707,38 @@ public int getScrollableBlockIncrement(Rectangle visibleRect, */ @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { - if (orientation == SwingConstants.VERTICAL) { - int lastHeight = 0, height = 0; - int bottomOfScrollArea = visibleRect.y + visibleRect.height; - - for (Component c : getComponents()) { - if (c.isVisible()) { - if (c instanceof DetailPanel) { - Dimension d = c.getPreferredSize(); - - int nextHeight = height + d.height; - - if (direction > 0) { - // scrolling down - if (nextHeight > bottomOfScrollArea) { - return nextHeight - bottomOfScrollArea; - } - } else { - // scrolling up - if (nextHeight > visibleRect.y) { - if (visibleRect.y != height) { - return visibleRect.y - height; - } else { - return visibleRect.y - lastHeight; - } - } - } + if (orientation != SwingConstants.VERTICAL) { + return 0; + } + int lastHeight = 0; + int height = 0; + int bottomOfScrollArea = visibleRect.y + visibleRect.height; - lastHeight = height; - height = nextHeight; - } + for (Component c : getComponents()) { + if (!(c.isVisible() && c instanceof DetailPanel)) { + continue; + } + Dimension d = c.getPreferredSize(); + + int nextHeight = height + d.height; + + if (direction > 0) { + // scrolling down + if (nextHeight > bottomOfScrollArea) { + return nextHeight - bottomOfScrollArea; + } + } else if (nextHeight > visibleRect.y) { + if (visibleRect.y != height) { + return visibleRect.y - height; + } else { + return visibleRect.y - lastHeight; } } + + lastHeight = height; + height = nextHeight; } + return 0; } @@ -691,6 +756,7 @@ public boolean getScrollableTracksViewportWidth() { public int getRowCount() { - return panelByContribution.size(); + // This will count section headers, but it is only used to check if any rows are shown + return sorter.getViewRowCount(); } } diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java index dc182b9bb9..cb128a73e9 100644 --- a/app/src/processing/app/contrib/LocalContribution.java +++ b/app/src/processing/app/contrib/LocalContribution.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -72,9 +72,9 @@ public LocalContribution(File folder) { } // changing to 'authors' in 3.0a11 authors = properties.get(AUTHORS_PROPERTY); - if (authors == null) { - authors = properties.get("authorList"); - } +// if (authors == null) { +// authors = properties.get("authorList"); +// } url = properties.get("url"); sentence = properties.get("sentence"); paragraph = properties.get("paragraph"); @@ -82,11 +82,11 @@ public LocalContribution(File folder) { try { version = Integer.parseInt(properties.get("version")); } catch (NumberFormatException e) { - System.err.println("The version number for the “" + name + "” library is not set properly."); + System.err.println("The version number for the “" + name + "” library is not a number."); System.err.println("Please contact the library author to fix it according to the guidelines."); } - prettyVersion = properties.get("prettyVersion"); + setPrettyVersion(properties.get("prettyVersion")); try { lastUpdated = Long.parseLong(properties.get("lastUpdated")); @@ -237,7 +237,8 @@ static void listClasses(ClassLoader loader) { LocalContribution copyAndLoad(Base base, boolean confirmReplace, StatusPanel status) { -// NOTE: null status => function is called on startup when Editor objects, et al. aren't ready + // NOTE: null status => function is called on startup + // when Editor objects, et al. aren't ready String contribFolderName = getFolder().getName(); @@ -262,10 +263,17 @@ LocalContribution copyAndLoad(Base base, (oldContrib.getId() != null && oldContrib.getId().equals(getId()))) { if (oldContrib.getType().requiresRestart()) { - // XXX: We can't replace stuff, soooooo.... do something different if (!oldContrib.backup(false, status)) { return null; } + /* + try { + Platform.deleteFile(oldContrib.getFolder()); + } catch (IOException e) { + status.setErrorMessage(e.getMessage()); + return null; + } + */ } else { int result = 0; boolean doBackup = Preferences.getBoolean("contribution.backup.on_install"); @@ -306,8 +314,7 @@ LocalContribution copyAndLoad(Base base, Util.removeDir(contribFolder); } - } - else { + } else { // This if should ideally never happen, since this function // is to be called only when restarting on update if (contribFolder.exists() && contribFolder.isDirectory()) { diff --git a/app/src/processing/app/contrib/ManagerFrame.java b/app/src/processing/app/contrib/ManagerFrame.java index e65a864db7..3e25531bf9 100644 --- a/app/src/processing/app/contrib/ManagerFrame.java +++ b/app/src/processing/app/contrib/ManagerFrame.java @@ -38,50 +38,46 @@ public class ManagerFrame { static final String ANY_CATEGORY = Language.text("contrib.all"); -// static final int TAB_WIDTH = 100; -// static final int TAB_HEIGHT = 34; - static final int AUTHOR_WIDTH = 240; - static final int STATUS_WIDTH = 66; + static final int AUTHOR_WIDTH = Toolkit.zoom(240); + static final int STATUS_WIDTH = Toolkit.zoom(66); static final String title = "Contribution Manager"; Base base; JFrame frame; -// JTabbedPane tabbedPane; ManagerTabs tabs; - // the calling editor, so updates can be applied -// Editor editor; - ContributionTab librariesTab; ContributionTab modesTab; ContributionTab toolsTab; ContributionTab examplesTab; UpdateContributionTab updatesTab; -// JLabel numberLabel; -// private JLabel[] tabLabels; -// private JPanel updateTabPanel; -// private JLabel updateTabLabel; + static Font SMALL_PLAIN; + static Font SMALL_BOLD; + static Font NORMAL_PLAIN; + static Font NORMAL_BOLD; public ManagerFrame(Base base) { this.base = base; -// numberLabel = new JLabel(Toolkit.getLibIconX("manager/notification")); + final int smallSize = Toolkit.zoom(12); + final int normalSize = Toolkit.zoom(14); + SMALL_PLAIN = Toolkit.getSansFont(smallSize, Font.PLAIN); + SMALL_BOLD = Toolkit.getSansFont(smallSize, Font.BOLD); + NORMAL_PLAIN = Toolkit.getSansFont(normalSize, Font.PLAIN); + NORMAL_BOLD = Toolkit.getSansFont(normalSize, Font.BOLD); + librariesTab = new ContributionTab(this, ContributionType.LIBRARY); modesTab = new ContributionTab(this, ContributionType.MODE); toolsTab = new ContributionTab(this, ContributionType.TOOL); examplesTab = new ContributionTab(this, ContributionType.EXAMPLES); - updatesTab = new UpdateContributionTab(this, null); + updatesTab = new UpdateContributionTab(this); } - // TODO remove this Editor... need to use Base.getActiveEditor() - // The editor may be closed while still running the contrib manager public void showFrame(ContributionType contributionType) { -// this.editor = editor; - ContributionTab showTab = getTab(contributionType); if (frame == null) { makeFrame(); @@ -100,7 +96,7 @@ public void showFrame(ContributionType contributionType) { private void makeFrame() { frame = new JFrame(title); - frame.setMinimumSize(new Dimension(750, 500)); + frame.setMinimumSize(Toolkit.zoom(750, 500)); tabs = new ManagerTabs(base); makeAndShowTab(false, true); @@ -111,129 +107,7 @@ private void makeFrame() { tabs.addPanel(examplesTab, "Examples"); tabs.addPanel(updatesTab, "Updates"); - /* - tabbedPane.addTab("Libraries", null, librariesTab, "Libraries"); - tabbedPane.setMnemonicAt(0, KeyEvent.VK_1); - - tabbedPane.addTab("Modes", null, modesTab, "Modes"); - tabbedPane.setMnemonicAt(1, KeyEvent.VK_2); - - tabbedPane.addTab("Tools", null, toolsTab, "Tools"); - tabbedPane.setMnemonicAt(2, KeyEvent.VK_3); - - tabbedPane.addTab("Examples", null, examplesTab, "Examples"); - tabbedPane.setMnemonicAt(3, KeyEvent.VK_4); - - tabbedPane.addTab("Updates", null, updatesTab, "Updates"); - tabbedPane.setMnemonicAt(4, KeyEvent.VK_5); - - tabbedPane.setUI(new SpacedTabbedPaneUI()); - tabbedPane.setBackground(new Color(0x132638)); - tabbedPane.setOpaque(true); - - for (int i = 0; i < 5; i++) { - tabbedPane.setToolTipTextAt(i, null); - } - */ - - /* - final String[] tabTitles = { - "Libraries", "Modes", "Tools", "Examples", "Updates" - }; - tabLabels = new JLabel[4]; - - for (int i = 0 ; i < 4; i++) { - final int temp = i; - tabLabels[i] = new JLabel(tabTitles[i]) { - @Override - protected void paintComponent(Graphics g) { - g.setClip(Toolkit.createRoundRect(0, 0, - getWidth(), getHeight(), - temp == 0 ? 6 : 0, - temp == 3 ? 6 : 0, - 0, 0)); - super.paintComponent(g); - } - }; - tabLabels[i].setForeground(Color.WHITE); - tabLabels[i].setBackground(new Color(0x2d4251)); - tabLabels[i].setOpaque(true); - tabLabels[i].setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); - tabLabels[i].setPreferredSize(new Dimension(TAB_WIDTH, TAB_HEIGHT)); - tabLabels[i].setHorizontalAlignment(SwingConstants.CENTER); - tabLabels[i].setFont(Toolkit.getSansFont(14, Font.BOLD)); - tabbedPane.setTabComponentAt(i, tabLabels[i]); - } - */ - - /* - updateTabPanel = new JPanel() { - @Override - protected void paintComponent(Graphics g) { - g.setClip(Toolkit.createRoundRect(0, 0, getWidth(), getHeight(), - 6, 6, 0, 0)); - super.paintComponent(g); - } - };; - updateTabLabel = new JLabel("Updates"); - updateTabLabel.setFont(Toolkit.getSansFont(14, Font.BOLD)); - numberLabel.setVerticalTextPosition(SwingConstants.CENTER); - numberLabel.setHorizontalTextPosition(SwingConstants.CENTER); - numberLabel.setFont(Toolkit.getSansFont(14, Font.BOLD)); - numberLabel.setForeground(Color.WHITE); - updateTabPanel.setOpaque(true); - updateTabPanel.setBackground(new Color(0x2d4251)); - updateTabLabel.setForeground(Color.WHITE); - updateTabPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); - updateTabPanel.setPreferredSize(new Dimension(TAB_WIDTH, TAB_HEIGHT)); - tabbedPane.setTabComponentAt(4, updateTabPanel); - */ - - /* - GroupLayout tabLayout = new GroupLayout(updateTabPanel); - tabLayout.setAutoCreateGaps(true); - updateTabPanel.setLayout(tabLayout); - tabLayout.setHorizontalGroup(tabLayout - .createSequentialGroup() - .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, - GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) - .addComponent(updateTabLabel) - .addComponent(numberLabel) - .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, - GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)); - tabLayout.setVerticalGroup(tabLayout - .createParallelGroup(GroupLayout.Alignment.CENTER) - .addComponent(numberLabel).addComponent(updateTabLabel)); - - numberLabel.setVisible(false); - */ - - /* - tabbedPane.addChangeListener(new ChangeListener() { - - @Override - public void stateChanged(ChangeEvent e) { - for(int i = 0 ; i < 4; i++){ - tabLabels[i].setBackground(new Color(0x2d4251)); - tabLabels[i].setForeground(Color.WHITE); - } - updateTabPanel.setBackground(new Color(0x2d4251)); - updateTabLabel.setForeground(Color.WHITE); - int currentIndex = tabbedPane.getSelectedIndex(); - if(currentIndex != 4){ - tabbedPane.getTabComponentAt(tabbedPane.getSelectedIndex()).setBackground(new Color(0xe0fffd)); - tabbedPane.getTabComponentAt(tabbedPane.getSelectedIndex()).setForeground(Color.BLACK); - }else{ - updateTabPanel.setBackground(new Color(0xe0fffd)); - updateTabLabel.setForeground(Color.BLACK); - } - getActiveTab().contributionListPanel.scrollPane.requestFocusInWindow(); - } - }); - */ - frame.setResizable(true); -// tabbedPane.setBorder(new EmptyBorder(BORDER, BORDER, BORDER, BORDER)); Container c = frame.getContentPane(); c.add(tabs); @@ -255,73 +129,7 @@ public void stateChanged(ChangeEvent e) { */ protected void disposeFrame() { frame.dispose(); -// editor = null; - } - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - /* - private class SpacedTabbedPaneUI extends BasicTabbedPaneUI { - - @Override - protected void installDefaults() { - UIManager.put("TabbedPane.selected", Color.BLACK); - UIManager.put("TabbedPane.tabsOverlapBorder" , true); - super.installDefaults(); - tabInsets = new Insets(0, 0, 0, 0); - contentBorderInsets = new Insets(0, 0, 0, 0); - tabAreaInsets = new Insets(0, 0, 0, 0); - selectedTabPadInsets = new Insets(0, 0, 0, 0); - } - - - @Override - protected int getTabLabelShiftY(int tabPlacement, int tabIndex, - boolean isSelected) { - return 1; - } - - - @Override - protected void paintTabBackground(Graphics g, int tabPlacement, - int tabIndex, int x, int y, int w, int h, - boolean isSelected) { - } - - - @Override - protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, - int x, int y, int w, int h, boolean isSelected) { - } - - - @Override - protected void paintFocusIndicator(Graphics g, int tabPlacement, - Rectangle[] rects, int tabIndex, - Rectangle iconRect, Rectangle textRect, - boolean isSelected) { - } - - - @Override - protected LayoutManager createLayoutManager() { - return new BasicTabbedPaneUI.TabbedPaneLayout() { - - @Override - protected void calculateTabRects(int tabPlacement, int tabCount) { - super.calculateTabRects(tabPlacement, tabCount); - rects[0].x -= 2; - rects[1].x -= 1; - rects[2].x -= 1; - rects[3].x -= 1; - rects[4].x = tabbedPane.getWidth() - rects[4].width + 1; - } - }; - } } - */ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -420,19 +228,5 @@ protected ContributionTab getTab(ContributionType contributionType) { ContributionTab getActiveTab() { return (ContributionTab) tabs.getPanel(); - /* - switch (tabbedPane.getSelectedIndex()) { - case 0: - return librariesTab; - case 1: - return modesTab; - case 2: - return toolsTab; - case 3: - return examplesTab; - default: - return updatesTab; - } - */ } } diff --git a/app/src/processing/app/contrib/ManagerTabs.java b/app/src/processing/app/contrib/ManagerTabs.java index ad986a24a8..8cc1e5d331 100644 --- a/app/src/processing/app/contrib/ManagerTabs.java +++ b/app/src/processing/app/contrib/ManagerTabs.java @@ -48,26 +48,24 @@ */ public class ManagerTabs extends Box { // height of this tab bar - static final int HIGH = 34; -// static final int HIGH = 29; + static final int HIGH = Toolkit.zoom(34); // amount of space around the entire window - static final int BORDER = 8; -// static final int BORDER = 12; + static final int BORDER = Toolkit.zoom(8); - static final int CURVE_RADIUS = 6; + static final int CURVE_RADIUS = Toolkit.zoom(6); - static final int TAB_TOP = 0; - static final int TAB_BOTTOM = HIGH - 2; + static final int TAB_TOP = Toolkit.zoom(0); + static final int TAB_BOTTOM = HIGH - Toolkit.zoom(2); // amount of extra space between individual tabs - static final int TAB_BETWEEN = 2; //4; + static final int TAB_BETWEEN = Toolkit.zoom(2); // amount of margin on the left/right for the text on the tab - static final int MARGIN = 14; + static final int MARGIN = Toolkit.zoom(14); - static final int ICON_WIDTH = 16; - static final int ICON_HEIGHT = 16; - static final int ICON_TOP = 7; - static final int ICON_MARGIN = 7; + static final int ICON_WIDTH = Toolkit.zoom(16); + static final int ICON_HEIGHT = Toolkit.zoom(16); + static final int ICON_TOP = Toolkit.zoom(7); + static final int ICON_MARGIN = Toolkit.zoom(7); static final int UNSELECTED = 0; static final int SELECTED = 1; @@ -109,7 +107,7 @@ public ManagerTabs(Base base) { tabColor[SELECTED] = mode.getColor("manager.tab.selected.color"); tabColor[UNSELECTED] = mode.getColor("manager.tab.unselected.color"); - gradient = mode.makeGradient("manager.tab", 400, HIGH); + gradient = mode.makeGradient("manager.tab", Toolkit.zoom(400), HIGH); setBorder(new EmptyBorder(BORDER, BORDER, BORDER, BORDER)); @@ -217,11 +215,7 @@ public void paintComponent(Graphics screen) { sizeH = size.height; imageW = sizeW; imageH = sizeH; - if (Toolkit.highResDisplay()) { - offscreen = createImage(imageW*2, imageH*2); - } else { - offscreen = createImage(imageW, imageH); - } + offscreen = Toolkit.offscreenGraphics(this, imageW, imageH); } Graphics g = offscreen.getGraphics(); @@ -235,7 +229,9 @@ public void paintComponent(Graphics screen) { g.drawImage(gradient, 0, 0, imageW, imageH, this); g.setColor(tabColor[SELECTED]); - g.fillRect(0, TAB_BOTTOM, imageW, 2); + // draw the two pixel line that extends left/right below the tabs + // can't be done with lines, b/c retina leaves tiny hairlines + g.fillRect(0, TAB_BOTTOM, imageW, Toolkit.zoom(2)); // reset all tab positions for (Tab tab : tabList) { @@ -243,16 +239,10 @@ public void paintComponent(Graphics screen) { font.getStringBounds(tab.name, g2.getFontRenderContext()).getWidth(); } - placeTabs(0); //Editor.LEFT_GUTTER); + placeTabs(0); // now actually draw the tabs drawTabs(g2); -// // draw the two pixel line that extends left/right below the tabs -// g.setColor(tabColor[SELECTED]); -// // can't be done with lines, b/c retina leaves tiny hairlines -// g.fillRect(Editor.LEFT_GUTTER, TAB_BOTTOM, -// editor.getTextArea().getWidth() - Editor.LEFT_GUTTER, 2); - screen.drawImage(offscreen, 0, 0, imageW, imageH, null); } diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java index d24f70b677..0005de2478 100644 --- a/app/src/processing/app/contrib/ModeContribution.java +++ b/app/src/processing/app/contrib/ModeContribution.java @@ -129,15 +129,6 @@ public ContributionType getType() { } - public boolean equals(Object o) { - if (o == null || !(o instanceof ModeContribution)) { - return false; - } - ModeContribution other = (ModeContribution) o; - return loader.equals(other.loader) && mode.equals(other.getMode()); - } - - public String initLoader(Base base, String className) throws Exception { File modeDirectory = new File(folder, getTypeName()); if (modeDirectory.exists()) { @@ -219,4 +210,4 @@ public String initLoader(Base base, String className) throws Exception { } return className; } -} \ No newline at end of file +} diff --git a/app/src/processing/app/contrib/StatusPanel.java b/app/src/processing/app/contrib/StatusPanel.java index 57d5ce5aa6..4c25c5ec1e 100644 --- a/app/src/processing/app/contrib/StatusPanel.java +++ b/app/src/processing/app/contrib/StatusPanel.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-16 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -45,7 +45,7 @@ class StatusPanel extends JPanel { - static final int BUTTON_WIDTH = 150; + static final int BUTTON_WIDTH = Toolkit.zoom(150); static Icon foundationIcon; static Icon installIcon; @@ -79,7 +79,7 @@ public StatusPanel(final ContributionTab contributionTab, int width) { installIcon = Toolkit.getLibIconX("manager/install"); updateIcon = Toolkit.getLibIconX("manager/update"); removeIcon = Toolkit.getLibIconX("manager/remove"); - buttonFont = Toolkit.getSansFont(14, Font.PLAIN); + buttonFont = ManagerFrame.NORMAL_PLAIN; } setBackground(new Color(0xebebeb)); @@ -104,8 +104,8 @@ public void hyperlinkUpdate(HyperlinkEvent e) { } } }); - installButton = new JButton("Install", installIcon); - installButton.setDisabledIcon(installIcon); + installButton = Toolkit.createIconButton("Install", installIcon); + //installButton.setDisabledIcon(installIcon); installButton.setFont(buttonFont); installButton.setHorizontalAlignment(SwingConstants.LEFT); installButton.addActionListener(new ActionListener() { @@ -126,8 +126,7 @@ public void actionPerformed(ActionEvent e) { updateLabel.setFont(buttonFont); updateLabel.setHorizontalAlignment(SwingConstants.CENTER); - updateButton = new JButton("Update", updateIcon); - updateButton.setDisabledIcon(updateIcon); + updateButton = Toolkit.createIconButton("Update", updateIcon); updateButton.setFont(buttonFont); updateButton.setHorizontalAlignment(SwingConstants.LEFT); updateButton.addActionListener(new ActionListener() { @@ -140,8 +139,7 @@ public void actionPerformed(ActionEvent e) { } }); - removeButton = new JButton("Remove", removeIcon); - removeButton.setDisabledIcon(removeIcon); + removeButton = Toolkit.createIconButton("Remove", removeIcon); removeButton.setFont(buttonFont); removeButton.setHorizontalAlignment(SwingConstants.LEFT); removeButton.addActionListener(new ActionListener() { @@ -249,22 +247,34 @@ public void update(DetailPanel panel) { !panel.updateInProgress); String latestVersion = - contributionListing.getLatestVersion(panel.getContrib()); + contributionListing.getLatestPrettyVersion(panel.getContrib()); String currentVersion = panel.getContrib().getPrettyVersion(); - installButton.setEnabled(!panel.getContrib().isInstalled() - && contributionListing.hasDownloadedLatestList() - && panel.getContrib().isCompatible(Base.getRevision()) - && !panel.installInProgress); + installButton.setEnabled(!panel.getContrib().isInstalled() && + contributionListing.hasDownloadedLatestList() && + panel.getContrib().isCompatible(Base.getRevision()) && + !panel.installInProgress); if (panel.getContrib().isCompatible(Base.getRevision())) { if (installButton.isEnabled()) { - updateLabel.setText(latestVersion + " available"); + if (latestVersion != null) { + updateLabel.setText(latestVersion + " available"); + } else { + updateLabel.setText("Available"); + } } else { - updateLabel.setText(currentVersion + " installed"); + if (currentVersion != null) { + updateLabel.setText(currentVersion + " installed"); + } else { + updateLabel.setText("Installed"); + } } } else { - updateLabel.setText(currentVersion + " not compatible"); + if (currentVersion != null) { + updateLabel.setText(currentVersion + " not compatible"); + } else { + updateLabel.setText("Not compatible"); + } } if (latestVersion != null) { @@ -273,18 +283,13 @@ public void update(DetailPanel panel) { latestVersion = "Update"; } - if (currentVersion == null) { - currentVersion = ""; - } - if (updateButton.isEnabled()) { updateButton.setText(latestVersion); } else { updateButton.setText("Update"); } - removeButton.setEnabled(panel.getContrib().isInstalled() - && !panel.removeInProgress); + removeButton.setEnabled(panel.getContrib().isInstalled() && !panel.removeInProgress); progressPanel.add(panel.installProgressBar); progressPanel.setVisible(false); updateLabel.setVisible(true); diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java index b3af82bf76..a9afc7f291 100644 --- a/app/src/processing/app/contrib/ToolContribution.java +++ b/app/src/processing/app/contrib/ToolContribution.java @@ -63,7 +63,7 @@ private ToolContribution(File folder) throws Throwable { String className = initLoader(null); if (className != null) { Class toolClass = loader.loadClass(className); - tool = (Tool) toolClass.newInstance(); + tool = (Tool) toolClass.getDeclaredConstructor().newInstance(); } referenceFile = new File(folder, "reference/index.html"); @@ -95,7 +95,7 @@ public void clearClassLoader() { static public List loadAll(File toolsFolder) { File[] list = ContributionType.TOOL.listCandidates(toolsFolder); - ArrayList outgoing = new ArrayList(); + ArrayList outgoing = new ArrayList<>(); // If toolsFolder does not exist or is inaccessible (stranger things have // happened, and are reported as bugs) list will come back null. if (list != null) { diff --git a/app/src/processing/app/contrib/UpdateContributionTab.java b/app/src/processing/app/contrib/UpdateContributionTab.java index af4a8d2884..a3de07f389 100644 --- a/app/src/processing/app/contrib/UpdateContributionTab.java +++ b/app/src/processing/app/contrib/UpdateContributionTab.java @@ -11,18 +11,18 @@ public class UpdateContributionTab extends ContributionTab { - public UpdateContributionTab(ManagerFrame dialog, ContributionType type) { + public UpdateContributionTab(ManagerFrame dialog) { super(); this.contribDialog = dialog; - this.contribType = type; - - filter = new Contribution.Filter() { - public boolean matches(Contribution contrib) { - if (contrib instanceof LocalContribution) { - return ContributionListing.getInstance().hasUpdates(contrib); - } - return false; + + filter = contrib -> { + if (contrib instanceof ListPanel.SectionHeaderContribution) { + return true; + } + if (contrib instanceof LocalContribution) { + return ContributionListing.getInstance().hasUpdates(contrib); } + return false; }; contributionListPanel = new UpdateListPanel(this, filter); // contributionListPanel.setBorder(new EmptyBorder(8, 8, 8, 8)); @@ -67,4 +67,9 @@ protected void setLayout(boolean error, boolean loading) { setBackground(Color.WHITE); } + + @Override + public void updateStatusPanel(DetailPanel contributionPanel) { + // Do nothing + } } diff --git a/app/src/processing/app/contrib/UpdateListPanel.java b/app/src/processing/app/contrib/UpdateListPanel.java index d03216a079..6ade2e439a 100644 --- a/app/src/processing/app/contrib/UpdateListPanel.java +++ b/app/src/processing/app/contrib/UpdateListPanel.java @@ -1,248 +1,50 @@ package processing.app.contrib; -import java.awt.Color; -import java.awt.Component; -import java.awt.EventQueue; -import java.awt.Font; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeMap; - -import javax.swing.BorderFactory; -import javax.swing.GroupLayout; -import javax.swing.Icon; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellRenderer; - -import processing.app.Base; -import processing.app.ui.Toolkit; - - public class UpdateListPanel extends ListPanel { - static final Color SECTION_COLOR = new Color(0xFFf8f8f8); - static final String[] PLURAL_TYPES = { - ContributionType.LIBRARY.getPluralTitle(), - ContributionType.MODE.getPluralTitle(), - ContributionType.TOOL.getPluralTitle(), - ContributionType.EXAMPLES.getPluralTitle(), - }; - Set sectionNames = new HashSet(Arrays.asList(PLURAL_TYPES)); - - public UpdateListPanel(ContributionTab contributionTab, - Contribution.Filter filter) { - this.contributionTab = contributionTab; - this.filter = filter; - - setOpaque(true); - setBackground(Color.WHITE); - - model = new DefaultTableModel() { - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - @Override - public Class getColumnClass(int columnIndex) { - return (columnIndex == 0) ? Icon.class : String.class; - } - }; - - model.setColumnIdentifiers(new String[] { - "", "Name", "Author", "Installed", "Available" - }); - - table = new JTable(model) { - @Override - public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { - Component c = super.prepareRenderer(renderer, row, column); - String title = (String) getValueAt(row, 1); - if (sectionNames.contains(title)) { - c.setBackground(SECTION_COLOR); - } else { - c.setBackground(Color.WHITE); - } - return c; - } - - @Override - public void changeSelection(int rowIndex, int columnIndex, - boolean toggle, boolean extend) { - String title = (String) getValueAt(rowIndex, 1); - // Disallow selection on the fake rows - if (!sectionNames.contains(title)) { - super.changeSelection(rowIndex, columnIndex, toggle, extend); - } - } - }; - - scrollPane = new JScrollPane(table); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - - table.setFillsViewportHeight(true); - table.setSelectionBackground(new Color(0xe0fffd)); - table.setSelectionForeground(table.getForeground()); - table.setFont(Toolkit.getSansFont(14, Font.PLAIN)); - table.setRowHeight(30); - table.setRowMargin(6); - table.getColumnModel().setColumnMargin(-1); - table.getColumnModel().getColumn(0).setMaxWidth(60); - table.setShowGrid(false); - table.setCellSelectionEnabled(false); - table.setRowSelectionAllowed(true); - table.setAutoCreateColumnsFromModel(true); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - table.setDefaultRenderer(String.class, new DefaultTableCellRenderer() { - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, - int row, int column) { - return super.getTableCellRendererComponent(table, value, isSelected, - false, row, column); - } - }); + Contribution.Filter contribFilter; - table.getTableHeader().setDefaultRenderer(new ContribHeaderRenderer()); /* { - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, int row, - int column) { - super.getTableCellRendererComponent(table, value, isSelected, - hasFocus, row, column); - JTableHeader tableHeader = table.getTableHeader(); - if (tableHeader != null) { - setForeground(tableHeader.getForeground()); - } - setIcon(getSortIcon(table, column)); - setBackground(new Color(0xebebeb)); - return this; - } - });*/ - - GroupLayout layout = new GroupLayout(this); - layout.setHorizontalGroup(layout.createParallelGroup().addComponent(scrollPane)); - layout.setVerticalGroup(layout.createSequentialGroup().addComponent(scrollPane)); - - setLayout(layout); - table.setVisible(true); - - panelByContribution = new TreeMap(new Comparator() { - @Override - public int compare(Contribution o1, Contribution o2) { - int diff = - ContributionManager.getTypeIndex(o1.getType()) - - ContributionManager.getTypeIndex(o2.getType()); - if (diff == 0) { - diff = o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); - } - return diff; - } - }); + public UpdateListPanel(ContributionTab contributionTab, + Contribution.Filter contribFilter) { + super(contributionTab, contribFilter, true, + ContributionColumn.STATUS_NO_HEADER, + ContributionColumn.NAME, + ContributionColumn.AUTHOR, + ContributionColumn.INSTALLED_VERSION, + ContributionColumn.AVAILABLE_VERSION); + + this.contribFilter = contribFilter; + table.getTableHeader().setEnabled(false); } + // Thread: EDT @Override - void updatePanelOrdering(Set contributionsSet) { -// int updateCount = panelByContribution.size(); -// new Exception("update count is " + updateCount).printStackTrace(System.out); -// (UpdateContributionTab) contributionTab - - model.getDataVector().removeAllElements(); - model.fireTableDataChanged(); - ContributionType currentType = null; - - // Avoid ugly synthesized bold - Font boldFont = Toolkit.getSansFont(table.getFont().getSize(), Font.BOLD); - String fontFace = ""; - - for (Contribution entry : contributionsSet) { - if (entry.getType() != currentType) { - currentType = entry.getType(); - model.addRow(new Object[] { - null, currentType.getPluralTitle(), null, null, null - }); - } - //TODO Make this into a function - StringBuilder name = new StringBuilder(""); - String authorList = entry.getAuthorList(); - if (authorList != null) { - for (int i = 0; i < authorList.length(); i++) { - if (authorList.charAt(i) == '[' || authorList.charAt(i) == ']') { - continue; - } - if (authorList.charAt(i) == '(') { - i++; - while (authorList.charAt(i) != ')') { - i++; - } - } else { - name.append(authorList.charAt(i)); - } - } - } - Icon icon = null; - if (entry.isInstalled()) { - icon = upToDateIcon; - if (contribListing.hasUpdates(entry)) { - icon = updateAvailableIcon; - } - if (!entry.isCompatible(Base.getRevision())) { - icon = incompatibleIcon; - } - } - if ((panelByContribution.get(entry)).updateInProgress || - (panelByContribution.get(entry)).installInProgress) { - // Display "Loading icon" if download/install in progress - icon = downloadingIcon; - } - model.addRow(new Object[] { - icon, - "" + fontFace + entry.getName() + "", - name, - entry.getPrettyVersion(), - contributionTab.contribListing.getLatestVersion(entry) - }); + public void contributionAdded(final Contribution contribution) { + // Ensures contributionAdded in ListPanel is only run on LocalContributions + if (contribFilter.matches(contribution)) { + super.contributionAdded(contribution); + ((UpdateStatusPanel) contributionTab.statusPanel).update(); // Enables update button } - UpdateContributionTab tab = (UpdateContributionTab) contributionTab; - ((UpdateStatusPanel) tab.statusPanel).update(); } + // Thread: EDT + @Override + public void contributionRemoved(final Contribution contribution) { + super.contributionRemoved(contribution); + ((UpdateStatusPanel) contributionTab.statusPanel).update(); // Disables update button on last contribution + } + // Thread: EDT @Override - public void contributionAdded(final Contribution contribution) { - if (filter.matches(contribution)) { - // TODO: this should already be on EDT, check it [jv] - EventQueue.invokeLater(new Runnable() { - public void run() { - // TODO make this longer and more contorted [fry] - DetailPanel newPanel = - contributionTab.contribDialog.getTab(contribution.getType()).contributionListPanel.panelByContribution.get(contribution); - if (newPanel == null) { - newPanel = new DetailPanel(UpdateListPanel.this); - } - synchronized (panelByContribution) { - if (!panelByContribution.containsKey(contribution)) { - panelByContribution.put(contribution, newPanel); - } - if (newPanel != null) { - newPanel.setContribution(contribution); - add(newPanel); - updatePanelOrdering(panelByContribution.keySet()); - updateColors(); // XXX this is the place - } - } - } - }); + public void contributionChanged(final Contribution oldContrib, + final Contribution newContrib) { + DetailPanel panel = panelByContribution.get(oldContrib); + if (panel == null) { + contributionAdded(newContrib); + } else if (newContrib.isInstalled()) { + panelByContribution.remove(oldContrib); } + model.fireTableDataChanged(); } -} \ No newline at end of file + +} diff --git a/app/src/processing/app/contrib/UpdateStatusPanel.java b/app/src/processing/app/contrib/UpdateStatusPanel.java index d8aef30e62..f91db9fbd5 100644 --- a/app/src/processing/app/contrib/UpdateStatusPanel.java +++ b/app/src/processing/app/contrib/UpdateStatusPanel.java @@ -1,25 +1,44 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013-16 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ package processing.app.contrib; import java.awt.Color; -import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout; -import javax.swing.JButton; import javax.swing.LayoutStyle; import javax.swing.SwingConstants; import processing.app.ui.Toolkit; + public class UpdateStatusPanel extends StatusPanel { public UpdateStatusPanel(UpdateContributionTab tab, int width) { super(); this.contributionTab = tab; - updateButton = new JButton("Update All", Toolkit.getLibIconX("manager/update")); - updateButton.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + updateButton = Toolkit.createIconButton("Update All", "manager/update"); + updateButton.setFont(ManagerFrame.NORMAL_PLAIN); updateButton.setHorizontalAlignment(SwingConstants.LEFT); updateButton.setVisible(true); updateButton.setEnabled(false); @@ -48,6 +67,7 @@ public void actionPerformed(ActionEvent e) { .addComponent(updateButton)); } + public void update() { updateButton.setEnabled(contributionTab.hasUpdates()); } diff --git a/app/src/processing/app/exec/StreamRedirectThread.java b/app/src/processing/app/exec/StreamRedirectThread.java index c3140d872c..ee6d7ed006 100644 --- a/app/src/processing/app/exec/StreamRedirectThread.java +++ b/app/src/processing/app/exec/StreamRedirectThread.java @@ -7,13 +7,13 @@ */ /* * Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved. - * + * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR @@ -25,7 +25,7 @@ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. - * + * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear @@ -50,7 +50,7 @@ public class StreamRedirectThread extends Thread { private static final int BUFFER_SIZE = 2048; - + /** * Set up for copy. * @param name Name of the thread @@ -63,15 +63,15 @@ public StreamRedirectThread(String name, InputStream in, OutputStream out) { this.out = new OutputStreamWriter(out); setPriority(Thread.MAX_PRIORITY-1); } - - + + public StreamRedirectThread(String name, Reader in, Writer out) { super(name); this.in = in; this.out = out; setPriority(Thread.MAX_PRIORITY-1); } - + /** * Copy. @@ -80,16 +80,15 @@ public void run() { try { char[] cbuf = new char[BUFFER_SIZE]; int count; - //System.out.println("opening streamredirectthread"); while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) { out.write(cbuf, 0, count); // had to add the flush() here.. maybe shouldn't be using writer? [fry] out.flush(); } - //System.out.println("exiting streamredirectthread"); out.flush(); - } catch(IOException exc) { - System.err.println("Child I/O Transfer - " + exc); + + } catch (IOException exc) { + processing.app.Console.systemErr("Child I/O Transfer - " + exc); } } } diff --git a/app/src/processing/app/platform/DefaultPlatform.java b/app/src/processing/app/platform/DefaultPlatform.java index f3b47425b3..58529b516f 100644 --- a/app/src/processing/app/platform/DefaultPlatform.java +++ b/app/src/processing/app/platform/DefaultPlatform.java @@ -153,4 +153,12 @@ public int unsetenv(String variable) { CLibrary clib = CLibrary.INSTANCE; return clib.unsetenv(variable); } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public int getSystemDPI() { + return 96; + } } diff --git a/app/src/processing/app/platform/LinuxPlatform.java b/app/src/processing/app/platform/LinuxPlatform.java index cf539fdb60..7bc7297246 100644 --- a/app/src/processing/app/platform/LinuxPlatform.java +++ b/app/src/processing/app/platform/LinuxPlatform.java @@ -23,15 +23,18 @@ package processing.app.platform; import java.io.File; +import java.awt.Desktop; import java.awt.Toolkit; import processing.app.Base; import processing.app.Messages; import processing.app.Preferences; -import processing.app.platform.DefaultPlatform; +import processing.core.PApplet; public class LinuxPlatform extends DefaultPlatform { + String homeDir; + public void initBase(Base base) { super.initBase(base); @@ -67,16 +70,61 @@ public void initBase(Base base) { } - public void openURL(String url) throws Exception { - if (openFolderAvailable()) { - String launcher = Preferences.get("launcher"); - if (launcher != null) { - Runtime.getRuntime().exec(new String[] { launcher, url }); + // The default Look & Feel is set in preferences.txt + // As of 3.0a6, defaults.txt is set to Nimbus for Linux. + + + // Java sets user.home to be /root for execution with sudo. + // This method attempts to use the user's real home directory instead. + public String getHomeDir() { + if (homeDir == null) { + // get home directory of SUDO_USER if set, else use user.home + homeDir = System.getProperty("user.home"); + String sudoUser = System.getenv("SUDO_USER"); + if (sudoUser != null && sudoUser.length() != 0) { + try { + homeDir = getHomeDir(sudoUser); + } catch (Exception e) { } } } + return homeDir; + } + + + static public String getHomeDir(String user) throws Exception { + Process p = PApplet.exec("/bin/sh", "-c", "echo ~" + user); + return PApplet.createReader(p.getInputStream()).readLine(); + } + + + @Override + public File getSettingsFolder() throws Exception { + return new File(getHomeDir(), ".processing"); + } + + + @Override + public File getDefaultSketchbookFolder() throws Exception { + return new File(getHomeDir(), "sketchbook"); + } + + + @Override + public void openURL(String url) throws Exception { + if (Desktop.isDesktopSupported()) { + super.openURL(url); + + } else if (openFolderAvailable()) { + String launcher = Preferences.get("launcher"); // guaranteed non-null + Runtime.getRuntime().exec(new String[] { launcher, url }); + + } else { + System.err.println("No launcher set, cannot open " + url); + } } + @Override public boolean openFolderAvailable() { if (Preferences.get("launcher") != null) { return true; @@ -111,19 +159,18 @@ public boolean openFolderAvailable() { } + @Override public void openFolder(File file) throws Exception { - if (openFolderAvailable()) { - String lunch = Preferences.get("launcher"); - try { - String[] params = new String[] { lunch, file.getAbsolutePath() }; - //processing.core.PApplet.println(params); - /*Process p =*/ Runtime.getRuntime().exec(params); - /*int result =*/ //p.waitFor(); - } catch (Exception e) { - e.printStackTrace(); - } + if (Desktop.isDesktopSupported()) { + super.openFolder(file); + + } else if (openFolderAvailable()) { + String launcher = Preferences.get("launcher"); + String[] params = new String[] { launcher, file.getAbsolutePath() }; + Runtime.getRuntime().exec(params); + } else { - System.out.println("No launcher set, cannot open " + + System.err.println("No launcher set, cannot open " + file.getAbsolutePath()); } } diff --git a/app/src/processing/app/platform/MacPlatform.java b/app/src/processing/app/platform/MacPlatform.java index 8fab34e6d7..02474a3942 100644 --- a/app/src/processing/app/platform/MacPlatform.java +++ b/app/src/processing/app/platform/MacPlatform.java @@ -22,15 +22,16 @@ package processing.app.platform; +import java.awt.Desktop; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URI; import com.apple.eio.FileManager; import processing.app.Base; import processing.app.Messages; -import processing.app.platform.DefaultPlatform; /** @@ -62,6 +63,7 @@ public void saveLanguage(String language) { } } + public void initBase(Base base) { super.initBase(base); System.setProperty("apple.laf.useScreenMenuBar", "true"); @@ -127,6 +129,21 @@ public File getDefaultSketchbookFolder() throws Exception { // } + public void openURL(String url) throws Exception { + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (IOException e) { + // Deal with a situation where the browser hangs on macOS + // https://github.com/fathominfo/processing-p5js-mode/issues/4 + if (e.getMessage().contains("Error code: -600")) { + throw new RuntimeException("Could not open the sketch, please restart your browser or computer"); + } else { + throw e; + } + } + } + + /* public void openURL(String url) throws Exception { if (PApplet.javaVersion < 1.6f) { diff --git a/app/src/processing/app/platform/WindowsPlatform.java b/app/src/processing/app/platform/WindowsPlatform.java index c19d14a1a1..3c4759a375 100644 --- a/app/src/processing/app/platform/WindowsPlatform.java +++ b/app/src/processing/app/platform/WindowsPlatform.java @@ -28,8 +28,11 @@ import com.sun.jna.Library; import com.sun.jna.Native; +import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Shell32Util; import com.sun.jna.platform.win32.ShlObj; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIOptions; import processing.app.Base; import processing.app.Messages; @@ -40,12 +43,22 @@ import processing.core.PApplet; +// With the changes to include .pyde files for 3.4, this class is +// a bit of a mess. Registering a single extension has moved to +// registerExtension(), however that method, and the checkAssociations() +// method now have too much duplicated effort, which isn't great, +// but more importantly, makes it hard to follow what's going on. +// At some point, checkAssociations() and setAssociations() can probably +// be merged, or at least turned into cleaner methods that don't re-do +// one another's work, but I haven't time today. [fry 180326] + /** * Platform-specific glue for Windows. */ public class WindowsPlatform extends DefaultPlatform { static final String APP_NAME = "Processing"; + static final String[] APP_EXTENSIONS = { ".pde", ".pyde" }; static final String REG_OPEN_COMMAND = System.getProperty("user.dir").replace('/', '\\') + "\\" + APP_NAME.toLowerCase() + ".exe \"%1\""; @@ -136,10 +149,18 @@ protected void checkAssociations() { // Check the key that should be set by a previous run of Processing String knownCommand = WindowsRegistry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, - "Software\\Classes\\" + REG_DOC + "\\shell\\open\\command", ""); + "Software\\Classes\\" + REG_DOC + "\\shell\\open\\command", ""); // If the association hasn't been set, or it's not correct, set it. if (knownCommand == null || !knownCommand.equals(REG_OPEN_COMMAND)) { setAssociations(); + + } else { // check each extension + for (String extension : APP_EXTENSIONS) { + if (!WindowsRegistry.valueExists(REGISTRY_ROOT_KEY.CURRENT_USER, + "Software\\Classes", extension)) { + setAssociations(); + } + } } } } catch (Exception e) { @@ -189,33 +210,36 @@ protected void setAssociations() throws UnsupportedEncodingException { openCommand)) { */ + // First create the .pde association + for (String extension : APP_EXTENSIONS) { + if (!registerExtension(extension)) { + Messages.log("Could not associate " + extension + "files, " + + "turning off auto-associate pref."); + Preferences.setBoolean("platform.auto_file_type_associations", false); + } + } + } + + + private boolean registerExtension(String extension) throws UnsupportedEncodingException { // "To change the settings for the interactive user, store the changes // under HKEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT." // msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx final REGISTRY_ROOT_KEY rootKey = REGISTRY_ROOT_KEY.CURRENT_USER; final String docPrefix = "Software\\Classes\\" + REG_DOC; - // First create the .pde association - if (WindowsRegistry.createKey(rootKey, "Software\\Classes", ".pde") && - WindowsRegistry.setStringValue(rootKey, "Software\\Classes\\.pde", "", REG_DOC) && - - // Now give files with a .pde extension a name for the explorer - WindowsRegistry.createKey(rootKey, "Software\\Classes", REG_DOC) && - WindowsRegistry.setStringValue(rootKey, docPrefix, "", APP_NAME + " Source Code") && - - // Now associate the 'open' command with the current processing.exe - WindowsRegistry.createKey(rootKey, docPrefix, "shell") && - WindowsRegistry.createKey(rootKey, docPrefix + "\\shell", "open") && - WindowsRegistry.createKey(rootKey, docPrefix + "\\shell\\open", "command") && - WindowsRegistry.setStringValue(rootKey, docPrefix + "\\shell\\open\\command", "", REG_OPEN_COMMAND)) { + return (WindowsRegistry.createKey(rootKey, "Software\\Classes", extension) && + WindowsRegistry.setStringValue(rootKey, "Software\\Classes\\" + extension, "", REG_DOC) && - // everything ok - // hooray! + // Now give files with a .pde extension a name for the explorer + WindowsRegistry.createKey(rootKey, "Software\\Classes", REG_DOC) && + WindowsRegistry.setStringValue(rootKey, docPrefix, "", APP_NAME + " Source Code") && - } else { - Messages.log("Could not associate files, turning off auto-associate pref."); - Preferences.setBoolean("platform.auto_file_type_associations", false); - } + // Now associate the 'open' command with the current processing.exe + WindowsRegistry.createKey(rootKey, docPrefix, "shell") && + WindowsRegistry.createKey(rootKey, docPrefix + "\\shell", "open") && + WindowsRegistry.createKey(rootKey, docPrefix + "\\shell\\open", "command") && + WindowsRegistry.setStringValue(rootKey, docPrefix + "\\shell\\open\\command", "", REG_OPEN_COMMAND)); } @@ -602,56 +626,57 @@ public int unsetenv(String variable) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - // JNA code for using SHGetFolderPath to fix Issue 410 - // https://code.google.com/p/processing/issues/detail?id=410 - // Based on answer provided by McDowell at - // http://stackoverflow.com/questions/585534/what-is-the-best-way-to-find-the-users-home-directory-in-java/586917#586917 -// private static Map OPTIONS = new HashMap(); -// -// static { -// OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE); -// OPTIONS.put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE); -// } -// -// -// static class HANDLE extends PointerType implements NativeMapped { -// public HANDLE() { } -// } -// -// static class HWND extends HANDLE { } -// -// -// public interface Shell32 extends Library { -// -// public static final int MAX_PATH = 260; -// public static final int SHGFP_TYPE_CURRENT = 0; -// public static final int SHGFP_TYPE_DEFAULT = 1; -// public static final int S_OK = 0; -// -// // KNOWNFOLDERIDs are preferred to CSDIL values -// // but Windows XP only supports CSDIL so thats what we have to use -// public static final int CSIDL_APPDATA = 0x001a; // "Application Data" -// public static final int CSIDL_PERSONAL = 0x0005; // "My Documents" -// -// static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, OPTIONS); -// -// /** -// * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx -// * -// * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken, -// * DWORD dwFlags, LPTSTR pszPath); -// */ -// public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, -// int dwFlags, char[] pszPath); -// -// /** -// * This function can be used to copy, move, rename, -// * or delete a file system object. -// * @param fileop Address of an SHFILEOPSTRUCT structure that contains -// * information this function needs to carry out the specified operation. -// * @return Returns zero if successful, or nonzero otherwise. -// */ -// public int SHFileOperation(SHFILEOPSTRUCT fileop); -// } + // Need to extend com.sun.jna.platform.win32.User32 to access + // Win32 function GetDpiForSystem() + interface ExtUser32 extends StdCallLibrary, com.sun.jna.platform.win32.User32 { + ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary("user32", ExtUser32.class, W32APIOptions.DEFAULT_OPTIONS); + + public int GetDpiForSystem(); + + public int SetProcessDpiAwareness(int value); + + public final int DPI_AWARENESS_INVALID = -1; + public final int DPI_AWARENESS_UNAWARE = 0; + public final int DPI_AWARENESS_SYSTEM_AWARE = 1; + public final int DPI_AWARENESS_PER_MONITOR_AWARE = 2; + + public Pointer SetThreadDpiAwarenessContext(Pointer dpiContext); + + public final Pointer DPI_AWARENESS_CONTEXT_UNAWARE = new Pointer(-1); + public final Pointer DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = new Pointer(-2); + public final Pointer DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = new Pointer(-3); + } + + + static private int detected = detectSystemDPI(); + + + public int getSystemDPI() { + if (detected == -1) { + return super.getSystemDPI(); + } + return detected; + } + + + public static int detectSystemDPI() { + try { + ExtUser32.INSTANCE.SetProcessDpiAwareness(ExtUser32.DPI_AWARENESS_SYSTEM_AWARE); + } catch (Throwable e) { + // Ignore error + } + try { + ExtUser32.INSTANCE.SetThreadDpiAwarenessContext(ExtUser32.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); + } catch (Throwable e) { + // Ignore error (call valid only on Windows 10) + } + try { + return ExtUser32.INSTANCE.GetDpiForSystem(); + } catch (Throwable e) { + // DPI detection failed, fall back with default + System.out.println("DPI detection failed, fallback to 96 dpi"); + return -1; + } + } } diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index d2ef145a97..b63084c63a 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -594,8 +594,7 @@ public int lineToY(int line) { public int yToLine(int y) { FontMetrics fm = painter.getFontMetrics(); int height = fm.getHeight(); - return Math.max(0,Math.min(getLineCount() - 1, - y / height + firstLine)); + return Math.max(0, Math.min(getLineCount() - 1, y / height + firstLine)); } @@ -620,7 +619,7 @@ public final int offsetToX(int line, int offset) { * @param offset The offset, from the start of the line */ public int _offsetToX(int line, int offset) { - TokenMarker tokenMarker = getTokenMarker(); + TokenMarkerState tokenMarker = getTokenMarker(); // Use painter's cached info for speed FontMetrics fm = painter.getFontMetrics(); @@ -682,7 +681,7 @@ public int _offsetToX(int line, int offset) { * @param x The x co-ordinate */ public int xToOffset(int line, int x) { - TokenMarker tokenMarker = getTokenMarker(); + TokenMarkerState tokenMarker = getTokenMarker(); /* Use painter's cached info for speed */ FontMetrics fm = painter.getFontMetrics(); @@ -855,7 +854,7 @@ public void setDocument(SyntaxDocument document, * Returns the document's token marker. Equivalent to calling * getDocument().getTokenMarker(). */ - public final TokenMarker getTokenMarker() { + public final TokenMarkerState getTokenMarker() { return document.getTokenMarker(); } @@ -1033,8 +1032,10 @@ public final void getText(int start, int len, Segment segment) { try { document.getText(start,len,segment); - } catch(BadLocationException bl) { + } catch (BadLocationException bl) { bl.printStackTrace(); + System.err.format("Bad Location: %d for start %d and length %d", + bl.offsetRequested(), start, len); segment.offset = segment.count = 0; } } @@ -1580,13 +1581,14 @@ public void copy() { Clipboard clipboard = getToolkit().getSystemClipboard(); String selection = getSelectedText(); + if (selection != null) { + int repeatCount = inputHandler.getRepeatCount(); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < repeatCount; i++) + sb.append(selection); - int repeatCount = inputHandler.getRepeatCount(); - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < repeatCount; i++) - sb.append(selection); - - clipboard.setContents(new StringSelection(sb.toString()), null); + clipboard.setContents(new StringSelection(sb.toString()), null); + } } } @@ -1680,7 +1682,7 @@ private void emitAsHTML(StringBuilder cf, int line, SyntaxDocument doc) { int segmentOffset = segment.offset; int segmentCount = segment.count; - TokenMarker tokenMarker = doc.getTokenMarker(); + TokenMarkerState tokenMarker = doc.getTokenMarker(); // If syntax coloring is disabled, do simple translation if (tokenMarker == null) { for (int j = 0; j < segmentCount; j++) { diff --git a/app/src/processing/app/syntax/PdeTextAreaPainter.java b/app/src/processing/app/syntax/PdeTextAreaPainter.java index 290cdfc414..24232f23e1 100644 --- a/app/src/processing/app/syntax/PdeTextAreaPainter.java +++ b/app/src/processing/app/syntax/PdeTextAreaPainter.java @@ -113,7 +113,7 @@ public void setMode(Mode mode) { * @param x horizontal position */ @Override - protected void paintLine(Graphics gfx, int line, int x, TokenMarker marker) { + protected void paintLine(Graphics gfx, int line, int x, TokenMarkerState marker) { try { // TODO This line is causing NPEs randomly ever since I added the // toggle for Java Mode/Debugger toolbar. [Manindra] @@ -346,4 +346,4 @@ public Editor getEditor() { public PdeTextArea getPdeTextArea() { return (PdeTextArea) textArea; } -} \ No newline at end of file +} diff --git a/app/src/processing/app/syntax/SyntaxDocument.java b/app/src/processing/app/syntax/SyntaxDocument.java index 25b50d69a0..cead844394 100644 --- a/app/src/processing/app/syntax/SyntaxDocument.java +++ b/app/src/processing/app/syntax/SyntaxDocument.java @@ -27,7 +27,7 @@ public class SyntaxDocument extends PlainDocument * of this document up into tokens. May return null if this * document is not to be colorized. */ - public TokenMarker getTokenMarker() + public TokenMarkerState getTokenMarker() { return tokenMarker; } @@ -40,9 +40,11 @@ public TokenMarker getTokenMarker() */ public void setTokenMarker(TokenMarker tm) { - tokenMarker = tm; - if(tm == null) + if (tm == null) { + tokenMarker = null; return; + } + tokenMarker = tm.createStateInstance(); tokenMarker.insertLines(0,getDefaultRootElement() .getElementCount()); tokenizeLines(); @@ -67,7 +69,7 @@ public void tokenizeLines() */ public void tokenizeLines(int start, int len) { - if(tokenMarker == null || !tokenMarker.supportsMultilineTokens()) + if(tokenMarker == null || !tokenMarker.marker.supportsMultilineTokens()) return; Segment lineSegment = new Segment(); @@ -118,7 +120,7 @@ public void endCompoundEdit() {} public void addUndoableEdit(UndoableEdit edit) {} // protected members - protected TokenMarker tokenMarker; + protected TokenMarkerState tokenMarker; /** * We overwrite this method to update the token marker diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 5e8836fdb7..86e1ce2dc1 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -10,8 +10,15 @@ */ package processing.app.syntax; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; import java.awt.event.MouseEvent; -import java.awt.*; import javax.swing.ToolTipManager; import javax.swing.text.*; @@ -19,6 +26,7 @@ import processing.app.Preferences; import processing.app.syntax.im.CompositionTextPainter; +import processing.app.ui.Toolkit; /** @@ -107,14 +115,15 @@ public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults) { public void updateAppearance() { -// // unfortunately probably can't just do setDefaults() since things aren't quite set up -// setFont(defaults.plainFont); -//// System.out.println("defaults font is " + defaults.font); setForeground(defaults.fgcolor); setBackground(defaults.bgcolor); + // Ensure that our monospaced font is loaded + // https://github.com/processing/processing/pull/4639 + Toolkit.getMonoFontName(); + String fontFamily = Preferences.get("editor.font.family"); - int fontSize = Preferences.getInteger("editor.font.size"); + final int fontSize = Toolkit.zoom(Preferences.getInteger("editor.font.size")); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); if (!fontFamily.equals(plainFont.getFamily())) { System.err.println(fontFamily + " not available, resetting to monospaced"); @@ -124,16 +133,11 @@ public void updateAppearance() { } boldFont = new Font(fontFamily, Font.BOLD, fontSize); antialias = Preferences.getBoolean("editor.smooth"); -// System.out.println(plainFont.getFamily()); -// System.out.println(plainFont); // moved from setFont() override (never quite comfortable w/ that override) fm = super.getFontMetrics(plainFont); tabSize = fm.charWidth(' ') * Preferences.getInteger("editor.tabs.size"); textArea.recalculateVisibleLines(); - -// fgcolor = mode.getColor("editor.fgcolor"); -// bgcolor = mode.getColor("editor.bgcolor"); } @@ -484,7 +488,7 @@ public void paint(Graphics gfx) { int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height; try { - TokenMarker tokenMarker = textArea.getDocument().getTokenMarker(); + TokenMarkerState tokenMarker = textArea.getDocument().getTokenMarker(); int x = textArea.getHorizontalOffset(); for (int line = firstInvalid; line <= lastInvalid; line++) { @@ -600,14 +604,8 @@ public Segment getCurrentLine() { } -// /** Old paintLine() method with kooky args order, kept around for X Mode. */ -// @Deprecated -// protected void paintLine(Graphics gfx, TokenMarker tokenMarker, -// int line, int x) { -// Font defaultFont = getFont(); -// Color defaultColor = getForeground(); protected void paintLine(Graphics gfx, int line, int x, - TokenMarker tokenMarker) { + TokenMarkerState tokenMarker) { currentLineIndex = line; int y = textArea.lineToY(line); @@ -621,40 +619,37 @@ protected void paintLine(Graphics gfx, int line, int x, } -// protected void paintLine(Graphics gfx, int line, int x, -// TokenMarker tokenMarker) { -// paintLine(gfx, tokenMarker, line, x); -// } - - -// protected void paintPlainLine(Graphics gfx, int line, Font defaultFont, -// Color defaultColor, int x, int y) { protected void paintPlainLine(Graphics gfx, int line, int x, int y) { - paintHighlight(gfx,line,y); - textArea.getLineText(line, currentLine); + paintHighlight(gfx, line, y); -// gfx.setFont(plainFont); -// gfx.setFont(defaultFont); -// gfx.setColor(defaultColor); + // don't try to draw lines past where they exist in the document + // https://github.com/processing/processing/issues/5628 + if (line < textArea.getLineCount()) { + textArea.getLineText(line, currentLine); - int x0 = x - textArea.getHorizontalOffset(); + int x0 = x - textArea.getHorizontalOffset(); + // prevent the blinking from drawing with last color used + // https://github.com/processing/processing/issues/5628 + gfx.setColor(defaults.fgcolor); + gfx.setFont(plainFont); - y += fm.getHeight(); - // doesn't respect fixed width like it should + y += fm.getHeight(); + // doesn't respect fixed width like it should // x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0); // int w = fm.charWidth(' '); - for (int i = 0; i < currentLine.count; i++) { - gfx.drawChars(currentLine.array, currentLine.offset+i, 1, x, y); - x = currentLine.array[currentLine.offset + i] == '\t' ? + for (int i = 0; i < currentLine.count; i++) { + gfx.drawChars(currentLine.array, currentLine.offset+i, 1, x, y); + x = currentLine.array[currentLine.offset + i] == '\t' ? x0 + (int)nextTabStop(x - x0, i) : x + fm.charWidth(currentLine.array[currentLine.offset+i]); - textArea.offsetToX(line, currentLine.offset + i); - } + //textArea.offsetToX(line, currentLine.offset + i); + } - // Draw characters via input method. - if (compositionTextPainter != null && + // Draw characters via input method. + if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, defaults.lineHighlightColor); + compositionTextPainter.draw(gfx, defaults.lineHighlightColor); + } } if (defaults.eolMarkers) { gfx.setColor(defaults.eolMarkerColor); @@ -663,11 +658,8 @@ protected void paintPlainLine(Graphics gfx, int line, int x, int y) { } -// protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker, -// int line, Font defaultFont, -// Color defaultColor, int x, int y) { protected void paintSyntaxLine(Graphics gfx, int line, int x, int y, - TokenMarker tokenMarker) { + TokenMarkerState tokenMarker) { textArea.getLineText(currentLineIndex, currentLine); currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex); diff --git a/app/src/processing/app/syntax/TokenMarker.java b/app/src/processing/app/syntax/TokenMarker.java index 0e414e901e..57d76e6b7b 100644 --- a/app/src/processing/app/syntax/TokenMarker.java +++ b/app/src/processing/app/syntax/TokenMarker.java @@ -15,7 +15,7 @@ * A token marker that splits lines of text into tokens. Each token carries * a length field and an indentification tag that can be mapped to a color * for painting that token.

- * + *

* For performance reasons, the linked list of tokens is reused after each * line is tokenized. Therefore, the return value of markTokens * should only be used for immediate painting. Notably, it cannot be @@ -23,321 +23,68 @@ * * @author Slava Pestov */ -public abstract class TokenMarker -{ - abstract public void addColoring(String keyword, String coloring); - - /** - * A wrapper for the lower-level markTokensImpl method - * that is called to split a line up into tokens. - * @param line The line - * @param lineIndex The line number - */ - public Token markTokens(Segment line, int lineIndex) - { - if(lineIndex >= length) - { - throw new IllegalArgumentException("Tokenizing invalid line: " - + lineIndex); - } - - lastToken = null; - - LineInfo info = lineInfo[lineIndex]; - LineInfo prev; - if(lineIndex == 0) - prev = null; - else - prev = lineInfo[lineIndex - 1]; - - byte oldToken = info.token; - byte token = markTokensImpl(prev == null ? - Token.NULL : prev.token,line,lineIndex); - - info.token = token; - - /* - * This is a foul hack. It stops nextLineRequested - * from being cleared if the same line is marked twice. - * - * Why is this necessary? It's all JEditTextArea's fault. - * When something is inserted into the text, firing a - * document event, the insertUpdate() method shifts the - * caret (if necessary) by the amount inserted. - * - * All caret movement is handled by the select() method, - * which eventually pipes the new position to scrollTo() - * and calls repaint(). - * - * Note that at this point in time, the new line hasn't - * yet been painted; the caret is moved first. - * - * scrollTo() calls offsetToX(), which tokenizes the line - * unless it is being called on the last line painted - * (in which case it uses the text area's painter cached - * token list). What scrollTo() does next is irrelevant. - * - * After scrollTo() has done it's job, repaint() is - * called, and eventually we end up in paintLine(), whose - * job is to paint the changed line. It, too, calls - * markTokens(). - * - * The problem was that if the line started a multiline - * token, the first markTokens() (done in offsetToX()) - * would set nextLineRequested (because the line end - * token had changed) but the second would clear it - * (because the line was the same that time) and therefore - * paintLine() would never know that it needed to repaint - * subsequent lines. - * - * This bug took me ages to track down, that's why I wrote - * all the relevant info down so that others wouldn't - * duplicate it. - */ - if(!(lastLine == lineIndex && nextLineRequested)) - nextLineRequested = (oldToken != token); - - lastLine = lineIndex; - - addToken(0,Token.END); - - return firstToken; - } - - /** - * An abstract method that splits a line up into tokens. It - * should parse the line, and call addToken() to - * add syntax tokens to the token list. Then, it should return - * the initial token type for the next line.

- * - * For example if the current line contains the start of a - * multiline comment that doesn't end on that line, this method - * should return the comment token type so that it continues on - * the next line. - * - * @param token The initial token type for this line - * @param line The line to be tokenized - * @param lineIndex The index of the line in the document, - * starting at 0 - * @return The initial token type for the next line - */ - protected abstract byte markTokensImpl(byte token, Segment line, - int lineIndex); - - /** - * Returns if the token marker supports tokens that span multiple - * lines. If this is true, the object using this token marker is - * required to pass all lines in the document to the - * markTokens() method (in turn).

- * - * The default implementation returns true; it should be overridden - * to return false on simpler token markers for increased speed. - */ - public boolean supportsMultilineTokens() - { - return true; - } - - /** - * Informs the token marker that lines have been inserted into - * the document. This inserts a gap in the lineInfo - * array. - * @param index The first line number - * @param lines The number of lines - */ - public void insertLines(int index, int lines) - { - if(lines <= 0) - return; - length += lines; - ensureCapacity(length); - int len = index + lines; - System.arraycopy(lineInfo,index,lineInfo,len, - lineInfo.length - len); - - for(int i = index + lines - 1; i >= index; i--) - { - lineInfo[i] = new LineInfo(); - } - } - - /** - * Informs the token marker that line have been deleted from - * the document. This removes the lines in question from the - * lineInfo array. - * @param index The first line number - * @param lines The number of lines - */ - public void deleteLines(int index, int lines) - { - if (lines <= 0) - return; - int len = index + lines; - length -= lines; - System.arraycopy(lineInfo,len,lineInfo, - index,lineInfo.length - len); - } - - /** - * Returns the number of lines in this token marker. - */ - public int getLineCount() - { - return length; - } - - /** - * Returns true if the next line should be repainted. This - * will return true after a line has been tokenized that starts - * a multiline token that continues onto the next line. - */ - public boolean isNextLineRequested() - { - return nextLineRequested; - } - - // protected members - - /** - * The first token in the list. This should be used as the return - * value from markTokens(). - */ - protected Token firstToken; - - /** - * The last token in the list. New tokens are added here. - * This should be set to null before a new line is to be tokenized. - */ - protected Token lastToken; - - /** - * An array for storing information about lines. It is enlarged and - * shrunk automatically by the insertLines() and - * deleteLines() methods. - */ - protected LineInfo[] lineInfo; - - /** - * The number of lines in the model being tokenized. This can be - * less than the length of the lineInfo array. - */ - protected int length; - - /** - * The last tokenized line. - */ - protected int lastLine; - - /** - * True if the next line should be painted. - */ - protected boolean nextLineRequested; - - /** - * Creates a new TokenMarker. This DOES NOT create - * a lineInfo array; an initial call to insertLines() - * does that. - */ - protected TokenMarker() - { - lastLine = -1; - } - - /** - * Ensures that the lineInfo array can contain the - * specified index. This enlarges it if necessary. No action is - * taken if the array is large enough already.

- * - * It should be unnecessary to call this under normal - * circumstances; insertLine() should take care of - * enlarging the line info array automatically. - * - * @param index The array index - */ - protected void ensureCapacity(int index) - { - if(lineInfo == null) - lineInfo = new LineInfo[index + 1]; - else if(lineInfo.length <= index) - { - LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2]; - System.arraycopy(lineInfo,0,lineInfoN,0, - lineInfo.length); - lineInfo = lineInfoN; - } - } - - /** - * Adds a token to the token list. - * @param length The length of the token - * @param id The id of the token - */ - protected void addToken(int length, byte id) - { - if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST) - throw new InternalError("Invalid id: " + id); - - if(length == 0 && id != Token.END) - return; - - if(firstToken == null) - { - firstToken = new Token(length,id); - lastToken = firstToken; - } - else if(lastToken == null) - { - lastToken = firstToken; - firstToken.length = length; - firstToken.id = id; - } - else if(lastToken.next == null) - { - lastToken.next = new Token(length,id); - lastToken = lastToken.next; - } - else - { - lastToken = lastToken.next; - lastToken.length = length; - lastToken.id = id; - } - } - - /** - * Inner class for storing information about tokenized lines. - */ - private static class LineInfo - { - /** - * Creates a new LineInfo object with token = Token.NULL - * and obj = null. - */ - public LineInfo() - { - } - - /** - * Creates a new LineInfo object with the specified - * parameters. - */ -// public LineInfo(byte token, Object obj) -// { -// this.token = token; -// this.obj = obj; -// } - - /** - * The id of the last token of the line. - */ - public byte token; - - /** - * This is for use by the token marker implementations - * themselves. It can be used to store anything that - * is an object and that needs to exist on a per-line - * basis. - */ -// public Object obj; - } +public abstract class TokenMarker { + + public interface TokenListener { + void addToken(int length, byte id); + } + + // Only needed during markTokensImpl() call so addToken() can be forwarded + private TokenListener tokenListener = null; + + public final void setTokenListener(TokenListener listener) { + this.tokenListener = listener; + } + + public final TokenMarkerState createStateInstance() { + return new TokenMarkerState(this); + } + + /** + * Creates a new TokenMarker. This DOES NOT create + * a lineInfo array; an initial call to insertLines() + * does that. + */ + protected TokenMarker() { } + + abstract public void addColoring(String keyword, String coloring); + + /** + * An abstract method that splits a line up into tokens. It + * should parse the line, and call addToken() to + * add syntax tokens to the token list. Then, it should return + * the initial token type for the next line.

+ *

+ * For example if the current line contains the start of a + * multiline comment that doesn't end on that line, this method + * should return the comment token type so that it continues on + * the next line. + * + * @param token The initial token type for this line + * @param line The line to be tokenized + * @param lineIndex The index of the line in the document, + * starting at 0 + * @return The initial token type for the next line + */ + protected abstract byte markTokensImpl(byte token, Segment line, + int lineIndex); + + protected final void addToken(int length, byte id) { + if (tokenListener != null) { + tokenListener.addToken(length, id); + } + } + + /** + * Returns if the token marker supports tokens that span multiple + * lines. If this is true, the object using this token marker is + * required to pass all lines in the document to the + * markTokens() method (in turn).

+ *

+ * The default implementation returns true; it should be overridden + * to return false on simpler token markers for increased speed. + */ + public boolean supportsMultilineTokens() { + return true; + } } diff --git a/app/src/processing/app/syntax/TokenMarkerState.java b/app/src/processing/app/syntax/TokenMarkerState.java new file mode 100644 index 0000000000..8b20b2603c --- /dev/null +++ b/app/src/processing/app/syntax/TokenMarkerState.java @@ -0,0 +1,266 @@ +package processing.app.syntax; + +import javax.swing.text.Segment; + +/** + * This class serves only as a workaround to preserve API and should be removed + * in the next major version. Base TokenMarker which serves as superclass for + * token markes for various modes is stateful, but single instance was shared + * between all tabs and Editors. This caused inherent bugs by leaking state + * between contexts. + * + * TokenMarker subclasses now serve two purposes: they keep keyword list and + * they override markTokensImpl to provide the marking logic. + * + * Since each tab and Editor should have it's own token marker state, I extracted + * most of the fields and associated metods working with them from TokenMarker + * into this class, and allowed TokenMarker to create instances of this class + * when requested. + * + * The way marking logic is handled is unfortunate, since markTokensImpl is + * expected to call addToken() of TokenMarker superclass instead of – for + * example - returning a List of tokens. I worked around this by plugging in + * TokenMarkerState instance as listener before markTokensImpl is called. + * This behavior is safe since TokenMarker is always operated from Event + * Dispatch Thread and no multithreading is involved. + * + * This allows having only single instance of TokenMarker in a way it was + * intended before while keeping state separate for each tab. + * + * In the next major version TokenMarker shound be redesigned with following + * requirements in mind: + * - Single instance of keyword list and other common data, initialized by Mode + * - Each tab should have its own instance of TokenMarker containing its state + * - Support multiple flavors for different doc types + * - Other modes should provide logic in a way which is compatible with + * multiple states (pure function? Function object?). + * Currently state, logic and keywords list are tied together into one + * TokenMarker instance, which leads to need for this workaround. + */ +public class TokenMarkerState { + + protected TokenMarker marker; + + protected TokenMarkerState(TokenMarker marker) { + this.marker = marker; + } + + /** + * The first token in the list. This should be used as the return + * value from markTokens(). + */ + protected Token firstToken; + + /** + * The last token in the list. New tokens are added here. + * This should be set to null before a new line is to be tokenized. + */ + protected Token lastToken; + + /** + * An array for storing information about lines. It is enlarged and + * shrunk automatically by the insertLines() and + * deleteLines() methods. + */ + protected byte[] lineInfo; + + /** + * The number of lines in the model being tokenized. This can be + * less than the length of the lineInfo array. + */ + protected int length; + + /** + * The last tokenized line. + */ + protected int lastLine = -1; + + /** + * True if the next line should be painted. + */ + protected boolean nextLineRequested; + + /** + * A wrapper for the lower-level markTokensImpl method + * that is called to split a line up into tokens. + * + * @param line The line + * @param lineIndex The line number + */ + public Token markTokens(Segment line, int lineIndex) { + if (lineIndex >= length) { + throw new IllegalArgumentException("Tokenizing invalid line: " + + lineIndex); + } + + marker.setTokenListener(this::addToken); + + lastToken = null; + + byte prev = (lineIndex == 0) ? Token.NULL : lineInfo[lineIndex - 1]; + + byte oldToken = lineInfo[lineIndex]; + byte token = marker.markTokensImpl(prev, line, lineIndex); + + marker.setTokenListener(null); + + lineInfo[lineIndex] = token; + + /* + * This is a foul hack. It stops nextLineRequested + * from being cleared if the same line is marked twice. + * + * Why is this necessary? It's all JEditTextArea's fault. + * When something is inserted into the text, firing a + * document event, the insertUpdate() method shifts the + * caret (if necessary) by the amount inserted. + * + * All caret movement is handled by the select() method, + * which eventually pipes the new position to scrollTo() + * and calls repaint(). + * + * Note that at this point in time, the new line hasn't + * yet been painted; the caret is moved first. + * + * scrollTo() calls offsetToX(), which tokenizes the line + * unless it is being called on the last line painted + * (in which case it uses the text area's painter cached + * token list). What scrollTo() does next is irrelevant. + * + * After scrollTo() has done it's job, repaint() is + * called, and eventually we end up in paintLine(), whose + * job is to paint the changed line. It, too, calls + * markTokens(). + * + * The problem was that if the line started a multiline + * token, the first markTokens() (done in offsetToX()) + * would set nextLineRequested (because the line end + * token had changed) but the second would clear it + * (because the line was the same that time) and therefore + * paintLine() would never know that it needed to repaint + * subsequent lines. + * + * This bug took me ages to track down, that's why I wrote + * all the relevant info down so that others wouldn't + * duplicate it. + */ + if (!(lastLine == lineIndex && nextLineRequested)) { + nextLineRequested = (oldToken != token); + } + + lastLine = lineIndex; + + addToken(0, Token.END); + + return firstToken; + } + + /** + * Informs the token marker that lines have been inserted into + * the document. This inserts a gap in the lineInfo + * array. + * + * @param index The first line number + * @param lines The number of lines + */ + public void insertLines(int index, int lines) { + if (lines <= 0) + return; + length += lines; + ensureCapacity(length); + int len = index + lines; + System.arraycopy(lineInfo, index, lineInfo, len, + lineInfo.length - len); + + for (int i = index + lines - 1; i >= index; i--) { + lineInfo[i] = Token.NULL; + } + } + + /** + * Informs the token marker that line have been deleted from + * the document. This removes the lines in question from the + * lineInfo array. + * + * @param index The first line number + * @param lines The number of lines + */ + public void deleteLines(int index, int lines) { + if (lines <= 0) + return; + int len = index + lines; + length -= lines; + System.arraycopy(lineInfo, len, lineInfo, + index, lineInfo.length - len); + } + + /** + * Returns the number of lines in this token marker. + */ + public int getLineCount() { + return length; + } + + /** + * Returns true if the next line should be repainted. This + * will return true after a line has been tokenized that starts + * a multiline token that continues onto the next line. + */ + public boolean isNextLineRequested() { + return nextLineRequested; + } + + /** + * Ensures that the lineInfo array can contain the + * specified index. This enlarges it if necessary. No action is + * taken if the array is large enough already.

+ *

+ * It should be unnecessary to call this under normal + * circumstances; insertLine() should take care of + * enlarging the line info array automatically. + * + * @param index The array index + */ + protected void ensureCapacity(int index) { + if (lineInfo == null) { + lineInfo = new byte[index + 1]; + } else if (lineInfo.length <= index) { + byte[] lineInfoN = new byte[(index + 1) * 2]; + System.arraycopy(lineInfo, 0, lineInfoN, 0, + lineInfo.length); + lineInfo = lineInfoN; + } + } + + /** + * Adds a token to the token list. + * + * @param length The length of the token + * @param id The id of the token + */ + protected void addToken(int length, byte id) { + if (id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST) { + throw new InternalError("Invalid id: " + id); + } + + if (length == 0 && id != Token.END) { + return; + } + + if (firstToken == null) { + firstToken = new Token(length, id); + lastToken = firstToken; + } else if (lastToken == null) { + lastToken = firstToken; + firstToken.length = length; + firstToken.id = id; + } else if (lastToken.next == null) { + lastToken.next = new Token(length, id); + lastToken = lastToken.next; + } else { + lastToken = lastToken.next; + lastToken.length = length; + lastToken.id = id; + } + } +} diff --git a/app/src/processing/app/syntax/im/CompositionTextManager.java b/app/src/processing/app/syntax/im/CompositionTextManager.java index d37441f2cc..a7cc100208 100644 --- a/app/src/processing/app/syntax/im/CompositionTextManager.java +++ b/app/src/processing/app/syntax/im/CompositionTextManager.java @@ -15,12 +15,12 @@ import javax.swing.text.BadLocationException; -import processing.app.Base; import processing.app.Messages; import processing.app.Preferences; import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaPainter; + /** * This class Manage texts from input method * by begin-process-end steps. @@ -156,16 +156,16 @@ private void removeNotCommittedText(AttributedCharacterIterator text){ e.printStackTrace(); } } - + private TextLayout getTextLayout(AttributedCharacterIterator text, int committedCount) { boolean antialias = Preferences.getBoolean("editor.smooth"); TextAreaPainter painter = textArea.getPainter(); - + // create attributed string with font info. AttributedString composed = new AttributedString(text, committedCount, text.getEndIndex()); Font font = painter.getFontMetrics().getFont(); composed.addAttribute(TextAttribute.FONT, font); - + // set hint of antialiasing to render target. Graphics2D g2d = (Graphics2D)painter.getGraphics(); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, @@ -173,9 +173,7 @@ private TextLayout getTextLayout(AttributedCharacterIterator text, int committed RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); FontRenderContext frc = g2d.getFontRenderContext(); - if (Base.DEBUG) { - Messages.log("debug: FontRenderContext is Antialiased = " + frc.getAntiAliasingHint()); - } + Messages.log("debug: FontRenderContext is Antialiased = " + frc.getAntiAliasingHint()); return new TextLayout(composed.getIterator(), frc); } diff --git a/app/src/processing/app/syntax/im/CompositionTextPainter.java b/app/src/processing/app/syntax/im/CompositionTextPainter.java index 4a53dd5edc..b31ad9271e 100644 --- a/app/src/processing/app/syntax/im/CompositionTextPainter.java +++ b/app/src/processing/app/syntax/im/CompositionTextPainter.java @@ -8,19 +8,18 @@ import java.awt.font.TextHitInfo; import java.awt.font.TextLayout; -import processing.app.Base; -import processing.app.Messages; import processing.app.syntax.JEditTextArea; + /** - * Paint texts from input method. Text via input method are transmitted by - * AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter + * Paint texts from input method. Text via input method are transmitted by + * AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter * to handle AttributedCaharacterIterator. - * + * * For practical purposes, paint to textarea is done by TextLayout class. - * Because TextLayout class is easy to draw composing texts. (For example, + * Because TextLayout class is easy to draw composing texts. (For example, * draw underline composing texts, focus when select from candidates text.) - * + * * @author Takashi Maekawa (takachin@generative.info) */ public class CompositionTextPainter { @@ -39,7 +38,7 @@ public CompositionTextPainter(JEditTextArea textArea) { composedTextLayout = null; } - + /** * Check the painter has TextLayout. * If a user input via InputMethod, this result will return true. @@ -47,19 +46,19 @@ public CompositionTextPainter(JEditTextArea textArea) { public boolean hasComposedTextLayout() { return (composedTextLayout != null); } - - + + /** * Set TextLayout to the painter. * TextLayout will be created and set by CompositionTextManager. - * + * * @see CompositionTextManager */ public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) { this.composedTextLayout = composedTextLayout; this.composedBeginCaretPosition = composedStartCaretPosition; } - + /** * Invalidate this TextLayout to set null. @@ -70,23 +69,23 @@ public void invalidateComposedTextLayout(int composedEndCaretPosition) { this.composedBeginCaretPosition = composedEndCaretPosition; //this.composedBeginCaretPosition = textArea.getCaretPosition(); } - - + + /** * Draw text via input method with composed text information. - * This method can draw texts with some underlines to illustrate converting characters. - * + * This method can draw texts with some underlines to illustrate converting characters. + * * This method is workaround for TextAreaPainter. * Because, TextAreaPainter can't treat AttributedCharacterIterator directly. * AttributedCharacterIterator has very important information when composing text. * It has a map where are converted characters and committed characters. * Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!! * So I choose to write some code as a workaround. - * + * * This draw method is proceeded with the following steps. - * 1. Original TextAreaPainter draws characters. + * 1. Original TextAreaPainter draws characters. * 2. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout. - * + * * @param gfx set TextAreaPainter's Graphics object. * @param fillBackGroundColor set textarea's background. */ @@ -102,7 +101,7 @@ public void draw(Graphics gfx, Color fillBackGroundColor) { Point composedLoc = getCaretLocation(); //refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y); composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y); - + // draw caret. if (this.caret != null) { int caretLocation = Math.round(composedTextLayout.getCaretInfo(caret)[0]); @@ -110,10 +109,6 @@ public void draw(Graphics gfx, Color fillBackGroundColor) { composedLoc.y - (int)composedTextLayout.getAscent(), 1, (int)composedTextLayout.getAscent() + (int)composedTextLayout.getDescent()); - // blink caret. - if (Base.DEBUG) { - Messages.log(rect.toString()); - } Color c = gfx.getColor(); // save if (caretColorFlag) { caretColorFlag = false; @@ -129,8 +124,8 @@ public void draw(Graphics gfx, Color fillBackGroundColor) { } // /** -// * Fill color to erase characters drawn by original TextAreaPainter. -// * +// * Fill color to erase characters drawn by original TextAreaPainter. +// * // * @param fillColor fill color to erase characters drawn by original TextAreaPainter method. // * @param x x-coordinate where to fill. // * @param y y-coordinate where to fill. @@ -144,7 +139,7 @@ public void draw(Graphics gfx, Color fillBackGroundColor) { // int paintWidth = (int) composedTextLayout.getBounds().getWidth(); // gfx.fillRect(x, newY, paintWidth, paintHeight); // } - + private Point getCaretLocation() { int line = textArea.getCaretLine(); diff --git a/app/src/processing/app/syntax/im/InputMethodSupport.java b/app/src/processing/app/syntax/im/InputMethodSupport.java index 2e83768d68..347480552d 100644 --- a/app/src/processing/app/syntax/im/InputMethodSupport.java +++ b/app/src/processing/app/syntax/im/InputMethodSupport.java @@ -195,9 +195,7 @@ public void inputMethodTextChanged(InputMethodEvent event) { } CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter(); - if (Base.DEBUG) { - Messages.log(" textArea.getCaretPosition() + committed_count: " + (textArea.getCaretPosition() + committedCount)); - } + Messages.log("textArea.getCaretPosition() + committed_count: " + (textArea.getCaretPosition() + committedCount)); compositionPainter.setComposedTextLayout(getTextLayout(text, committedCount), textArea.getCaretPosition() + committedCount); compositionPainter.setCaret(event.getCaret()); diff --git a/app/src/processing/app/tools/InstallCommander.java b/app/src/processing/app/tools/InstallCommander.java index b2723f8c6f..518789d4ce 100644 --- a/app/src/processing/app/tools/InstallCommander.java +++ b/app/src/processing/app/tools/InstallCommander.java @@ -105,7 +105,7 @@ public void run() { String classPath = jarList.join(":").replaceAll(javaRoot + "\\/?", ""); writer.println("cd \"" + javaRoot + "\" && " + - Platform.getJavaPath() + + Platform.getJavaPath().replaceAll(" ", "\\\\ ") + " -Djna.nosys=true" + " $OPTION_FOR_HEADLESS_RUN" + " -cp \"" + classPath + "\"" + diff --git a/app/src/processing/app/ui/About.java b/app/src/processing/app/ui/About.java index a84a680c5a..526bc31de6 100644 --- a/app/src/processing/app/ui/About.java +++ b/app/src/processing/app/ui/About.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or diff --git a/app/src/processing/app/ui/ChangeDetector.java b/app/src/processing/app/ui/ChangeDetector.java index 866d2ffc45..6d95275d0a 100644 --- a/app/src/processing/app/ui/ChangeDetector.java +++ b/app/src/processing/app/ui/ChangeDetector.java @@ -1,16 +1,40 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012-19 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + package processing.app.ui; -import java.awt.EventQueue; -import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.io.File; -import java.lang.reflect.InvocationTargetException; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Collectors; -import javax.swing.JOptionPane; - +import processing.app.Language; import processing.app.Messages; import processing.app.Preferences; import processing.app.Sketch; @@ -21,6 +45,9 @@ public class ChangeDetector implements WindowFocusListener { private final Sketch sketch; private final Editor editor; + private List ignoredRemovals = new ArrayList<>(); + private List ignoredModifications = new ArrayList<>(); + // Windows and others seem to have a few hundred ms difference in reported // times, so we're arbitrarily setting a gap in time here. // Mac OS X has an (exactly) one second difference. Not sure if it's a Java @@ -32,9 +59,6 @@ public class ChangeDetector implements WindowFocusListener { static private final boolean DEBUG = Preferences.getBoolean("editor.watcher.debug"); - // Store the known number of files to avoid re-asking about the same change -// private int lastKnownCount = -1; - public ChangeDetector(Editor editor) { this.sketch = editor.sketch; @@ -44,27 +68,14 @@ public ChangeDetector(Editor editor) { @Override public void windowGainedFocus(WindowEvent e) { - // When the window is activated, fire off a Thread to check for changes if (Preferences.getBoolean("editor.watcher")) { - new Thread(new Runnable() { - @Override - public void run() { - if (sketch != null) { - // make sure the sketch folder exists at all. - // if it does not, it will be re-saved, and no changes will be detected - sketch.ensureExistence(); - -// if (lastKnownCount == -1) { -// lastKnownCount = sketch.getCodeCount(); -// } - - boolean alreadyPrompted = checkFileCount(); - if (!alreadyPrompted) { - checkFileTimes(); - } - } - } - }).start(); + if (sketch != null) { + // make sure the sketch folder exists at all. + // if it does not, it will be re-saved, and no changes will be detected + sketch.ensureExistence(); + + checkFiles(); + } } } @@ -76,205 +87,199 @@ public void windowLostFocus(WindowEvent e) { } - private boolean checkFileCount() { - // check file count first - + private void checkFiles() { List filenames = new ArrayList<>(); + List extensions = new ArrayList<>(); + sketch.getSketchCodeFiles(filenames, extensions); - sketch.getSketchCodeFiles(filenames, null); + SketchCode[] codes = sketch.getCode(); - int fileCount = filenames.size(); + // Separate codes with and without files + Map> existsMap = Arrays.stream(codes) + .collect(Collectors.groupingBy(code -> filenames.contains(code.getFileName()))); - // Was considering keeping track of the last "known" number of files - // (instead of using sketch.getCodeCount() here) in case the user - // didn't want to reload after the number of files had changed. - // However, that's a bad situation anyway and there aren't good - // ways to recover or work around it, so just prompt the user again. - if (fileCount == sketch.getCodeCount()) { - return false; - } - if (DEBUG) { - System.out.println(sketch.getName() + " file count now " + fileCount + - " instead of " + sketch.getCodeCount()); - } + // ADDED FILES - if (reloadPrompt()) { - if (sketch.getMainFile().exists()) { - reloadSketch(); - } else { - // If the main file was deleted, and that's why we're here, - // then we need to re-save the sketch instead. - try { - // Mark everything as modified so that it saves properly - for (SketchCode code : sketch.getCode()) { - code.setModified(true); - } - sketch.save(); - } catch (Exception e) { - //if that didn't work, tell them it's un-recoverable - showErrorEDT("Reload Failed", - "The main file for this sketch was deleted\n" + - "and could not be rewritten.", e); - } - } + List codeFilenames = Arrays.stream(codes) + .map(SketchCode::getFileName) + .collect(Collectors.toList()); - /* - if (fileCount < 1) { - // if they chose to reload and there aren't any files left - try { - // make a blank file for the main PDE - sketch.getMainFile().createNewFile(); - } catch (Exception e1) { - //if that didn't work, tell them it's un-recoverable - showErrorEDT("Reload failed", "The sketch contains no code files.", e1); - //don't try to reload again after the double fail - //this editor is probably trashed by this point, but a save-as might be possible -// skip = true; - return true; - } - // it's okay to do this without confirmation, because they already - // confirmed to deleting the unsaved changes above - sketch.reload(); - showWarningEDT("Modified Reload", - "You cannot delete the last code file in a sketch.\n" + - "A new blank sketch file has been generated for you."); - } - */ - } else { // !reload (user said no or closed the window) - // Because the number of files changed, they may be working with a file - // that doesn't exist any more. So find the files that are missing, - // and mark them as modified so that the next "Save" will write them. - for (SketchCode code : sketch.getCode()) { - if (!code.getFile().exists()) { - setCodeModified(code); - } - } - rebuildHeaderEDT(); - } - // Yes, we've brought this up with the user (so don't bother them further) - return true; - } + // Get filenames which are in filesystem but don't have code + List addedFilenames = filenames.stream() + .filter(f -> !codeFilenames.contains(f)) + .collect(Collectors.toList()); + // Take action if there are any added files which were not previously ignored + boolean added = !addedFilenames.isEmpty(); - private void checkFileTimes() { - List reloadList = new ArrayList<>(); - for (SketchCode code : sketch.getCode()) { - File sketchFile = code.getFile(); - if (sketchFile.exists()) { - long diff = sketchFile.lastModified() - code.getLastModified(); - if (diff > MODIFICATION_WINDOW_MILLIS) { - if (DEBUG) System.out.println(sketchFile.getName() + " " + diff + "ms"); - reloadList.add(code); - } - } else { - // If a file in the sketch was not found, then it must have been - // deleted externally, so reload the sketch. - if (DEBUG) System.out.println(sketchFile.getName() + " (file disappeared)"); - reloadList.add(code); - } - } - // If there are any files that need to be reloaded - if (reloadList.size() > 0) { - if (reloadPrompt()) { - reloadSketch(); + // REMOVED FILES - } else { - // User said no, but take bulletproofing actions - for (SketchCode code : reloadList) { - // Set the file as modified in the Editor so the contents will - // save to disk when the user saves from inside Processing. - setCodeModified(code); - // Since this was canceled, update the "last modified" time so we - // don't ask the user about it again. - code.setLastModified(); - } - rebuildHeaderEDT(); + // Get codes which don't have file + List removedCodes = Optional.ofNullable(existsMap.get(Boolean.FALSE)) + .orElse(Collections.emptyList()); + List removedCodesFinal = removedCodes.stream() + .filter(code -> !ignoredRemovals.contains(code)) + .collect(Collectors.toList()); + + // Show prompt if there are any removed codes which were not previously ignored + boolean removed = !removedCodesFinal.isEmpty(); + + + /// MODIFIED FILES + + // Get codes which have file with different modification time + List modifiedCodes = existsMap.containsKey(Boolean.TRUE) ? + existsMap.get(Boolean.TRUE) : Collections.emptyList(); + List modifiedCodesFinal = new ArrayList<>(); + for (SketchCode code : modifiedCodes) { + if (ignoredModifications.contains(code)) continue; + long fileLastModified = code.getFile().lastModified(); + long codeLastModified = code.getLastModified(); + long diff = fileLastModified - codeLastModified; + if (fileLastModified == 0L || diff > MODIFICATION_WINDOW_MILLIS) { + modifiedCodesFinal.add(code); } } - } + // Show prompt if any open codes were modified + boolean modified = !modifiedCodesFinal.isEmpty(); - private void setCodeModified(SketchCode sc) { - sc.setModified(true); - sketch.setModified(true); - } + // Clean ignore lists + ignoredModifications.retainAll(modifiedCodes); + ignoredRemovals.retainAll(removedCodes); - private void reloadSketch() { - sketch.reload(); - rebuildHeaderEDT(); - } + boolean changes = added || removed || modified; + // Do both PDE and disk change for any one file? + List mergeConflicts = modifiedCodesFinal.stream() + .filter(SketchCode::isModified) + .collect(Collectors.toList()); + boolean ask = !mergeConflicts.isEmpty() || removed; + if (DEBUG) { + System.out.println("ask: " + ask + "\n" + + "merge conflicts: " + mergeConflicts + ",\n" + + "added filenames: " + addedFilenames + ",\n" + + "removed codes: " + removedCodes + ",\n" + + "ignored removed: " + ignoredRemovals + ",\n" + + "modified codes: " + modifiedCodesFinal + "\n"); + } - /** - * Prompt the user whether to reload the sketch. If the user says yes, - * perform the actual reload. - * @return true if user said yes, false if they hit No or closed the window - */ - private boolean reloadPrompt() { - int response = blockingYesNoPrompt(editor, - "File Modified", - "Your sketch has been modified externally.
" + - "Would you like to reload the sketch?", - "If you reload the sketch, any unsaved changes will be lost."); - return response == JOptionPane.YES_OPTION; - } + // No prompt yet. + if (changes) { + for (int i = 0; i < filenames.size(); i++) { + for (String addedTab : addedFilenames) { + if (filenames.get(i).equals(addedTab)) { + sketch.loadNewTab(filenames.get(i), extensions.get(i), true); + } + } + } + for (SketchCode modifiedCode : modifiedCodesFinal) { + if (!mergeConflicts.contains(modifiedCode)) { + sketch.loadNewTab(modifiedCode.getFileName(), + modifiedCode.getExtension(), false); + } + } - private void showErrorEDT(final String title, final String message, - final Exception e) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - Messages.showError(title, message, e); + // Destructive actions, so prompt. + if (ask) { + sketch.updateSketchCodes(); + + showReloadPrompt(mergeConflicts, removedCodesFinal, + scReload -> { + try { + File file = scReload.getFile(); + File autosave = File.createTempFile(scReload.getPrettyName(), + ".autosave", file.getParentFile()); + scReload.copyTo(autosave); + } catch (IOException e) { + Messages.showWarning("Could not autosave modified tab", + "Your changes to " + scReload.getPrettyName() + + " have not been saved, so we won't load the new version.", e); + scReload.setModified(true); // So we'll have another go at saving + // it later, + ignoredModifications.add(scReload); // but not create a loop. + return; + } + sketch.loadNewTab(scReload.getFileName(), scReload.getExtension(), false); + }, + scKeep -> { + scKeep.setLastModified(); + scKeep.setModified(true); + }, + scDelete -> sketch.removeCode(scDelete), + scResave -> { + try { + scResave.save(); + } catch (IOException e) { + if (sketch.getCode(0).equals(scResave)) { + // Not a fatal error; the sketch has to stay open if + // they're going to save the code that's in it. + Messages.showWarning( + scResave.getFileName() + " deleted and not re-saved", + "Your main tab was deleted, and Processing couldn't " + + "resave it.\nYour sketch won't work without the " + + "main tab.", e); + } else { + Messages.showWarning("Could not re-save deleted tab", + "Your copy of " + scResave.getPrettyName() + + " will stay in the editor.", e); + } + ignoredRemovals.add(scResave); + scResave.setModified(true); // So we'll have another go at + // saving it later. + } + } + ); } - }); + editor.rebuildHeader(); + sketch.setCurrentCode(sketch.getCurrentCodeIndex()); + editor.repaintHeader(); + + editor.sketchChanged(); + } + } - /* - private void showWarningEDT(final String title, final String message) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - Messages.showWarning(title, message); + /** + * Prompt the user what to do about each tab. Passes the tab to the user's + * choice of Consumer. Won't let you delete the main tab. + */ + private void showReloadPrompt( + List mergeConflict, List removed, + Consumer modifiedReload, Consumer modifiedKeep, + Consumer delete, Consumer deletedResave) { + for (SketchCode sc : mergeConflict) { + if (1 == Messages.showCustomQuestion(editor, + Language.text("change_detect.reload.title"), + Language.interpolate("change_detect.reload.question", sc.getFileName()), + Language.text("change_detect.reload.comment"), + 0, + Language.text("change_detect.button.keep"), + Language.text("change_detect.button.load_new"))) { + modifiedReload.accept(sc); + } else { + modifiedKeep.accept(sc); } - }); - } - */ - - - private int blockingYesNoPrompt(final Frame editor, final String title, - final String message1, - final String message2) { - final int[] result = { -1 }; // yuck - try { - //have to wait for a response on this one - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - result[0] = Messages.showYesNoQuestion(editor, title, message1, message2); - } - }); - } catch (InvocationTargetException e) { - //occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen - e.getTargetException().printStackTrace(); - } catch (InterruptedException e) { - //occurs if the EDT is interrupted, so, shouldn't happen - e.printStackTrace(); } - return result[0]; - } - - private void rebuildHeaderEDT() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - editor.header.rebuild(); + for (SketchCode sc : removed) { + if (!sketch.getCode(0).equals(sc) && + 1 == Messages.showCustomQuestion(editor, + Language.text("change_detect.delete.title"), + Language.interpolate("change_detect.delete.question", sc.getFileName()), + Language.text("change_detect.delete.comment"), + 0, + Language.text("change_detect.button.resave"), + Language.text("change_detect.button.discard"))) { + delete.accept(sc); + } else { + deletedResave.accept(sc); } - }); + } } } diff --git a/app/src/processing/app/ui/ColorChooser.java b/app/src/processing/app/ui/ColorChooser.java index 1281206e2c..5693db6c66 100644 --- a/app/src/processing/app/ui/ColorChooser.java +++ b/app/src/processing/app/ui/ColorChooser.java @@ -3,7 +3,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2006-14 Ben Fry and Casey Reas + Copyright (c) 2012-19 The Processing Foundation + Copyright (c) 2006-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index 5f210c164f..6780a53100 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -79,9 +79,9 @@ public abstract class Editor extends JFrame implements RunnerListener { protected EditorState state; protected Mode mode; - static public final int LEFT_GUTTER = 44; - static public final int RIGHT_GUTTER = 12; - static public final int GUTTER_MARGIN = 3; + static public final int LEFT_GUTTER = Toolkit.zoom(44); + static public final int RIGHT_GUTTER = Toolkit.zoom(12); + static public final int GUTTER_MARGIN = Toolkit.zoom(3); protected MarkerColumn errorColumn; @@ -131,7 +131,7 @@ public abstract class Editor extends JFrame implements RunnerListener { protected CopyAsHtmlAction copyAsHtmlAction; protected PasteAction pasteAction; /** Menu Actions updated on the opening of the edit menu. */ - protected List editMenuUpdatable = new ArrayList(); + protected List editMenuUpdatable = new ArrayList<>(); /** The currently selected tab's undo manager */ private UndoManager undo; @@ -144,8 +144,8 @@ public abstract class Editor extends JFrame implements RunnerListener { // true if inserting text, false if removing text private boolean isInserting; // maintain caret position during undo operations - private final Stack caretUndoStack = new Stack(); - private final Stack caretRedoStack = new Stack(); + private final Stack caretUndoStack = new Stack<>(); + private final Stack caretRedoStack = new Stack<>(); private FindReplace find; JMenu toolsMenu; @@ -182,25 +182,21 @@ public void windowClosing(WindowEvent e) { // When bringing a window to front, let the Base know addWindowListener(new WindowAdapter() { -// int importIndex; public void windowActivated(WindowEvent e) { base.handleActivated(Editor.this); fileMenu.insert(Recent.getMenu(), 2); Toolkit.setMenuMnemsInside(fileMenu); - //sketchMenu.insert(mode.getImportMenu(), 5); mode.insertImportMenu(sketchMenu); - //sketchMenu.insert(mode.getImportMenu(), importIndex); Toolkit.setMenuMnemsInside(sketchMenu); mode.insertToolbarRecentMenu(); } public void windowDeactivated(WindowEvent e) { + // TODO call handleActivated(null)? or do we run the risk of the + // deactivate call for old window being called after the activate? fileMenu.remove(Recent.getMenu()); -// JMenu importMenu = mode.getImportMenu(); -// importIndex = sketchMenu.getComponentZOrder(mode.getImportMenu()); -// sketchMenu.remove(mode.getImportMenu()); mode.removeImportMenu(sketchMenu); mode.removeToolbarRecentMenu(); } @@ -267,9 +263,10 @@ public void paintComponent(Graphics g) { textarea.setRightClickPopup(new TextAreaPopup()); textarea.setHorizontalOffset(JEditTextArea.leftHandGutter); - { // Hack: add Numpad Slash as an alternative shortcut for Comment/Uncomment + { // Hack: add Numpad Slash as alternative shortcut for Comment/Uncomment int modifiers = Toolkit.awtToolkit.getMenuShortcutKeyMask(); - KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DIVIDE, modifiers); + KeyStroke keyStroke = + KeyStroke.getKeyStroke(KeyEvent.VK_DIVIDE, modifiers); final String ACTION_KEY = "COMMENT_UNCOMMENT_ALT"; textarea.getInputMap().put(keyStroke, ACTION_KEY); textarea.getActionMap().put(ACTION_KEY, new AbstractAction() { @@ -323,6 +320,17 @@ public BasicSplitPaneDivider createDefaultDivider() { status = new EditorStatus(this, Editor.this); return status; } + + + @Override + public void finishDraggingTo(int location) { + super.finishDraggingTo(location); + // JSplitPane issue: if you only make the lower component visible at + // the last minute, its minmum size is ignored. + if (location > splitPane.getMaximumDividerLocation()) { + splitPane.setDividerLocation(splitPane.getMaximumDividerLocation()); + } + } }); box.add(splitPane); @@ -345,15 +353,17 @@ public void caretUpdate(CaretEvent e) { contentPain.setTransferHandler(new FileDropHandler()); - // Finish preparing Editor (formerly found in Base) + // Finish preparing Editor pack(); // Set the window bounds and the divider location before setting it visible state.apply(this); // Set the minimum size for the editor window - int minWidth = Preferences.getInteger("editor.window.width.min"); - int minHeight = Preferences.getInteger("editor.window.height.min"); + int minWidth = + Toolkit.zoom(Preferences.getInteger("editor.window.width.min")); + int minHeight = + Toolkit.zoom(Preferences.getInteger("editor.window.height.min")); setMinimumSize(new Dimension(minWidth, minHeight)); // Bring back the general options for the editor @@ -871,13 +881,8 @@ protected JMenu buildEditMenu() { undoItem = Toolkit.newJMenuItem(undoAction = new UndoAction(), 'Z'); menu.add(undoItem); - // Gotta follow them interface guidelines - // http://code.google.com/p/processing/issues/detail?id=363 - if (Platform.isWindows()) { - redoItem = Toolkit.newJMenuItem(redoAction = new RedoAction(), 'Y'); - } else { // Linux and OS X - redoItem = Toolkit.newJMenuItemShift(redoAction = new RedoAction(), 'Z'); - } + redoItem = new JMenuItem(redoAction = new RedoAction()); + redoItem.setAccelerator(Toolkit.getKeyStrokeExt("menu.edit.redo")); menu.add(redoItem); menu.addSeparator(); @@ -946,7 +951,7 @@ public void actionPerformed(ActionEvent e) { }); menu.add(item); - item = Toolkit.newJMenuItem(Language.text("menu.edit.comment_uncomment"), '/'); + item = Toolkit.newJMenuItemExt("menu.edit.comment_uncomment"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleCommentUncomment(); @@ -954,7 +959,7 @@ public void actionPerformed(ActionEvent e) { }); menu.add(item); - item = Toolkit.newJMenuItem("\u2192 "+Language.text("menu.edit.increase_indent"), ']'); + item = Toolkit.newJMenuItemExt("menu.edit.increase_indent"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(true); @@ -962,7 +967,7 @@ public void actionPerformed(ActionEvent e) { }); menu.add(item); - item = Toolkit.newJMenuItem("\u2190 "+Language.text("menu.edit.decrease_indent"), '['); + item = Toolkit.newJMenuItemExt("menu.edit.decrease_indent"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleIndentOutdent(false); @@ -1070,7 +1075,7 @@ public void actionPerformed(ActionEvent e) { sketchMenu.addMenuListener(new MenuListener() { // Menu Listener that populates the menu only when the menu is opened - List menuList = new ArrayList(); + List menuList = new ArrayList<>(); @Override public void menuSelected(MenuEvent event) { @@ -1126,6 +1131,8 @@ public void librariesChanged() { } public void codeFolderChanged() { } + public void sketchChanged() { } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2135,13 +2142,26 @@ protected void handleCommentUncomment() { // log("Commented: " + commented); - // This is the line start offset of the first line, which is added to - // all other lines while adding a comment. Required when commenting + // This is the min line start offset of the selection, which is added to + // all lines while adding a comment. Required when commenting // lines which have uneven whitespaces in the beginning. Makes the // commented lines look more uniform. int lso = Math.abs(textarea.getLineStartNonWhiteSpaceOffset(startLine) - textarea.getLineStartOffset(startLine)); + if (!commented) { + // get min line start offset of all selected lines + for (int line = startLine+1; line <= stopLine; line++) { + String lineText = textarea.getLineText(line); + if (lineText.trim().length() == 0) { + continue; //ignore blank lines + } + int so = Math.abs(textarea.getLineStartNonWhiteSpaceOffset(line) + - textarea.getLineStartOffset(line)); + lso = Math.min(lso, so); + } + } + for (int line = startLine; line <= stopLine; line++) { int location = textarea.getLineStartNonWhiteSpaceOffset(line); String lineText = textarea.getLineText(line); @@ -2208,7 +2228,7 @@ public void handleIndentOutdent(boolean indent) { int last = Math.min(location + tabSize, textarea.getDocumentLength()); textarea.select(location, last); // Don't eat code if it's not indented - if (textarea.getSelectedText().equals(tabString)) { + if (tabString.equals(textarea.getSelectedText())) { textarea.setSelectedText(""); } } @@ -2307,11 +2327,11 @@ protected void handleFindReference() { if (ref != null) { showReference(ref + ".html"); } else { - String text = textarea.getSelectedText().trim(); - if (text.length() == 0) { + String text = textarea.getSelectedText(); + if (text == null) { statusNotice(Language.text("editor.status.find_reference.select_word_first")); } else { - statusNotice(Language.interpolate("editor.status.find_reference.not_available", text)); + statusNotice(Language.interpolate("editor.status.find_reference.not_available", text.trim())); } } } @@ -2465,7 +2485,7 @@ public boolean checkModified() { // on macosx, setting the destructive property places this option // away from the others at the lefthand side pane.putClientProperty("Quaqua.OptionPane.destructiveOption", - new Integer(2)); + Integer.valueOf(2)); JDialog dialog = pane.createDialog(this, null); dialog.setVisible(true); @@ -2579,6 +2599,7 @@ protected void handleOpenInternal(String path) throws EditorException { Preferences.save(); } + /** * Set the title of the PDE window based on the current sketch, i.e. * something like "sketch_070752a - Processing 0126" @@ -2781,6 +2802,8 @@ protected SizeRequirements calculateMinorAxisRequirements( /** * Grab current contents of the sketch window, advance the console, * stop any other running sketches... not in that order. + * It's essential that this function be called by any Mode subclass, + * otherwise current edits may not be stored for getProgram(). */ public void prepareRun() { internalCloseRunner(); @@ -2883,6 +2906,17 @@ public void statusError(Exception e) { if (e instanceof SketchException) { SketchException re = (SketchException) e; + + // Make sure something is printed into the console + // Status bar is volatile + if (!re.isStackTraceEnabled()) { + System.err.println(re.getMessage()); + } + + // Move the cursor to the line before updating the status bar, otherwise + // status message might get hidden by a potential message caused by moving + // the cursor to a line with warning in it + if (re.hasCodeIndex()) { sketch.setCurrentCode(re.getCodeIndex()); } @@ -3049,9 +3083,9 @@ public void updateErrorTable(List problems) { } - public void highlight(Problem p) { + public void highlight(Problem p) { if (p != null) { - highlight(p.getTabIndex(), p.getStartOffset(), p.getStartOffset()); + highlight(p.getTabIndex(), p.getStartOffset(), p.getStopOffset()); } } @@ -3102,20 +3136,15 @@ public void updateEditorStatus() { /** - * @return the Problem for the first error or warning on 'line' + * @return the Problem for the most relevant error or warning on 'line', + * defaults to the first error, if there are no errors first warning. */ - Problem findProblem(int line) { - int currentTab = getSketch().getCurrentCodeIndex(); - return problems.stream() - .filter(p -> p.getTabIndex() == currentTab) - .filter(p -> { - int pStartLine = p.getLineNumber(); - int pEndOffset = p.getStopOffset(); - int pEndLine = textarea.getLineOfOffset(pEndOffset); - return line >= pStartLine && line <= pEndLine; - }) - .findFirst() - .orElse(null); + protected Problem findProblem(int line) { + List problems = findProblems(line); + for (Problem p : problems) { + if (p.isError()) return p; + } + return problems.isEmpty() ? null : problems.get(0); } @@ -3154,20 +3183,22 @@ public void showConsole() { public void statusToolTip(JComponent comp, String message, boolean error) { if (font == null) { - font = Toolkit.getSansFont(9, Font.PLAIN); + font = Toolkit.getSansFont(Toolkit.zoom(9), Font.PLAIN); textColor = mode.getColor("errors.selection.fgcolor"); bgColorWarning = mode.getColor("errors.selection.warning.bgcolor"); bgColorError = mode.getColor("errors.selection.error.bgcolor"); } - Color bgColor = error ? //text.startsWith(Language.text("editor.status.error")) ? - bgColorError : bgColorWarning; - String content = "" + - "

" + message + "
"; - //System.out.println(content); + "font-size: " + font.getSize() + "px;"; + String content = + "
" + message + "
"; comp.setToolTipText(content); } diff --git a/app/src/processing/app/ui/EditorButton.java b/app/src/processing/app/ui/EditorButton.java index 8a115c5715..f65f081398 100644 --- a/app/src/processing/app/ui/EditorButton.java +++ b/app/src/processing/app/ui/EditorButton.java @@ -2,7 +2,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2015 The Processing Foundation + + Copyright (c) 2015-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -30,7 +31,7 @@ abstract public class EditorButton extends JComponent implements MouseListener, MouseMotionListener, ActionListener { - static public final int DIM = 30; + static public final int DIM = Toolkit.zoom(30); /** Button's description. */ protected String title; @@ -112,10 +113,18 @@ public void paintComponent(Graphics g) { } else if (rollover) { image = rolloverImage; } + + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + + int dim = getSize().width; // width == height if (gradient != null) { - g.drawImage(gradient, 0, 0, DIM, DIM, this); + //g.drawImage(gradient, 0, 0, DIM, DIM, this); + g.drawImage(gradient, 0, 0, dim, dim, this); } - g.drawImage(image, 0, 0, DIM, DIM, this); + //g.drawImage(image, 0, 0, DIM, DIM, this); + g.drawImage(image, 0, 0, dim, dim, this); } diff --git a/app/src/processing/app/ui/EditorConsole.java b/app/src/processing/app/ui/EditorConsole.java index b5f5b94964..186e692b90 100644 --- a/app/src/processing/app/ui/EditorConsole.java +++ b/app/src/processing/app/ui/EditorConsole.java @@ -3,7 +3,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2004-10 Ben Fry and Casey Reas + Copyright (c) 2012-19 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify @@ -27,33 +28,23 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.event.*; -import java.io.*; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.concurrent.LinkedBlockingQueue; import javax.swing.*; import javax.swing.border.MatteBorder; import javax.swing.text.*; -import processing.app.*; -import processing.core.PApplet; +import processing.app.Console; +import processing.app.Mode; +import processing.app.Preferences; /** * Message console that sits below the editing area. - *

- * Be careful when debugging this class, because if it's throwing exceptions, - * don't take over System.err, and debug while watching just System.out - * or just call println() or whatever directly to systemOut or systemErr. - *

- * Also note that encodings will not work properly when run from Eclipse. This - * means that if you use non-ASCII characters in a println() or some such, - * the characters won't print properly in the Processing and/or Eclipse console. - * It seems that Eclipse's console-grabbing and that of Processing don't - * get along with one another. Use 'ant run' to work on encoding-related issues. */ public class EditorConsole extends JScrollPane { Editor editor; @@ -67,95 +58,30 @@ public class EditorConsole extends JScrollPane { MutableAttributeSet errStyle; int maxLineCount; + int maxCharCount; PrintStream sketchOut; PrintStream sketchErr; - // Single static instance shared because there's only one real System.out. - // Within the input handlers, the currentConsole variable will be used to - // echo things to the correct location. - - static PrintStream systemOut; - static PrintStream systemErr; - - static PrintStream consoleOut; - static PrintStream consoleErr; - - static OutputStream stdoutFile; - static OutputStream stderrFile; - - static EditorConsole currentConsole; - - // For 0185, moved the first init to this static { } block, so that we never - // have a situation that causes systemOut/Err to not be set properly. - static { - systemOut = System.out; - systemErr = System.err; - - // placing everything inside a try block because this can be a dangerous - // time for the lights to blink out and crash for and obscure reason. - try { - // Create output files that will have a randomized name. Has to - // be randomized otherwise another instance of Processing (or one of its - // sister IDEs) might collide with the file causing permissions problems. - // The files and folders are not deleted on exit because they may be - // needed for debugging or bug reporting. - SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd"); - String randy = PApplet.nf((int) (1000 * Math.random()), 4); - String stamp = formatter.format(new Date()) + "_" + randy; - - File consoleDir = Base.getSettingsFile("console"); - consoleDir.mkdirs(); - File outFile = new File(consoleDir, stamp + ".out"); - stdoutFile = new FileOutputStream(outFile); - File errFile = new File(consoleDir, stamp + ".err"); - stderrFile = new FileOutputStream(errFile); - - consoleOut = new PrintStream(new EditorConsoleStream(false, null)); - consoleErr = new PrintStream(new EditorConsoleStream(true, null)); - - System.setOut(consoleOut); - System.setErr(consoleErr); - -// } catch (Exception e) { -// stdoutFile = null; -// stderrFile = null; -// -// e.printStackTrace(); -// Base.showWarning("Console Error", -// "A problem occurred while trying to open the\n" + -// "files used to store the console output.", e); - } catch (Exception e) { - stdoutFile = null; - stderrFile = null; - - consoleOut = null; - consoleErr = null; - - System.setOut(systemOut); - System.setErr(systemErr); - - e.printStackTrace(systemErr); - } - } + static EditorConsole current; public EditorConsole(Editor editor) { this.editor = editor; - maxLineCount = Preferences.getInteger("console.length"); + maxLineCount = Preferences.getInteger("console.scrollback.lines"); + maxCharCount = Preferences.getInteger("console.scrollback.chars"); - consoleDoc = new BufferedStyledDocument(10000, maxLineCount); + consoleDoc = new BufferedStyledDocument(10000, maxLineCount, maxCharCount); consoleTextPane = new JTextPane(consoleDoc); consoleTextPane.setEditable(false); updateMode(); - // add the jtextpane to this scrollpane - this.setViewportView(consoleTextPane); + setViewportView(consoleTextPane); - sketchOut = new PrintStream(new EditorConsoleStream(false, this)); - sketchErr = new PrintStream(new EditorConsoleStream(true, this)); + sketchOut = new PrintStream(new EditorConsoleStream(false)); + sketchErr = new PrintStream(new EditorConsoleStream(true)); startTimer(); } @@ -163,7 +89,7 @@ public EditorConsole(Editor editor) { protected void flush() { // only if new text has been added - if (consoleDoc.hasAppendage) { + if (consoleDoc.hasAppendage()) { // insert the text that's been added in the meantime consoleDoc.insertAll(); // always move to the end of the text as it's added @@ -215,7 +141,7 @@ public PrintStream getErr() { */ protected void updateAppearance() { String fontFamily = Preferences.get("editor.font.family"); - int fontSize = Preferences.getInteger("console.font.size"); + int fontSize = Toolkit.zoom(Preferences.getInteger("console.font.size")); StyleConstants.setFontFamily(stdStyle, fontFamily); StyleConstants.setFontSize(stdStyle, fontSize); StyleConstants.setFontFamily(errStyle, fontFamily); @@ -282,55 +208,33 @@ protected void updateMode() { static public void setEditor(Editor editor) { - if (currentConsole != null) { - currentConsole.stopTimer(); // allow to be garbage collected + if (current != null) { + current.stopTimer(); // allow to be garbage collected } - currentConsole = editor.console; - currentConsole.startTimer(); + editor.console.setCurrent(); } - /** - * Close the streams so that the temporary files can be deleted. - *

- * File.deleteOnExit() cannot be used because the stdout and stderr - * files are inside a folder, and have to be deleted before the - * folder itself is deleted, which can't be guaranteed when using - * the deleteOnExit() method. - */ - public static void handleQuit() { - // replace original streams to remove references to console's streams - System.setOut(systemOut); - System.setErr(systemErr); - - try { - // close the PrintStream - if (consoleOut != null) consoleOut.close(); - if (consoleErr != null) consoleErr.close(); - - // also have to close the original FileOutputStream - // otherwise it won't be shut down completely - if (stdoutFile != null) stdoutFile.close(); - if (stderrFile != null) stderrFile.close(); - - } catch (IOException e) { - e.printStackTrace(systemErr); - } + void setCurrent() { + current = this; //editor.console; + startTimer(); + Console.setEditor(sketchOut, sketchErr); } - synchronized public void message(String what, boolean err) { - if (err) { - systemErr.print(what); - } else { - systemOut.print(what); - } - + public void message(String what, boolean err) { if (err && (what.contains("invalid context 0x0") || (what.contains("invalid drawable")))) { // Respectfully declining... This is a quirk of more recent releases of // Java on Mac OS X, but is widely reported as the source of any other // bug or problem that a user runs into. It may well be a Processing // bug, but until we know, we're suppressing the messages. + } else if (err && what.contains("is calling TIS/TSM in non-main thread environment")) { + // Error message caused by JOGL since macOS 10.13.4, cannot fix at the moment so silencing it: + // https://github.com/processing/processing/issues/5462 + // Some discussion on the Apple's developer forums seems to suggest that is not serious: + // https://forums.developer.apple.com/thread/105244 + } else if (err && what.contains("NSWindow drag regions should only be invalidated on the Main Thread")) { + // Keep hiding warnings triggered by JOGL on recent macOS versions (this is from 10.14 onwards I think). } else if (err && what.contains("Make pbuffer:")) { // Remove initalization warning from LWJGL. } else if (err && what.contains("XInitThreads() called for concurrent")) { @@ -365,53 +269,20 @@ public void clear() { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - private static class EditorConsoleStream extends OutputStream { - final boolean err; // whether stderr or stdout - final byte single[] = new byte[1]; - EditorConsole console; + class EditorConsoleStream extends OutputStream { + boolean err; - public EditorConsoleStream(boolean err, EditorConsole console) { + public EditorConsoleStream(boolean err) { this.err = err; - this.console = console; - } - - public void close() { } - - public void flush() { } - - public void write(byte b[]) { // appears never to be used - write(b, 0, b.length); } public void write(byte b[], int offset, int length) { - if (console != null) { - console.message(new String(b, offset, length), err); - } else if (currentConsole != null) { - currentConsole.message(new String(b, offset, length), err); - } else { - // If no console is present, still need to write this to the actual - // System.out or System.err. Otherwise we can't !#$!% debug anything. - if (err) { - systemErr.write(b, offset, length); - } else { - systemOut.write(b, offset, length); - } - } - - final OutputStream echo = err ? stderrFile : stdoutFile; - if (echo != null) { - try { - echo.write(b, offset, length); - echo.flush(); - } catch (IOException e) { - e.printStackTrace(); - } - } + message(new String(b, offset, length), err); } + // doesn't appear to be called (but must be implemented) public void write(int b) { - single[0] = (byte) b; - write(single, 0, 1); + write(new byte[] { (byte) b }, 0, 1); } } } @@ -428,22 +299,32 @@ public void write(int b) { * swing event thread, so they need to be synchronized */ class BufferedStyledDocument extends DefaultStyledDocument { - List elements = new ArrayList(); - int maxLineLength, maxLineCount; + //List elements = new ArrayList<>(); + LinkedBlockingQueue elements; +// AtomicInteger queuedLineCount = new AtomicInteger(); + int maxLineLength, maxLineCount, maxCharCount; int currentLineLength = 0; boolean needLineBreak = false; - boolean hasAppendage = false; +// boolean hasAppendage = false; + final Object insertLock = new Object(); - public BufferedStyledDocument(int maxLineLength, int maxLineCount) { + public BufferedStyledDocument(int maxLineLength, int maxLineCount, + int maxCharCount) { this.maxLineLength = maxLineLength; this.maxLineCount = maxLineCount; + this.maxCharCount = maxCharCount; + elements = new LinkedBlockingQueue<>(); + } + + // monitor this so that it's only updated when needed (otherwise console + // updates every 250 ms when an app isn't even running.. see bug 180) + public boolean hasAppendage() { + return elements.size() > 0; } /** buffer a string for insertion at the end of the DefaultStyledDocument */ - public synchronized void appendString(String str, AttributeSet a) { - // do this so that it's only updated when needed (otherwise console - // updates every 250 ms when an app isn't even running.. see bug 180) - hasAppendage = true; + public void appendString(String str, AttributeSet a) { +// hasAppendage = true; // process each line of the string while (str.length() > 0) { @@ -452,6 +333,7 @@ public synchronized void appendString(String str, AttributeSet a) { if (needLineBreak || currentLineLength > maxLineLength) { elements.add(new ElementSpec(a, ElementSpec.EndTagType)); elements.add(new ElementSpec(a, ElementSpec.StartTagType)); +// queuedLineCount.incrementAndGet(); currentLineLength = 0; } @@ -467,15 +349,42 @@ public synchronized void appendString(String str, AttributeSet a) { needLineBreak = true; str = str.substring(str.indexOf('\n') + 1); // eat the line } + /* + while (queuedLineCount.get() > maxLineCount) { + Console.systemOut("too many: " + queuedLineCount); + ElementSpec elem = elements.remove(); + if (elem.getType() == ElementSpec.EndTagType) { + queuedLineCount.decrementAndGet(); + } + } + */ + } + if (elements.size() > 1000) { + insertAll(); } } /** insert the buffered strings */ - public synchronized void insertAll() { - ElementSpec[] elementArray = new ElementSpec[elements.size()]; - elements.toArray(elementArray); + public void insertAll() { + /* + // each line is ~3 elements + int tooMany = elements.size() - maxLineCount*3; + if (tooMany > 0) { + try { + remove(0, getLength()); // clear the document first + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + Console.systemOut("skipping " + elements.size()); + for (int i = 0; i < tooMany; i++) { + elements.remove(); + } + } + */ + ElementSpec[] elementArray = elements.toArray(new ElementSpec[0]); try { + /* // check how many lines have been used so far // if too many, shave off a few lines from the beginning Element element = super.getDefaultRootElement(); @@ -492,13 +401,42 @@ public synchronized void insertAll() { // remove to the end of the 200th line super.remove(0, endOffset); } - super.insert(super.getLength(), elementArray); + */ + synchronized (insertLock) { + checkLength(); + insert(getLength(), elementArray); + checkLength(); + } } catch (BadLocationException e) { // ignore the error otherwise this will cause an infinite loop // maybe not a good idea in the long run? } elements.clear(); - hasAppendage = false; +// hasAppendage = false; + } + + private void checkLength() throws BadLocationException { + // set a limit on the number of characters in the console + int docLength = getLength(); + if (docLength > maxCharCount) { + remove(0, docLength - maxCharCount); + } + // check how many lines have been used so far + // if too many, shave off a few lines from the beginning + Element element = super.getDefaultRootElement(); + int lineCount = element.getElementCount(); + int overage = lineCount - maxLineCount; + if (overage > 0) { + // if 1200 lines, and 1000 lines is max, + // find the position of the end of the 200th line + //systemOut.println("overage is " + overage); + Element lineElement = element.getElement(overage); + if (lineElement != null) { + int endOffset = lineElement.getEndOffset(); + // remove to the end of the 200th line + super.remove(0, endOffset); + } + } } } diff --git a/app/src/processing/app/ui/EditorException.java b/app/src/processing/app/ui/EditorException.java index 67c170a88f..9dc210edcb 100644 --- a/app/src/processing/app/ui/EditorException.java +++ b/app/src/processing/app/ui/EditorException.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2015 The Processing Foundation + Copyright (c) 2015-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 diff --git a/app/src/processing/app/ui/EditorFooter.java b/app/src/processing/app/ui/EditorFooter.java index 80c5c50dc0..81b16fc685 100644 --- a/app/src/processing/app/ui/EditorFooter.java +++ b/app/src/processing/app/ui/EditorFooter.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2015 The Processing Foundation + Copyright (c) 2015-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -50,21 +50,21 @@ */ public class EditorFooter extends Box { // height of this tab bar - static final int HIGH = 32; + static final int HIGH = Toolkit.zoom(32); - static final int CURVE_RADIUS = 6; + static final int CURVE_RADIUS = Toolkit.zoom(6); - static final int TAB_TOP = 2; - static final int TAB_BOTTOM = 29; + static final int TAB_TOP = Toolkit.zoom(2); + static final int TAB_BOTTOM = Toolkit.zoom(29); // amount of extra space between individual tabs - static final int TAB_BETWEEN = 2; + static final int TAB_BETWEEN = Toolkit.zoom(2); // amount of margin on the left/right for the text on the tab - static final int MARGIN = 14; + static final int MARGIN = Toolkit.zoom(14); - static final int ICON_WIDTH = 16; - static final int ICON_HEIGHT = 16; - static final int ICON_TOP = 7; - static final int ICON_MARGIN = 7; + static final int ICON_WIDTH = Toolkit.zoom(16); + static final int ICON_HEIGHT = Toolkit.zoom(16); + static final int ICON_TOP = Toolkit.zoom(7); + static final int ICON_MARGIN = Toolkit.zoom(7); static final int UNSELECTED = 0; static final int SELECTED = 1; @@ -229,11 +229,7 @@ public void paintComponent(Graphics screen) { sizeH = size.height; imageW = sizeW; imageH = sizeH; - if (Toolkit.highResDisplay()) { - offscreen = createImage(imageW*2, imageH*2); - } else { - offscreen = createImage(imageW, imageH); - } + offscreen = Toolkit.offscreenGraphics(this, imageW, imageH); } Graphics g = offscreen.getGraphics(); @@ -245,9 +241,10 @@ public void paintComponent(Graphics screen) { Graphics2D g2 = Toolkit.prepareGraphics(g); g.setColor(tabColor[SELECTED]); - g.fillRect(0, 0, imageW, 2); + // can't be done with lines, b/c retina leaves tiny hairlines + g.fillRect(0, 0, imageW, Toolkit.zoom(2)); - g.drawImage(gradient, 0, 2, imageW, imageH, this); + g.drawImage(gradient, 0, Toolkit.zoom(2), imageW, imageH, this); // reset all tab positions for (Tab tab : tabs) { @@ -258,14 +255,9 @@ public void paintComponent(Graphics screen) { // now actually draw the tabs drawTabs(Editor.LEFT_GUTTER, g2); + // the number of updates available in the Manager drawUpdates(g2); -// // draw the two pixel line that extends left/right below the tabs -// g.setColor(tabColor[SELECTED]); -// // can't be done with lines, b/c retina leaves tiny hairlines -// g.fillRect(Editor.LEFT_GUTTER, TAB_BOTTOM, -// editor.getTextArea().getWidth() - Editor.LEFT_GUTTER, 2); - screen.drawImage(offscreen, 0, 0, imageW, imageH, null); } @@ -295,7 +287,7 @@ private void drawTabs(int left, Graphics2D g) { private void drawUpdates(Graphics2D g2) { if (updateCount != 0) { FontRenderContext frc = g2.getFontRenderContext(); - final int GAP = 5; + final int GAP = Toolkit.zoom(5); final String updateLabel = "Updates"; String updatesStr = "" + updateCount; double countWidth = font.getStringBounds(updatesStr, frc).getWidth(); @@ -319,7 +311,7 @@ private void drawUpdates(Graphics2D g2) { public Dimension getPreferredSize() { - return new Dimension(300, HIGH); + return new Dimension(Toolkit.zoom(300), HIGH); } diff --git a/app/src/processing/app/ui/EditorHeader.java b/app/src/processing/app/ui/EditorHeader.java index e669314196..50fa1b8bf8 100644 --- a/app/src/processing/app/ui/EditorHeader.java +++ b/app/src/processing/app/ui/EditorHeader.java @@ -3,8 +3,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation - Copyright (c) 2004-13 Ben Fry and Casey Reas + Copyright (c) 2012-19 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify @@ -44,26 +44,25 @@ */ public class EditorHeader extends JComponent { // height of this tab bar - static final int HIGH = 29; + static final int HIGH = Toolkit.zoom(29); - static final int ARROW_TAB_WIDTH = 18; - static final int ARROW_TOP = 11; - static final int ARROW_BOTTOM = 18; - static final int ARROW_WIDTH = 6; + static final int ARROW_TAB_WIDTH = Toolkit.zoom(18); + static final int ARROW_TOP = Toolkit.zoom(11); + static final int ARROW_BOTTOM = Toolkit.zoom(18); + static final int ARROW_WIDTH = Toolkit.zoom(6); - static final int CURVE_RADIUS = 6; + static final int CURVE_RADIUS = Toolkit.zoom(6); static final int TAB_TOP = 0; - static final int TAB_BOTTOM = 27; + static final int TAB_BOTTOM = Toolkit.zoom(27); // amount of extra space between individual tabs - static final int TAB_BETWEEN = 3; + static final int TAB_BETWEEN = Toolkit.zoom(3); // amount of margin on the left/right for the text on the tab - static final int TEXT_MARGIN = 16; + static final int TEXT_MARGIN = Toolkit.zoom(16); // width of the tab when no text visible // (total tab width will be this plus TEXT_MARGIN*2) - static final int NO_TEXT_WIDTH = 16; + static final int NO_TEXT_WIDTH = Toolkit.zoom(16); -// Color bgColor; Color textColor[] = new Color[2]; Color tabColor[] = new Color[2]; Color modifiedColor; @@ -185,11 +184,7 @@ public void paintComponent(Graphics screen) { sizeH = size.height; imageW = sizeW; imageH = sizeH; - if (Toolkit.highResDisplay()) { - offscreen = createImage(imageW*2, imageH*2); - } else { - offscreen = createImage(imageW, imageH); - } + offscreen = Toolkit.offscreenGraphics(this, imageW, imageH); } Graphics g = offscreen.getGraphics(); @@ -199,6 +194,7 @@ public void paintComponent(Graphics screen) { } Graphics2D g2 = Toolkit.prepareGraphics(g); +// Toolkit.dpiStroke(g2); g.drawImage(gradient, 0, 0, imageW, imageH, this); @@ -265,7 +261,8 @@ public void paintComponent(Graphics screen) { g.setColor(tabColor[SELECTED]); // can't be done with lines, b/c retina leaves tiny hairlines g.fillRect(Editor.LEFT_GUTTER, TAB_BOTTOM, - editor.getTextArea().getWidth() - Editor.LEFT_GUTTER, 2); + editor.getTextArea().getWidth() - Editor.LEFT_GUTTER, + Toolkit.zoom(2)); // draw the tab for the menu g.setColor(tabColor[UNSELECTED]); @@ -497,47 +494,29 @@ public void actionPerformed(ActionEvent e) { // KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep - final String prevTab = Language.text("editor.header.previous_tab"); - if (Platform.isLinux()) { - item = Toolkit.newJMenuItem(prevTab, KeyEvent.VK_PAGE_UP); - } else { - item = Toolkit.newJMenuItemAlt(prevTab, KeyEvent.VK_LEFT); - } + mapKey = "editor.header.previous_tab"; + item = Toolkit.newJMenuItemExt(mapKey); action = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { editor.getSketch().handlePrevCode(); } }; - mapKey = "editor.header.previous_tab"; - if (Platform.isLinux()) { - keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, Toolkit.SHORTCUT_KEY_MASK); - } else { - keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.SHORTCUT_ALT_KEY_MASK); - } + keyStroke = item.getAccelerator(); inputMap.put(keyStroke, mapKey); actionMap.put(mapKey, action); item.addActionListener(action); menu.add(item); - final String nextTab = Language.text("editor.header.next_tab"); - if (Platform.isLinux()) { - item = Toolkit.newJMenuItem(nextTab, KeyEvent.VK_PAGE_DOWN); - } else { - item = Toolkit.newJMenuItemAlt(nextTab, KeyEvent.VK_RIGHT); - } + mapKey = "editor.header.next_tab"; + item = Toolkit.newJMenuItemExt(mapKey); action = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { editor.getSketch().handleNextCode(); } }; - mapKey = "editor.header.next_tab"; - if (Platform.isLinux()) { - keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, Toolkit.SHORTCUT_KEY_MASK); - } else { - keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.SHORTCUT_ALT_KEY_MASK); - } + keyStroke = item.getAccelerator(); inputMap.put(keyStroke, mapKey); actionMap.put(mapKey, action); item.addActionListener(action); diff --git a/app/src/processing/app/ui/EditorState.java b/app/src/processing/app/ui/EditorState.java index d44dd3b07f..b560bf8ed8 100644 --- a/app/src/processing/app/ui/EditorState.java +++ b/app/src/processing/app/ui/EditorState.java @@ -3,6 +3,7 @@ /* Part of the Processing project - http://processing.org + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -158,8 +159,10 @@ GraphicsConfiguration defaultConfig() { * @param editors List of editors currently opened */ void defaultLocation(List editors) { - int defaultWidth = Preferences.getInteger("editor.window.width.default"); - int defaultHeight = Preferences.getInteger("editor.window.height.default"); + int defaultWidth = + Toolkit.zoom(Preferences.getInteger("editor.window.width.default")); + int defaultHeight = + Toolkit.zoom(Preferences.getInteger("editor.window.height.default")); defaultWidth = Math.min(defaultWidth, deviceBounds.width); defaultHeight = Math.min(defaultHeight, deviceBounds.height); @@ -217,9 +220,12 @@ void update(Editor editor) { void apply(Editor editor) { editor.setBounds(editorBounds); - if (dividerLocation != 0) { - editor.setDividerLocation(dividerLocation); + + if (dividerLocation == 0) { + dividerLocation = 2 * editor.getSize().height / 3; } + editor.setDividerLocation(dividerLocation); + if (isMaximized) { editor.setExtendedState(Frame.MAXIMIZED_BOTH); } diff --git a/app/src/processing/app/ui/EditorStatus.java b/app/src/processing/app/ui/EditorStatus.java index 73269775c0..8affa8c6a3 100644 --- a/app/src/processing/app/ui/EditorStatus.java +++ b/app/src/processing/app/ui/EditorStatus.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -31,59 +31,89 @@ import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; import processing.app.Mode; import processing.app.Platform; +import processing.app.Preferences; import processing.core.PApplet; /** * Panel just below the editing area that contains status messages. */ -public class EditorStatus extends BasicSplitPaneDivider { //JPanel { - static final int HIGH = 28; +public class EditorStatus extends BasicSplitPaneDivider { + static final int HIGH = Toolkit.zoom(28); static final int LEFT_MARGIN = Editor.LEFT_GUTTER; - static final int RIGHT_MARGIN = 20; + static final int RIGHT_MARGIN = Toolkit.zoom(20); + Color urlColor; Color[] fgColor; Color[] bgColor; Image[] bgImage; @SuppressWarnings("hiding") - static public final int ERROR = 1; + static public final int ERROR = 1; static public final int CURSOR_LINE_ERROR = 2; static public final int WARNING = 3; static public final int CURSOR_LINE_WARNING = 4; - static public final int NOTICE = 0; + static public final int NOTICE = 0; - static final int YES = 1; - static final int NO = 2; + static final int YES = 1; + static final int NO = 2; static final int CANCEL = 3; - static final int OK = 4; - - static final String NO_MESSAGE = ""; + static final int OK = 4; Editor editor; int mode; - String message; + String message = ""; + String url; + int rightEdge; + int mouseX; + + static final int ROLLOVER_NONE = 0; + static final int ROLLOVER_URL = 1; + static final int ROLLOVER_COLLAPSE = 2; + static final int ROLLOVER_CLIPBOARD = 3; + int rolloverState; + Font font; FontMetrics metrics; int ascent; + // actual Clipboard character not available [fry 180326] + //static final String CLIPBOARD_GLYPH = "\uD83D\uDCCB"; + // other apps seem to use this one as a hack + static final String CLIPBOARD_GLYPH = "\u2398"; + + // https://en.wikipedia.org/wiki/Geometric_Shapes +// static final String COLLAPSE_GLYPH = "\u25B3"; // large up +// static final String EXPAND_GLYPH = "\u25BD"; // large down +// static final String COLLAPSE_GLYPH = "\u25B5"; // small up (unavailable) +// static final String EXPAND_GLYPH = "\u25BF"; // small down (unavailable) + static final String COLLAPSE_GLYPH = "\u25C1"; // left + static final String EXPAND_GLYPH = "\u25B7"; // right +// static final String COLLAPSE_GLYPH = "\u25F8"; // upper-left (unavailable) +// static final String EXPAND_GLYPH = "\u25FF"; // lower-right (unavailable) + + // a font that supports the Unicode glyphs we need + Font glyphFont; + Image offscreen; int sizeW, sizeH; - -// JButton cancelButton; -// JButton okButton; -// JTextField editField; + // size of the glyph buttons (width and height are identical) + int buttonSize; + boolean collapsed = false; int response; @@ -98,18 +128,85 @@ public EditorStatus(BasicSplitPaneUI ui, Editor editor) { updateMode(); addMouseListener(new MouseAdapter() { + + @Override public void mouseEntered(MouseEvent e) { - if (url != null) { - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } + updateMouse(); } + @Override public void mousePressed(MouseEvent e) { - if (url != null) { + if (rolloverState == ROLLOVER_URL) { Platform.openURL(url); + + } else if (rolloverState == ROLLOVER_CLIPBOARD) { + if (e.isShiftDown()) { + // open the text in a browser window as a search + final String fmt = Preferences.get("search.format"); + Platform.openURL(String.format(fmt, PApplet.urlEncode(message))); + + } else { + // copy the text to the clipboard + Clipboard clipboard = getToolkit().getSystemClipboard(); + clipboard.setContents(new StringSelection(message), null); + System.out.println("Copied to the clipboard. " + + "Use shift-click to search the web instead."); + } + + } else if (rolloverState == ROLLOVER_COLLAPSE) { + setCollapsed(!collapsed); } } + + @Override + public void mouseExited(MouseEvent e) { + mouseX = -100; + updateMouse(); + } + }); + + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + // BasicSplitPaneUI.startDragging gets called even when you click but + // don't drag, so we can't expand the console whenever that gets called + // or the button wouldn't work. + setCollapsed(false); + } + + @Override + public void mouseMoved(MouseEvent e) { + mouseX = e.getX(); + updateMouse(); + } + }); + } + + + void setCollapsed(boolean newState) { + if (collapsed != newState) { + collapsed = newState; + editor.footer.setVisible(!newState); + splitPane.resetToPreferredSizes(); + } + } + + + void updateMouse() { + switch (rolloverState) { + case ROLLOVER_CLIPBOARD: + case ROLLOVER_URL: + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + break; + case ROLLOVER_COLLAPSE: + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + break; + case ROLLOVER_NONE: + setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + break; + } + repaint(); } @@ -125,6 +222,8 @@ static String findURL(String message) { public void updateMode() { Mode mode = editor.getMode(); + urlColor = mode.getColor("status.url.fgcolor"); + fgColor = new Color[] { mode.getColor("status.notice.fgcolor"), mode.getColor("status.error.fgcolor"), @@ -150,13 +249,14 @@ public void updateMode() { }; font = mode.getFont("status.font"); + glyphFont = mode.getFont("status.emoji.font"); metrics = null; } public void empty() { mode = NOTICE; - message = NO_MESSAGE; + message = ""; url = null; repaint(); } @@ -229,8 +329,6 @@ public void stopIndeterminate() { //public void paintComponent(Graphics screen) { public void paint(Graphics screen) { -// if (okButton == null) setup(); - Dimension size = getSize(); if ((size.width != sizeW) || (size.height != sizeH)) { // component has been resized @@ -240,12 +338,8 @@ public void paint(Graphics screen) { if (offscreen == null) { sizeW = size.width; sizeH = size.height; -// setButtonBounds(); - if (Toolkit.highResDisplay()) { - offscreen = createImage(sizeW*2, sizeH*2); - } else { - offscreen = createImage(sizeW, sizeH); - } + buttonSize = sizeH; + offscreen = Toolkit.offscreenGraphics(this, sizeW, sizeH); } Graphics g = offscreen.getGraphics(); @@ -257,14 +351,31 @@ public void paint(Graphics screen) { ascent = metrics.getAscent(); } - //g.setColor(bgColor[mode]); - //g.fillRect(0, 0, sizeW, sizeH); g.drawImage(bgImage[mode], 0, 0, sizeW, sizeH, this); - g.setColor(fgColor[mode]); + rolloverState = ROLLOVER_NONE; + if (mouseX > sizeW - buttonSize && mouseX < sizeW) { + rolloverState = ROLLOVER_COLLAPSE; + + } else if (message != null && !message.isEmpty()) { + if (sizeW - 2*buttonSize < mouseX) { + rolloverState = ROLLOVER_CLIPBOARD; + + } else if (url != null && mouseX > LEFT_MARGIN && + // calculate right edge of the text for rollovers (otherwise the pane + // cannot be resized up or down whenever a URL is being displayed) + mouseX < (LEFT_MARGIN + g.getFontMetrics().stringWidth(message))) { + rolloverState = ROLLOVER_URL; + } + } + // https://github.com/processing/processing/issues/3265 if (message != null) { - g.setFont(font); // needs to be set each time on osx + // font needs to be set each time on osx + g.setFont(font); + // set the highlight color on rollover so that the user's not surprised + // to see the web browser open when they click + g.setColor((rolloverState == ROLLOVER_URL) ? urlColor : fgColor[mode]); g.drawString(message, LEFT_MARGIN, (sizeH + ascent) / 2); } @@ -272,28 +383,61 @@ public void paint(Graphics screen) { //int x = cancelButton.getX(); //int w = cancelButton.getWidth(); int w = Toolkit.getButtonWidth(); - int x = getWidth() - RIGHT_MARGIN - w; - int y = getHeight() / 3; - int h = getHeight() / 3; + int x = getWidth() - Math.max(RIGHT_MARGIN, (int)(buttonSize*1.2)) - w; + int y = sizeH / 3; + int h = sizeH / 3; g.setColor(new Color(0x80000000, true)); g.drawRect(x, y, w, h); for (int i = 0; i < 10; i++) { int r = (int) (x + Math.random() * w); g.drawLine(r, y, r, y+h); } + + } else if (!message.isEmpty()) { + g.setFont(glyphFont); + drawButton(g, CLIPBOARD_GLYPH, 1, rolloverState == ROLLOVER_CLIPBOARD); + g.setFont(font); } + // draw collapse/expand button + String collapseGlyph = collapsed ? EXPAND_GLYPH : COLLAPSE_GLYPH; + drawButton(g, collapseGlyph, 0, rolloverState == ROLLOVER_COLLAPSE); + screen.drawImage(offscreen, 0, 0, sizeW, sizeH, null); } + //private final Color whitishTint = new Color(0x20eeeeee, true); + + /** + * @param pos A zero-based button index with 0 as the rightmost button + */ + private void drawButton(Graphics g, String symbol, int pos, boolean highlight) { + int left = sizeW - (pos + 1) * buttonSize; + // Overlap very long errors + g.drawImage(bgImage[mode], left, 0, buttonSize, sizeH, this); + + if (highlight) { + // disabling since this doesn't match any of our other UI +// g.setColor(whitishTint); +// g.fillRect(left, 0, sizeH, sizeH); + g.setColor(urlColor); + } else { + g.setColor(fgColor[mode]); + } + g.drawString(symbol, + left + (buttonSize - g.getFontMetrics().stringWidth(symbol))/2, + (sizeH + ascent) / 2); + } + + public Dimension getPreferredSize() { return getMinimumSize(); } public Dimension getMinimumSize() { - return new Dimension(300, HIGH); + return new Dimension(Toolkit.zoom(300), HIGH); } diff --git a/app/src/processing/app/ui/EditorToolbar.java b/app/src/processing/app/ui/EditorToolbar.java index 0af6c8a4c1..63fa851acf 100644 --- a/app/src/processing/app/ui/EditorToolbar.java +++ b/app/src/processing/app/ui/EditorToolbar.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyirght (c) 2012-15 The Processing Foundation + Copyirght (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -52,11 +52,11 @@ abstract public class EditorToolbar extends JPanel implements KeyListener { // haven't decided how to handle this/how to make public/consistency // for components/does it live in theme.txt - static final int HIGH = 53; + static final int HIGH = Toolkit.zoom(53); // horizontal gap between buttons - static final int GAP = 9; + static final int GAP = Toolkit.zoom(9); // corner radius on the mode selector - static final int RADIUS = 3; + static final int RADIUS = Toolkit.zoom(3); protected Editor editor; protected Base base; @@ -78,8 +78,7 @@ public EditorToolbar(Editor editor) { base = editor.getBase(); mode = editor.getMode(); - gradient = mode.makeGradient("toolbar", 400, HIGH); -// reverseGradient = mode.getGradient("reversed", 100, EditorButton.DIM); + gradient = mode.makeGradient("toolbar", Toolkit.zoom(400), HIGH); rebuild(); } @@ -286,11 +285,11 @@ class ModeSelector extends JPanel { int titleAscent; int titleWidth; - final int MODE_GAP_WIDTH = 13; - final int ARROW_GAP_WIDTH = 6; - final int ARROW_WIDTH = 6; - final int ARROW_TOP = 12; - final int ARROW_BOTTOM = 18; + final int MODE_GAP_WIDTH = Toolkit.zoom(13); + final int ARROW_GAP_WIDTH = Toolkit.zoom(6); + final int ARROW_WIDTH = Toolkit.zoom(6); + final int ARROW_TOP = Toolkit.zoom(12); + final int ARROW_BOTTOM = Toolkit.zoom(18); int[] triangleX = new int[3]; int[] triangleY = new int[] { ARROW_TOP, ARROW_TOP, ARROW_BOTTOM }; @@ -328,11 +327,7 @@ public void paintComponent(Graphics screen) { Dimension size = getSize(); width = 0; if (width != size.width || height != size.height) { - if (Toolkit.highResDisplay()) { - offscreen = createImage(size.width*2, size.height*2); - } else { - offscreen = createImage(size.width, size.height); - } + offscreen = Toolkit.offscreenGraphics(this, size.width, size.height); width = size.width; height = size.height; } @@ -357,6 +352,7 @@ public void paintComponent(Graphics screen) { // draw the outline for this feller g.setColor(outlineColor); + //Toolkit.dpiStroke(g2); g2.draw(Toolkit.createRoundRect(1, 1, width-1, height-1, RADIUS, RADIUS, RADIUS, RADIUS)); diff --git a/app/src/processing/app/ui/ErrorTable.java b/app/src/processing/app/ui/ErrorTable.java index 14d02e11cd..8abfdf77a0 100644 --- a/app/src/processing/app/ui/ErrorTable.java +++ b/app/src/processing/app/ui/ErrorTable.java @@ -2,7 +2,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + + Copyright (c) 2012-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -40,7 +41,6 @@ import processing.app.Language; import processing.app.Mode; import processing.app.Problem; -import processing.app.ui.Editor; public class ErrorTable extends JTable { @@ -62,9 +62,9 @@ public class ErrorTable extends JTable { Color headerColor; Color headerBgColor; - Font rowFont; - Color rowColor; - Color rowBgColor; +// Font rowFont; +// Color rowColor; +// Color rowBgColor; public ErrorTable(final Editor editor) { @@ -117,6 +117,7 @@ synchronized public void mouseClicked(MouseEvent e) { }); header.setReorderingAllowed(false); + setFillsViewportHeight(true); ToolTipManager.sharedInstance().registerComponent(this); } @@ -158,6 +159,18 @@ public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) { + + // Adjust height for magnified displays. The font is scaled properly, + // but the rows don't automatically use the scaled preferred size. + // https://github.com/processing/processing/issues/4936 + int high = getPreferredSize().height; + if (high != 0) { + JTableHeader header = table.getTableHeader(); + int current = header.getSize().height; + if (current != high) { + table.setPreferredSize(new Dimension(table.getWidth(), high)); + } + } setText(value == null ? "" : value.toString()); return this; } @@ -175,7 +188,6 @@ static class GradyRowRenderer extends JLabel implements TableCellRenderer { Color bgColorError; Color bgColorWarning; -// int indicatorSize; Color errorIndicatorColor; Color warningIndicatorColor; @@ -190,7 +202,6 @@ public GradyRowRenderer(Mode mode) { bgColorError = mode.getColor("errors.selection.error.bgcolor"); bgColorWarning = mode.getColor("errors.selection.warning.bgcolor"); -// indicatorSize = mode.getInteger("errors.indicator.size"); errorIndicatorColor = mode.getColor("errors.indicator.error.color"); warningIndicatorColor = mode.getColor("errors.indicator.warning.color"); @@ -204,6 +215,17 @@ public Component getTableCellRendererComponent(JTable table, Object value, int row, int column) { Problem entry = (Problem) table.getValueAt(row, DATA_COLUMN); + // Adjust row height for magnified displays. The font is scaled properly, + // but the rows don't automatically use the scaled preferred size. + // https://github.com/processing/processing/issues/4936 + int high = getPreferredSize().height; + if (high != 0) { + int current = table.getRowHeight(); + if (current != high) { + table.setRowHeight(high); + } + } + if (selected) { setForeground(textColorSelected); if (entry.isError()) { diff --git a/app/src/processing/app/ui/ExamplesFrame.java b/app/src/processing/app/ui/ExamplesFrame.java index 105858a87a..70258650d5 100644 --- a/app/src/processing/app/ui/ExamplesFrame.java +++ b/app/src/processing/app/ui/ExamplesFrame.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,7 +26,6 @@ import java.awt.Color; import java.awt.Component; import java.awt.Cursor; -import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Point; import java.awt.event.ActionEvent; @@ -183,9 +182,12 @@ public void treeCollapsed(TreeExpansionEvent event) { tree.setToggleClickCount(1); } + // Special cell renderer that takes the UI zoom into account + tree.setCellRenderer(new ZoomTreeCellRenderer(mode)); + JScrollPane treePane = new JScrollPane(tree); - treePane.setPreferredSize(new Dimension(250, 300)); - treePane.setBorder(new EmptyBorder(2, 0, 0, 0)); + treePane.setPreferredSize(Toolkit.zoom(250, 300)); + treePane.setBorder(new EmptyBorder(Toolkit.zoom(2), 0, 0, 0)); treePane.setOpaque(true); treePane.setBackground(Color.WHITE); treePane.setAlignmentX(Component.LEFT_ALIGNMENT); diff --git a/app/src/processing/app/ui/FindReplace.java b/app/src/processing/app/ui/FindReplace.java index b9e9409cac..757ab96251 100644 --- a/app/src/processing/app/ui/FindReplace.java +++ b/app/src/processing/app/ui/FindReplace.java @@ -3,6 +3,7 @@ /* Part of the Processing project - http://processing.org + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -424,10 +425,10 @@ protected void setFound(boolean found) { */ public void replace(boolean isCompoundEdit) { editor.setSelectedText(replaceField.getText(), isCompoundEdit); - + editor.getSketch().setModified(true); // This necessary- calling replace() // doesn't seem to mark a sketch as modified - + setFound(false); } diff --git a/app/src/processing/app/ui/MarkerColumn.java b/app/src/processing/app/ui/MarkerColumn.java index 03dc948e32..8d6371fbd5 100644 --- a/app/src/processing/app/ui/MarkerColumn.java +++ b/app/src/processing/app/ui/MarkerColumn.java @@ -2,7 +2,8 @@ /* Part of the Processing project - http://processing.org -Copyright (c) 2012-16 The Processing Foundation + +Copyright (c) 2012-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -38,7 +39,6 @@ import processing.app.Sketch; import processing.app.SketchCode; import processing.app.syntax.PdeTextArea; -import processing.app.ui.Editor; import processing.core.PApplet; @@ -60,7 +60,7 @@ public class MarkerColumn extends JPanel { private Color warningColor; // Stores error markers displayed PER TAB along the error bar. - private List errorPoints = new ArrayList(); + private List errorPoints = new ArrayList<>(); public MarkerColumn(Editor editor, int height) { diff --git a/app/src/processing/app/ui/PreferencesFrame.java b/app/src/processing/app/ui/PreferencesFrame.java index f475f6bf3e..d4684b2e24 100644 --- a/app/src/processing/app/ui/PreferencesFrame.java +++ b/app/src/processing/app/ui/PreferencesFrame.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -37,7 +37,6 @@ import processing.app.Messages; import processing.app.Platform; import processing.app.Preferences; -import processing.app.ui.ColorChooser; import processing.core.*; @@ -69,7 +68,9 @@ public class PreferencesFrame { JCheckBox warningsCheckerBox; JCheckBox codeCompletionBox; JCheckBox importSuggestionsBox; - //JCheckBox codeCompletionTriggerBox; + + JComboBox zoomSelectionBox; + JCheckBox zoomAutoBox; JComboBox displaySelectionBox; JComboBox languageSelectionBox; @@ -96,9 +97,9 @@ public PreferencesFrame(Base base) { pain.setLayout(layout); - final int BORDER = Platform.isMacOS() ? 20 : 13; - - JLabel sketchbookLocationLabel, restartProcessingLabel; + JLabel sketchbookLocationLabel; + JLabel languageRestartLabel; + JLabel zoomRestartLabel; JButton browseButton; //, button2; @@ -123,7 +124,7 @@ public void actionPerformed(ActionEvent e) { // Language: [ English ] (requires restart of Processing) JLabel languageLabel = new JLabel(Language.text("preferences.language")+": "); - languageSelectionBox = new JComboBox(); + languageSelectionBox = new JComboBox<>(); Map languages = Language.getLanguages(); String[] languageSelection = new String[languages.size()]; @@ -134,8 +135,8 @@ public void actionPerformed(ActionEvent e) { languageSelection[i++] = lang.getValue(); } } - languageSelectionBox.setModel(new DefaultComboBoxModel(languageSelection)); - restartProcessingLabel = new JLabel(" (" + Language.text("preferences.requires_restart") + ")"); + languageSelectionBox.setModel(new DefaultComboBoxModel<>(languageSelection)); + languageRestartLabel = new JLabel(" (" + Language.text("preferences.requires_restart") + ")"); // Editor and console font [ Source Code Pro ] @@ -144,7 +145,7 @@ public void actionPerformed(ActionEvent e) { final String fontTip = "" + Language.text("preferences.editor_and_console_font.tip"); fontLabel.setToolTipText(fontTip); // get a wide name in there before getPreferredSize() is called - fontSelectionBox = new JComboBox(new String[] { Toolkit.getMonoFontName() }); + fontSelectionBox = new JComboBox<>(new String[] { Toolkit.getMonoFontName() }); fontSelectionBox.setToolTipText(fontTip); fontSelectionBox.setEnabled(false); // don't enable until fonts are loaded @@ -152,12 +153,31 @@ public void actionPerformed(ActionEvent e) { // Editor font size [ 12 ] Console font size [ 10 ] JLabel fontSizelabel = new JLabel(Language.text("preferences.editor_font_size")+": "); - fontSizeField = new JComboBox(FONT_SIZES); + fontSizeField = new JComboBox<>(FONT_SIZES); JLabel consoleFontSizeLabel = new JLabel(Language.text("preferences.console_font_size")+": "); - consoleFontSizeField = new JComboBox(FONT_SIZES); + consoleFontSizeField = new JComboBox<>(FONT_SIZES); fontSizeField.setSelectedItem(Preferences.getFont("editor.font.size")); + + // Interface scale: [ 100% ] (requires restart of Processing) + + JLabel zoomLabel = new JLabel(Language.text("preferences.zoom") + ": "); + + zoomAutoBox = new JCheckBox(Language.text("preferences.zoom.auto")); + zoomAutoBox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + zoomSelectionBox.setEnabled(!zoomAutoBox.isSelected()); + } + }); + + zoomSelectionBox = new JComboBox<>(); + zoomSelectionBox.setModel(new DefaultComboBoxModel<>(Toolkit.zoomOptions.array())); + zoomRestartLabel = new JLabel(" (" + Language.text("preferences.requires_restart") + ")"); + + // + JLabel backgroundColorLabel = new JLabel(Language.text("preferences.background_color")+": "); final String colorTip = "" + Language.text("preferences.background_color.tip"); @@ -326,7 +346,7 @@ public void stateChanged(ChangeEvent e) { JLabel displayLabel = new JLabel(Language.text("preferences.run_sketches_on_display") + ": "); final String tip = "" + Language.text("preferences.run_sketches_on_display.tip"); displayLabel.setToolTipText(tip); - displaySelectionBox = new JComboBox(); + displaySelectionBox = new JComboBox<>(); updateDisplayList(); // needs to happen here for getPreferredSize() @@ -383,7 +403,7 @@ public void actionPerformed(ActionEvent e) { final int buttonWidth = Toolkit.getButtonWidth(); layout.setHorizontalGroup(layout.createSequentialGroup() // sequential group for border + mainContent + border - .addGap(BORDER) + .addGap(Toolkit.BORDER) .addGroup(layout.createParallelGroup() // parallel group for rest of the components .addComponent(sketchbookLocationLabel) .addGroup(layout.createSequentialGroup() @@ -392,7 +412,7 @@ public void actionPerformed(ActionEvent e) { .addGroup(layout.createSequentialGroup() .addComponent(languageLabel) .addComponent(languageSelectionBox,GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) // This makes the component non-resizable in the X direction - .addComponent(restartProcessingLabel)) + .addComponent(languageRestartLabel)) .addGroup(layout.createSequentialGroup() .addComponent(fontLabel) .addComponent(fontSelectionBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) @@ -402,6 +422,11 @@ public void actionPerformed(ActionEvent e) { .addComponent(fontSizeField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(consoleFontSizeLabel) .addComponent(consoleFontSizeField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(zoomLabel) + .addComponent(zoomAutoBox) + .addComponent(zoomSelectionBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(zoomRestartLabel)) .addGroup(layout.createSequentialGroup() .addComponent(backgroundColorLabel) .addComponent(hashLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) @@ -440,11 +465,11 @@ public void actionPerformed(ActionEvent e) { .addComponent(okButton, buttonWidth, GroupLayout.DEFAULT_SIZE, buttonWidth) // Ok and Cancel buttton are now of size BUTTON_WIDTH .addComponent(cancelButton, buttonWidth, GroupLayout.DEFAULT_SIZE, buttonWidth) )) - .addGap(BORDER) + .addGap(Toolkit.BORDER) ); layout.setVerticalGroup(layout.createSequentialGroup() // sequential group for border + mainContent + border - .addGap(BORDER) + .addGap(Toolkit.BORDER) .addComponent(sketchbookLocationLabel) .addGroup(layout.createParallelGroup() .addComponent(sketchbookLocationField) @@ -452,7 +477,7 @@ public void actionPerformed(ActionEvent e) { .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(languageLabel) .addComponent(languageSelectionBox) - .addComponent(restartProcessingLabel)) + .addComponent(languageRestartLabel)) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER). addComponent(fontLabel) .addComponent(fontSelectionBox)) @@ -461,6 +486,11 @@ public void actionPerformed(ActionEvent e) { .addComponent(fontSizeField) .addComponent(consoleFontSizeLabel) .addComponent(consoleFontSizeField)) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) + .addComponent(zoomLabel) + .addComponent(zoomAutoBox) + .addComponent(zoomSelectionBox) + .addComponent(zoomRestartLabel)) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(backgroundColorLabel) .addComponent(hashLabel) @@ -491,7 +521,7 @@ public void actionPerformed(ActionEvent e) { .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(okButton) .addComponent(cancelButton)) - .addGap(BORDER) + .addGap(Toolkit.BORDER) ); if (Platform.isWindows()){ @@ -635,6 +665,10 @@ protected void applyFrame() { fontSizeField.setSelectedItem(Preferences.getInteger("editor.font.size")); } + Preferences.setBoolean("editor.zoom.auto", zoomAutoBox.isSelected()); + Preferences.set("editor.zoom", + String.valueOf(zoomSelectionBox.getSelectedItem())); + try { Object selection = consoleFontSizeField.getSelectedItem(); if (selection instanceof String) { @@ -704,6 +738,19 @@ public void run() { fontSizeField.setSelectedItem(Preferences.getInteger("editor.font.size")); consoleFontSizeField.setSelectedItem(Preferences.getInteger("console.font.size")); + boolean zoomAuto = Preferences.getBoolean("editor.zoom.auto"); + if (zoomAuto) { + zoomAutoBox.setSelected(zoomAuto); + zoomSelectionBox.setEnabled(!zoomAuto); + } + String zoomSel = Preferences.get("editor.zoom"); + int zoomIndex = Toolkit.zoomOptions.index(zoomSel); + if (zoomIndex != -1) { + zoomSelectionBox.setSelectedIndex(zoomIndex); + } else { + zoomSelectionBox.setSelectedIndex(0); + } + presentColor.setBackground(Preferences.getColor("run.present.bgcolor")); presentColorHex.setText(Preferences.get("run.present.bgcolor").substring(1)); @@ -752,7 +799,7 @@ void initFontList() { EventQueue.invokeLater(new Runnable() { @Override public void run() { - fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies)); + fontSelectionBox.setModel(new DefaultComboBoxModel<>(monoFontFamilies)); String family = Preferences.get("editor.font.family"); // Set a reasonable default, in case selecting the family fails @@ -787,7 +834,7 @@ int updateDisplayList() { } items[i] = title; } - displaySelectionBox.setModel(new DefaultComboBoxModel(items)); + displaySelectionBox.setModel(new DefaultComboBoxModel<>(items)); // Disable it if you can't actually change the default display displaySelectionBox.setEnabled(displayCount != 1); diff --git a/app/src/processing/app/ui/Recent.java b/app/src/processing/app/ui/Recent.java index 11599374e0..bc26761736 100644 --- a/app/src/processing/app/ui/Recent.java +++ b/app/src/processing/app/ui/Recent.java @@ -3,6 +3,7 @@ /* Part of the Processing project - http://processing.org + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify @@ -77,7 +78,7 @@ static public void init(Base b) { static protected void load() throws IOException { - records = new ArrayList(); + records = new ArrayList<>(); if (file.exists()) { BufferedReader reader = PApplet.createReader(file); String version = reader.readLine(); @@ -103,6 +104,7 @@ static protected void load() throws IOException { static protected void save() { + file.setWritable(true, false); PrintWriter writer = PApplet.createWriter(file); writer.println(VERSION); for (Record record : records) { @@ -240,6 +242,8 @@ public void actionPerformed(ActionEvent e) { synchronized static public void remove(Editor editor) { int index = findRecord(editor.getSketch().getMainFilePath()); if (index != -1) { + System.out.println("removing " + editor.getSketch().getMainFilePath()); + new Exception().printStackTrace(System.out); records.remove(index); } } @@ -289,6 +293,7 @@ synchronized static public void append(Editor editor) { // If this sketch is already in the menu, remove it remove(editor); + // If the list is full, remove the first entry if (records.size() == Preferences.getInteger("recent.count")) { records.remove(0); // remove the first entry } diff --git a/app/src/processing/app/ui/SketchbookFrame.java b/app/src/processing/app/ui/SketchbookFrame.java index e1b9ede034..ae36203a29 100644 --- a/app/src/processing/app/ui/SketchbookFrame.java +++ b/app/src/processing/app/ui/SketchbookFrame.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +23,6 @@ package processing.app.ui; import java.awt.Color; -import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Point; import java.awt.event.ActionEvent; @@ -111,25 +110,29 @@ public void keyTyped(KeyEvent e) { } }); - tree.setBorder(new EmptyBorder(5, 5, 5, 5)); + final int border = Toolkit.zoom(5); + tree.setBorder(new EmptyBorder(border, border, border, border)); if (Platform.isMacOS()) { tree.setToggleClickCount(2); } else { tree.setToggleClickCount(1); } + // Special cell renderer that takes the UI zoom into account + tree.setCellRenderer(new ZoomTreeCellRenderer(mode)); + // Check whether sketch book is empty or not TreeModel treeModel = tree.getModel(); if (treeModel.getChildCount(treeModel.getRoot()) != 0) { JScrollPane treePane = new JScrollPane(tree); - treePane.setPreferredSize(new Dimension(250, 450)); + treePane.setPreferredSize(Toolkit.zoom(250, 450)); treePane.setBorder(new EmptyBorder(0, 0, 0, 0)); getContentPane().add(treePane); } else { JPanel emptyPanel = new JPanel(); emptyPanel.setBackground(Color.WHITE); - emptyPanel.setPreferredSize(new Dimension(250,450)); + emptyPanel.setPreferredSize(Toolkit.zoom(250,450)); JLabel emptyLabel = new JLabel("Empty Sketchbook"); emptyLabel.setForeground(Color.GRAY); diff --git a/app/src/processing/app/ui/Toolkit.java b/app/src/processing/app/ui/Toolkit.java index e30b9f98a5..866190c6ed 100644 --- a/app/src/processing/app/ui/Toolkit.java +++ b/app/src/processing/app/ui/Toolkit.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -21,6 +21,7 @@ package processing.app.ui; +import java.awt.BasicStroke; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; @@ -52,13 +53,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; import javax.swing.Action; +import javax.swing.Icon; import javax.swing.ImageIcon; +import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; @@ -67,39 +69,29 @@ import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.KeyStroke; +import javax.swing.border.EmptyBorder; import processing.app.Language; import processing.app.Messages; import processing.app.Platform; import processing.app.Preferences; import processing.app.Util; +import processing.core.PApplet; +import processing.data.StringList; /** * Utility functions for base that require a java.awt.Toolkit object. These * are broken out from Base as we start moving toward the possibility of the * code running in headless mode. - * @author fry */ public class Toolkit { - /* - static public final String PROMPT_YES = Language.text("prompt.yes"); - static public final String PROMPT_NO = Language.text("prompt.no"); - static public final String PROMPT_CANCEL = Language.text("prompt.cancel"); - static public final String PROMPT_OK = Language.text("prompt.ok"); - static public final String PROMPT_BROWSE = Language.text("prompt.browse"); - */ - static final java.awt.Toolkit awtToolkit = java.awt.Toolkit.getDefaultToolkit(); /** Command on Mac OS X, Ctrl on Windows and Linux */ static final int SHORTCUT_KEY_MASK = awtToolkit.getMenuShortcutKeyMask(); - - /** Command-W on Mac OS X, Ctrl-W on Windows and Linux */ - public static final KeyStroke WINDOW_CLOSE_KEYSTROKE = - KeyStroke.getKeyStroke('W', SHORTCUT_KEY_MASK); /** Command-Option on Mac OS X, Ctrl-Alt on Windows and Linux */ static final int SHORTCUT_ALT_KEY_MASK = ActionEvent.ALT_MASK | SHORTCUT_KEY_MASK; @@ -107,6 +99,12 @@ public class Toolkit { static final int SHORTCUT_SHIFT_KEY_MASK = ActionEvent.SHIFT_MASK | SHORTCUT_KEY_MASK; + /** Command-W on Mac OS X, Ctrl-W on Windows and Linux */ + static public final KeyStroke WINDOW_CLOSE_KEYSTROKE = + KeyStroke.getKeyStroke('W', SHORTCUT_KEY_MASK); + + static final String BAD_KEYSTROKE = + "'%s' is not understood, please re-read the Java reference for KeyStroke"; /** * Standardized width for buttons. Mac OS X 10.3 wants 70 as its default, @@ -117,7 +115,58 @@ public class Toolkit { static public int getButtonWidth() { // Made into a method so that calling Toolkit methods doesn't require // the languages to be loaded, and with that, Base initialized completely - return Integer.parseInt(Language.text("preferences.button.width")); + return zoom(Integer.parseInt(Language.text("preferences.button.width"))); + } + + + /** + * Return the correct KeyStroke per locale and platform. + * Also checks for any additional overrides in preferences.txt. + * @param base the localization key for the menu item + * (.keystroke and .platform will be added to the end) + * @return KeyStroke for base + .keystroke + .platform + * (or the value from preferences) or null if none found + */ + static public KeyStroke getKeyStrokeExt(String base) { + String key = base + ".keystroke"; + + // see if there's an override in preferences.txt + String sequence = Preferences.get(key); + if (sequence != null) { + KeyStroke ks = KeyStroke.getKeyStroke(sequence); + if (ks != null) { + return ks; // user did good, we're all set + + } else { + System.err.format(BAD_KEYSTROKE, sequence); + } + } + + sequence = Language.text(key + "." + Platform.getName()); + KeyStroke ks = KeyStroke.getKeyStroke(sequence); + if (ks == null) { + // this can only happen if user has screwed up their language files + System.err.format(BAD_KEYSTROKE, sequence); + //return KeyStroke.getKeyStroke(0, 0); // badness + } + return ks; + } + + + /** + * Create a menu item and set its KeyStroke by name (so it can be stored + * in the language settings or the preferences. Syntax is here: + * https://docs.oracle.com/javase/8/docs/api/javax/swing/KeyStroke.html#getKeyStroke-java.lang.String- + * @param sequence the name, as outlined by the KeyStroke API + * @param fallback what to use if getKeyStroke() comes back null + */ + static public JMenuItem newJMenuItemExt(String base) { + JMenuItem menuItem = new JMenuItem(Language.text(base)); + KeyStroke ks = getKeyStrokeExt(base); // will print error if necessary + if (ks != null) { + menuItem.setAccelerator(ks); + } + return menuItem; } @@ -293,7 +342,7 @@ public int compare(Character ch1, Character ch2) { // Holds only [0-9a-z], not uppercase. // Prevents X != x, so "Save" and "Save As" aren't both given 'a'. - final List taken = new ArrayList(menu.length); + final List taken = new ArrayList<>(menu.length); char firstChar; char[] cleanChars; Character[] cleanCharas; @@ -332,7 +381,7 @@ public int compare(Character ch1, Character ch2) { if (cleanString.length() == 0) continue; // First, ban letters by underscores. - final List banned = new ArrayList(); + final List banned = new ArrayList<>(); for (int i = 0; i < cleanString.length(); i++) { if (cleanString.charAt(i) == '_') { if (i > 0) @@ -390,7 +439,7 @@ public int compare(Character ch1, Character ch2) { cleanChars = cleanString.toCharArray(); cleanCharas = new Character[cleanChars.length]; for (int i = 0; i < cleanChars.length; i++) { - cleanCharas[i] = new Character(cleanChars[i]); + cleanCharas[i] = cleanChars[i]; } Arrays.sort(cleanCharas, charComparator); // sorts in increasing order for (char mnem : cleanCharas) { @@ -438,7 +487,7 @@ static public void setMenuMnemonics(JMenuBar menubar) { * As setMenuMnemonics(JMenuItem...). */ static public void setMenuMnemonics(JPopupMenu menu) { - ArrayList items = new ArrayList(); + ArrayList items = new ArrayList<>(); for (Component c : menu.getComponents()) { if (c instanceof JMenuItem) items.add((JMenuItem)c); @@ -501,25 +550,25 @@ static public ImageIcon getIconX(File dir, String base) { * a hidpi display, get the NN*2 version automatically, sized at NN */ static public ImageIcon getIconX(File dir, String base, int size) { - final int scale = Toolkit.highResDisplay() ? 2 : 1; + final int scale = Toolkit.highResImages() ? 2 : 1; String filename = (size == 0) ? (base + "-" + scale + "x.png") : (base + "-" + (size*scale) + ".png"); -// File file = Platform.getContentFile("lib/" + filename); File file = new File(dir, filename); if (!file.exists()) { -// System.err.println("does not exist: " + file); return null; } + ImageIcon outgoing = new ImageIcon(file.getAbsolutePath()) { + @Override public int getIconWidth() { - return super.getIconWidth() / scale; + return Toolkit.zoom(super.getIconWidth()) / scale; } @Override public int getIconHeight() { - return super.getIconHeight() / scale; + return Toolkit.zoom(super.getIconHeight()) / scale; } @Override @@ -549,6 +598,33 @@ static public ImageIcon getLibIconX(String base, int size) { } + /** + * Create a JButton with an icon, and set its disabled and pressed images + * to be the same image, so that 2x versions of the icon work properly. + */ + static public JButton createIconButton(String title, String base) { + ImageIcon icon = Toolkit.getLibIconX(base); + return createIconButton(title, icon); + } + + + /** Same as above, but with no text title (follows JButton constructor) */ + static public JButton createIconButton(String base) { + return createIconButton(null, base); + } + + + static public JButton createIconButton(String title, Icon icon) { + JButton button = new JButton(title, icon); + button.setDisabledIcon(icon); + button.setPressedIcon(icon); + return button; + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + static List iconImages; @@ -568,7 +644,7 @@ static public void setIcon(Frame frame) { static public void setIcon(Window window) { if (!Platform.isMacOS()) { if (iconImages == null) { - iconImages = new ArrayList(); + iconImages = new ArrayList<>(); final int[] sizes = { 16, 32, 48, 64, 128, 256, 512 }; for (int sz : sizes) { iconImages.add(Toolkit.getLibImage("icons/pde-" + sz + ".png")); @@ -613,25 +689,6 @@ static public Shape createRoundRect(float x1, float y1, float x2, float y2, } - // someone needs to be slapped - //static KeyStroke closeWindowKeyStroke; - - /** - * Return true if the key event was a Ctrl-W or an ESC, - * both indicators to close the window. - * Use as part of a keyPressed() event handler for frames. - */ - /* - static public boolean isCloseWindowEvent(KeyEvent e) { - if (closeWindowKeyStroke == null) { - int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - closeWindowKeyStroke = KeyStroke.getKeyStroke('W', modifiers); - } - return ((e.getKeyCode() == KeyEvent.VK_ESCAPE) || - KeyStroke.getKeyStrokeForEvent(e).equals(closeWindowKeyStroke)); - } - */ - /** * Registers key events for a Ctrl-W and ESC with an ActionListener * that will take care of disposing the window. @@ -665,6 +722,17 @@ static public Clipboard getSystemClipboard() { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** + * Create an Image to be used as an offscreen drawing context, + * automatically doubling the size if running on a retina display. + */ + static public Image offscreenGraphics(Component comp, int width, int height) { + int m = Toolkit.isRetina() ? 2 : 1; + //return comp.createImage(m * dpi(width), m * dpi(height)); + return comp.createImage(m * width, m * height); + } + + /** * Handles scaling for high-res displays, also sets text anti-aliasing * options to be far less ugly than the defaults. @@ -674,19 +742,24 @@ static public Clipboard getSystemClipboard() { static public Graphics2D prepareGraphics(Graphics g) { Graphics2D g2 = (Graphics2D) g; - if (Toolkit.highResDisplay()) { + //float z = zoom * (Toolkit.isRetina() ? 2 : 1); + if (Toolkit.isRetina()) { // scale everything 2x, will be scaled down when drawn to the screen g2.scale(2, 2); } + //g2.scale(z, z); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - if (Toolkit.highResDisplay()) { + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + if (Toolkit.isRetina()) { // Looks great on retina, not so great (with our font) on 1x g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); } + zoomStroke(g2); return g2; } @@ -725,14 +798,116 @@ static public Graphics2D prepareGraphics(Graphics g) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - static Boolean highResProp; + static float zoom = 0; + + + /* + // http://stackoverflow.com/a/35029265 + static public void zoomSwingFonts() { + Set keySet = UIManager.getLookAndFeelDefaults().keySet(); + Object[] keys = keySet.toArray(new Object[keySet.size()]); + + for (Object key : keys) { + if (key != null && key.toString().toLowerCase().contains("font")) { + System.out.println(key); + Font font = UIManager.getDefaults().getFont(key); + if (font != null) { + font = font.deriveFont(font.getSize() * zoom); + UIManager.put(key, font); + } + } + } + } + */ + + + static final StringList zoomOptions = + new StringList("100%", "150%", "200%", "300%"); - static public boolean highResDisplay() { - if (highResProp == null) { - highResProp = checkRetina(); + static public int zoom(int pixels) { + if (zoom == 0) { + zoom = parseZoom(); } - return highResProp; + // Deal with 125% scaling badness + // https://github.com/processing/processing/issues/4902 + return (int) Math.ceil(zoom * pixels); + } + + + static public Dimension zoom(int w, int h) { + return new Dimension(zoom(w), zoom(h)); + } + + + static public final int BORDER = + Toolkit.zoom(Platform.isMacOS() ? 20 : 13); + + + static public void setBorder(JComponent comp) { + setBorder(comp, BORDER, BORDER, BORDER, BORDER); + } + + + static public void setBorder(JComponent comp, + int top, int left, int bottom, int right) { + comp.setBorder(new EmptyBorder(Toolkit.zoom(top), Toolkit.zoom(left), + Toolkit.zoom(bottom), Toolkit.zoom(right))); + } + + + static private float parseZoom() { + if (Preferences.getBoolean("editor.zoom.auto")) { + float newZoom = Platform.getSystemDPI() / 96f; + String percentSel = ((int) (newZoom*100)) + "%"; + Preferences.set("editor.zoom", percentSel); + return newZoom; + + } else { + String zoomSel = Preferences.get("editor.zoom"); + if (zoomOptions.hasValue(zoomSel)) { + // shave off the % symbol at the end + zoomSel = zoomSel.substring(0, zoomSel.length() - 1); + return PApplet.parseInt(zoomSel, 100) / 100f; + + } else { + Preferences.set("editor.zoom", "100%"); + return 1; + } + } + } + + + static BasicStroke zoomStroke; + + static private void zoomStroke(Graphics2D g2) { + if (zoom != 1) { + if (zoomStroke == null || zoomStroke.getLineWidth() != zoom) { + zoomStroke = new BasicStroke(zoom); + } + g2.setStroke(zoomStroke); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + // Changed to retinaProp instead of highResProp because only Mac + // "retina" displays use this mechanism for high-resolution scaling. + static Boolean retinaProp; + + + static public boolean highResImages() { + return isRetina() || (zoom > 1); + } + + + static public boolean isRetina() { + if (retinaProp == null) { + retinaProp = checkRetina(); + } + return retinaProp; } @@ -763,57 +938,12 @@ static private boolean checkRetina() { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -// static Font monoFont; -// static Font plainFont; -// static Font boldFont; -// -// -// static public Font getMonoFont(int size) { -// if (monoFont == null) { -// try { -// monoFont = createFont("DroidSansMono.ttf", size); -// } catch (Exception e) { -// monoFont = new Font("Monospaced", Font.PLAIN, size); -// } -// } -// return monoFont; -// } -// -// -// static public Font getPlainFont(int size) { -// if (plainFont == null) { -// try { -// plainFont = createFont("DroidSans.ttf", size); -// } catch (Exception e) { -// plainFont = new Font("SansSerif", Font.PLAIN, size); -// } -// } -// return plainFont; -// } -// -// -// static public Font getBoldFont(int size) { -// if (boldFont == null) { -// try { -// boldFont = createFont("DroidSans-Bold.ttf", size); -// } catch (Exception e) { -// boldFont = new Font("SansSerif", Font.BOLD, size); -// } -// } -// return boldFont; -// } - - - static final char GREEK_SMALL_LETTER_ALPHA = '\u03B1'; // α - static final char GREEK_CAPITAL_LETTER_OMEGA = '\u03A9'; // ω - - // Gets the plain (not bold, not italic) version of each static private List getMonoFontList() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Font[] fonts = ge.getAllFonts(); - ArrayList outgoing = new ArrayList(); + List outgoing = new ArrayList<>(); // Using AffineTransform.getScaleInstance(100, 100) doesn't change sizes FontRenderContext frc = new FontRenderContext(new AffineTransform(), @@ -855,13 +985,12 @@ static private List getMonoFontList() { static public String[] getMonoFontFamilies() { - HashSet families = new HashSet(); + StringList families = new StringList(); for (Font font : getMonoFontList()) { - families.add(font.getFamily()); + families.appendUnique(font.getFamily()); } - String[] names = families.toArray(new String[0]); - Arrays.sort(names); - return names; + families.sort(); + return families.array(); } @@ -873,7 +1002,8 @@ static public String[] getMonoFontFamilies() { static public String getMonoFontName() { if (monoFont == null) { - getMonoFont(12, Font.PLAIN); // load a dummy version + // create a dummy version if the font has never been loaded (rare) + getMonoFont(12, Font.PLAIN); } return monoFont.getName(); } @@ -885,17 +1015,12 @@ static public Font getMonoFont(int size, int style) { monoFont = createFont("SourceCodePro-Regular.ttf", size); monoBoldFont = createFont("SourceCodePro-Bold.ttf", size); - // additional language constraints - if ("el".equals(Language.getLanguage())) { - if (!monoFont.canDisplay(GREEK_SMALL_LETTER_ALPHA) || - !monoFont.canDisplay(GREEK_CAPITAL_LETTER_OMEGA)) { - monoFont = createFont("AnonymousPro-Regular.ttf", size); - monoBoldFont = createFont("AnonymousPro-Bold.ttf", size); - } - } // https://github.com/processing/processing/issues/2886 + // https://github.com/processing/processing/issues/4944 String lang = Language.getLanguage(); - if (Locale.CHINESE.getLanguage().equals(lang) || + if ("el".equals(lang) || + "ar".equals(lang) || + Locale.CHINESE.getLanguage().equals(lang) || Locale.JAPANESE.getLanguage().equals(lang) || Locale.KOREAN.getLanguage().equals(lang)) { sansFont = new Font("Monospaced", Font.PLAIN, size); @@ -923,24 +1048,27 @@ static public Font getMonoFont(int size, int style) { } + static public String getSansFontName() { + if (sansFont == null) { + // create a dummy version if the font has never been loaded (rare) + getSansFont(12, Font.PLAIN); + } + return sansFont.getName(); + } + + static public Font getSansFont(int size, int style) { if (sansFont == null) { try { - sansFont = createFont("SourceSansPro-Regular.ttf", size); - sansBoldFont = createFont("SourceSansPro-Semibold.ttf", size); - - // additional language constraints - if ("el".equals(Language.getLanguage())) { - if (!sansFont.canDisplay(GREEK_SMALL_LETTER_ALPHA) || - !sansFont.canDisplay(GREEK_CAPITAL_LETTER_OMEGA)) { - sansFont = createFont("Carlito-Regular.ttf", size); - sansBoldFont = createFont("Carlito-Bold.ttf", size); - } - } + sansFont = createFont("ProcessingSansPro-Regular.ttf", size); + sansBoldFont = createFont("ProcessingSansPro-Semibold.ttf", size); // https://github.com/processing/processing/issues/2886 + // https://github.com/processing/processing/issues/4944 String lang = Language.getLanguage(); - if (Locale.CHINESE.getLanguage().equals(lang) || + if ("el".equals(lang) || + "ar".equals(lang) || + Locale.CHINESE.getLanguage().equals(lang) || Locale.JAPANESE.getLanguage().equals(lang) || Locale.KOREAN.getLanguage().equals(lang)) { sansFont = new Font("SansSerif", Font.PLAIN, size); @@ -969,23 +1097,23 @@ static public Font getSansFont(int size, int style) { /** - * Get a font from the JRE lib/fonts folder. Our default fonts are also + * Get a font from the lib/fonts folder. Our default fonts are also * installed there so that the monospace (and others) can be used by other * font listing calls (i.e. it appears in the list of monospace fonts in * the Preferences window, and can be used by HTMLEditorKit for WebFrame). */ static private Font createFont(String filename, int size) throws IOException, FontFormatException { - // Can't use Base.getJavaHome(), because if we're not using our local JRE, - // we likely have bigger problems with how things are running. + boolean registerFont = false; + + // try the JRE font directory first File fontFile = new File(System.getProperty("java.home"), "lib/fonts/" + filename); + + // else fall back to our own content dir if (!fontFile.exists()) { - // if we're debugging from Eclipse, grab it from the work folder (user.dir is /app) - fontFile = new File(System.getProperty("user.dir"), "../build/shared/lib/fonts/" + filename); - } - if (!fontFile.exists()) { - // if we're debugging the new Java Mode from Eclipse, paths are different - fontFile = new File(System.getProperty("user.dir"), "../../shared/lib/fonts/" + filename); + fontFile = Platform.getContentFile("lib/fonts/" + filename); + registerFont = true; } + if (!fontFile.exists()) { String msg = "Could not find required fonts. "; // This gets the JAVA_HOME for the *local* copy of the JRE installed with @@ -1000,9 +1128,16 @@ static private Font createFont(String filename, int size) throws IOException, Fo Messages.showError("Font Sadness", msg, null); } + BufferedInputStream input = new BufferedInputStream(new FileInputStream(fontFile)); Font font = Font.createFont(Font.TRUETYPE_FONT, input); input.close(); + + if (registerFont) { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + ge.registerFont(font); + } + return font.deriveFont((float) size); } @@ -1019,20 +1154,6 @@ static public double getAscent(Graphics g) { } -// /** Do not use or rely upon presence of this method: not approved as final API. */ -// static public void debugOpacity(Component comp) { -// //Component parent = comp.getParent(); -// while (comp != null) { -// //EditorConsole.systemOut.println("parent is " + parent + " " + parent.isOpaque()); -// //EditorConsole.systemOut.println(parent.getClass().getName() + " " + (parent.isOpaque() ? "OPAQUE" : "")); -// System.out.println(comp.getClass().getName() + " " + (comp.isOpaque() ? "OPAQUE" : "")); -// comp = comp.getParent(); -// } -// //EditorConsole.systemOut.println(); -// System.out.println(); -// } - - static public int getMenuItemIndex(JMenu menu, JMenuItem item) { int index = 0; for (Component comp : menu.getMenuComponents()) { diff --git a/app/src/processing/app/ui/WebFrame.java b/app/src/processing/app/ui/WebFrame.java index 376007e68e..f1f791d3f2 100644 --- a/app/src/processing/app/ui/WebFrame.java +++ b/app/src/processing/app/ui/WebFrame.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2015 The Processing Foundation + Copyright (c) 2015-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,6 +21,7 @@ package processing.app.ui; +import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -46,10 +47,10 @@ public class WebFrame extends JFrame { boolean ready; - public WebFrame(File file, int width) throws IOException { + public WebFrame(File file, int width, Container panel) throws IOException { // Need to use the URL version so that relative paths work for images // https://github.com/processing/processing/issues/3494 - URL fileUrl = file.toURI().toURL(); //.toExternalForm(); + URL fileUrl = file.toURI().toURL(); requestContentHeight(width, fileUrl); editorPane = new JEditorPane(); @@ -68,7 +69,14 @@ public void propertyChange(PropertyChangeEvent evt) { editorPane.setEditable(false); // set height to something generic editorPane.setPreferredSize(new Dimension(width, width)); - getContentPane().add(editorPane); + + //getContentPane().add(editorPane); + Container pain = getContentPane(); + pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS)); + pain.add(editorPane); + if (panel != null) { + pain.add(panel); + } Toolkit.registerWindowCloseKeys(getRootPane(), new ActionListener() { @Override diff --git a/app/src/processing/app/ui/Welcome.java b/app/src/processing/app/ui/Welcome.java index c0b38d198f..9de89a1db8 100644 --- a/app/src/processing/app/ui/Welcome.java +++ b/app/src/processing/app/ui/Welcome.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2015 The Processing Foundation + Copyright (c) 2015-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,54 +21,114 @@ package processing.app.ui; +import java.awt.Color; import java.awt.EventQueue; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.io.File; import java.io.IOException; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; + import processing.app.Base; import processing.app.Language; import processing.app.Platform; import processing.app.Preferences; import processing.core.PApplet; -import processing.data.StringDict; -public class Welcome extends WebFrame { +public class Welcome { Base base; + WebFrame view; public Welcome(Base base, boolean sketchbook) throws IOException { - super(getIndexFile(sketchbook), 400); this.base = base; - //addStyle("#new_sketchbook { background-color: rgb(0, 255, 0); }"); - setVisible(true); - } + // TODO this should live inside theme or somewhere modifiable + Font dialogFont = Toolkit.getSansFont(14, Font.PLAIN); + + JComponent panel = Box.createHorizontalBox(); + panel.setBackground(new Color(245, 245, 245)); + Toolkit.setBorder(panel, 15, 20, 15, 20); + + //panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + //panel.add(Box.createHorizontalStrut(20)); + JCheckBox checkbox = new JCheckBox("Show this message on startup"); + checkbox.setFont(dialogFont); + // handles the Help menu invocation, and also the pref not existing + checkbox.setSelected("true".equals(Preferences.get("welcome.show"))); + checkbox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + Preferences.setBoolean("welcome.show", true); + } else if (e.getStateChange() == ItemEvent.DESELECTED) { + Preferences.setBoolean("welcome.show", false); + } + } + }); + panel.add(checkbox); - public void handleSubmit(StringDict dict) { - // sketchbook = "create_new" or "use_existing" - // show_each_time = "on" or - //dict.print(); - - String sketchbookAction = dict.get("sketchbook", null); - if ("create_new".equals(sketchbookAction)) { - // open file dialog - // on affirmative selection, update sketchbook folder -// String path = Preferences.getSketchbookPath() + "3"; -// File folder = new File(path); -// folder.mkdirs(); - File folder = new File(Preferences.getSketchbookPath()).getParentFile(); - PApplet.selectFolder(Language.text("preferences.sketchbook_location.popup"), - "sketchbookCallback", folder, - this, this); - } + panel.add(Box.createHorizontalGlue()); - // If un-checked, the key won't be in the dict, so null will be passed - boolean keepShowing = "on".equals(dict.get("show_each_time", null)); - Preferences.setBoolean("welcome.show", keepShowing); - Preferences.save(); + JButton button = new JButton("Get Started"); + button.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + view.handleClose(); + } + }); + panel.add(button); + //panel.add(Box.createHorizontalGlue()); + + view = new WebFrame(getIndexFile(sketchbook), 425, panel) { + /* + @Override + public void handleSubmit(StringDict dict) { + String sketchbookAction = dict.get("sketchbook", null); + if ("create_new".equals(sketchbookAction)) { + File folder = new File(Preferences.getSketchbookPath()).getParentFile(); + PApplet.selectFolder(Language.text("preferences.sketchbook_location.popup"), + "sketchbookCallback", folder, + this, this); + } - handleClose(); +// // If un-checked, the key won't be in the dict, so null will be passed +// boolean keepShowing = "on".equals(dict.get("show_each_time", null)); +// Preferences.setBoolean("welcome.show", keepShowing); +// Preferences.save(); + handleClose(); + } + */ + + @Override + public void handleLink(String link) { + // The link will already have the full URL prefix + if (link.endsWith("#sketchbook")) { + File folder = new File(Preferences.getSketchbookPath()).getParentFile(); + PApplet.selectFolder(Language.text("preferences.sketchbook_location.popup"), + "sketchbookCallback", folder, + this, this); + } else { + super.handleLink(link); + } + } + + @Override + public void handleClose() { + Preferences.setBoolean("welcome.seen", true); + Preferences.save(); + super.handleClose(); + } + }; + view.setVisible(true); } @@ -77,16 +137,17 @@ public void sketchbookCallback(File folder) { if (folder != null) { if (base != null) { base.setSketchbookFolder(folder); - } else { - System.out.println("user selected " + folder); +// } else { +// System.out.println("user selected " + folder); } } } - public void handleClose() { - dispose(); - } +// @Override +// public void handleClose() { +// dispose(); +// } static private File getIndexFile(boolean sketchbook) { @@ -120,11 +181,7 @@ static public void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { - new Welcome(null, true) { - public void handleClose() { - System.exit(0); - } - }; + new Welcome(null, true); } catch (IOException e) { e.printStackTrace(); } diff --git a/app/src/processing/app/ui/Welcome2.java b/app/src/processing/app/ui/Welcome2.java new file mode 100644 index 0000000000..7c635dc115 --- /dev/null +++ b/app/src/processing/app/ui/Welcome2.java @@ -0,0 +1,362 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2017-19 The Processing Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +package processing.app.ui; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextArea; + +import processing.app.Base; +import processing.app.Language; +import processing.app.Platform; +import processing.app.Preferences; +import processing.core.PApplet; + + +/** + * The Welcome class creates a welcome window upon startup + * + * It provides links to changes Processing 3 + * + * If the user is migrating from Processing 2, it provides a + * prompt asking whether to use the same sketchbook folder + * as before, or use a new one. + */ +public class Welcome2 extends JFrame { + Base base; + boolean newSketchbook; + + /** + * @param Base the current Processing Base + * @param oldSketchbook true if the user has a Processing 2 sketchbook + * @throws IOException if resources cannot be found + */ + public Welcome2(Base base, boolean oldSketchbook) throws IOException { + this.base = base; + + // strings used in the GUI + // should be moved to external files to make tranlsation easier + final String welcomeText = "Welcome to Processing 3"; + final String whatsNewText = "Read about what's new in 3.0 \u2192"; + final String compatibleText = "Note that some sketches from Processing 2 " + + "may not be compatible."; + final String whatHasChangedText = "What has changed?"; + final String newSketchbookText = "Since older sketches may " + + "not be compatible, we recommend creating a new sketchbook folder, " + + "so Processing 2 and 3 can happily coexist. This is a one-time " + + "process."; + final String readMoreText = "Read more about it"; + final String createNewSketchbookText = "Create a new sketchbook " + + "folder for use with Processing 3 sketches (recommended!)"; + final String useOldSketchbookText = "Use the existing sketchbook " + + "for both old and new sketches (may cause conflicts with installed " + + "libraries)"; + final String showEachTimeText = "Show this welcome message each time"; + + // color used for boxes with special information + final Color insetColor = new Color(224, 253, 251); + // color used in hyperlinks + final Color linkColor = new Color(44, 123, 181); + + final String whatsNewUrl = "https://github.com/processing/processing/wiki/Changes-in-3.0"; + +// Font processingSemibold; +// Font processingSansPro; + + // load fonts +// try { +// processingSemibold = Font.createFont(Font.TRUETYPE_FONT, +// Base.getLibFile("/fonts/ProcessingSansPro-Semibold.ttf")); +// processingSansPro = Font.createFont(Font.TRUETYPE_FONT, +// Base.getLibFile("/fonts/ProcessingSansPro-Regular.ttf")); +// } catch (FontFormatException e) { +// processingSemibold = UIManager.getDefaults().getFont("Label.font"); +// processingSansPro = UIManager.getDefaults().getFont("Label.font"); +// } +// +// headerFont = processingSemibold.deriveFont(20f); +// bodyFont = processingSansPro.deriveFont(12f); + + Font headerFont = Toolkit.getSansFont(20, Font.BOLD); + Font bodyFont = Toolkit.getSansFont(12, Font.PLAIN); + + //Set welcome window title + setTitle(welcomeText); + + // release frame resources on close + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + //Main content panel + JPanel panel = new JPanel(new GridBagLayout()); + Toolkit.setBorder(panel, 20, 20, 20, 20); + GridBagConstraints c = new GridBagConstraints(); + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + + //int width = sketchbook ? 500 : 400; +// int width = Toolkit.zoom(400); +// int height = Toolkit.zoom(oldSketchbook ? 400 : 250); + int width = 400; + int height = oldSketchbook ? 400 : 250; + + panel.setPreferredSize(Toolkit.zoom(width, height)); + panel.setBackground(Color.white); + + // Processing logo + JLabel logo = new JLabel(Toolkit.getLibIcon("/icons/pde-64.png")); + c.gridx = 0; + c.gridy = 0; + panel.add(logo, c); + + // welcome header + JLabel header = new JLabel(welcomeText); + header.setFont(headerFont); + c.gridx = 1; + c.gridy = 0; + panel.add(header, c); + + // read what's new link + JLabel readNew = new JLabel(whatsNewText); + readNew.setForeground(linkColor); + readNew.setFont(bodyFont); + readNew.setCursor(new Cursor(Cursor.HAND_CURSOR)); + readNew.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + Platform.openURL(whatsNewUrl); + } + }); + c.gridwidth = 2; + c.gridx = 0; + c.gridy = 1; + panel.add(readNew, c); + + // compatible notice inset + JPanel compatible = new JPanel(new GridBagLayout()); + GridBagConstraints compc = new GridBagConstraints(); + compatible.setBackground(insetColor); + Toolkit.setBorder(compatible, 10, 0, 10, 0); + compc.anchor = GridBagConstraints.FIRST_LINE_START; + compc.fill = GridBagConstraints.HORIZONTAL; + + // compatible notice text + JLabel compatibleNotice = new JLabel(compatibleText); + compatibleNotice.setFont(bodyFont); + compc.gridx = 0; + compc.gridy = 0; + compatible.add(compatibleNotice, compc); + + // link to what has changed + JLabel changed = new JLabel(whatHasChangedText); + changed.setFont(bodyFont); + changed.setForeground(linkColor); + changed.setCursor(new Cursor(Cursor.HAND_CURSOR)); + changed.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + Platform.openURL(whatsNewUrl); + } + }); + compc.gridx = 0; + compc.gridy = 1; + compatible.add(changed, compc); + + // add compatible notice inset into main panel + c.gridx = 0; + c.gridy = 2; + panel.add(compatible, c); + + // if the user needs to choose a new sketchbook + if (oldSketchbook) { + // create new sketchbook prompt + JTextArea newSketchbookPrompt = new JTextArea(newSketchbookText); + newSketchbookPrompt.setFont(bodyFont); + newSketchbookPrompt.setEditable(false); + newSketchbookPrompt.setLineWrap(true); + newSketchbookPrompt.setWrapStyleWord(true); + c.gridx = 0; + c.gridy = 3; + panel.add(newSketchbookPrompt, c); + + // read more link + JLabel readMore = new JLabel(readMoreText); + readMore.setFont(bodyFont); + c.gridx = 0; + c.gridy = 4; + panel.add(readMore, c); + + // inset for choose sketchbook + JPanel chooseSketchbook = new JPanel(new GridBagLayout()); + Toolkit.setBorder(chooseSketchbook, 10, 0, 10, 0); + GridBagConstraints choosec = new GridBagConstraints(); + choosec.fill = GridBagConstraints.HORIZONTAL; + choosec.anchor = GridBagConstraints.LINE_START; + chooseSketchbook.setBackground(insetColor); + + // sketchbookGroup contains radio buttons for selection + ButtonGroup sketchbookGroup = new ButtonGroup(); + + // create a new sketchbook for Processing 3 option + JRadioButton createNew = new JRadioButton(createNewSketchbookText); + sketchbookGroup.add(createNew); + createNew.setSelected(true); + createNew.setFont(bodyFont); + createNew.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + //dict.set("sketchbook", "create_new"); + newSketchbook = true; + } + } + }); + // set default + //dict.set("sketchbook", "create_new"); + newSketchbook = true; + choosec.gridx = 0; + choosec.gridy = 0; + chooseSketchbook.add(createNew, choosec); + + // share sketchbook with Processing 2 option + JRadioButton useOld = new JRadioButton("" + useOldSketchbookText); + sketchbookGroup.add(useOld); + useOld.setFont(bodyFont); + useOld.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + //dict.set("sketchbook", "use_existing"); + newSketchbook = false; + } + } + }); + choosec.gridx = 0; + choosec.gridy = 1; + chooseSketchbook.add(useOld, choosec); + + // add choose sketchbook inset into main panel + c.gridx = 0; + c.gridy = 5; + panel.add(chooseSketchbook, c); + } + + // show welcome each time checkbox + // fixes https://github.com/processing/processing/issues/3912 + JCheckBox showEachTime = new JCheckBox("" + showEachTimeText); + // handles the Help menu invocation, and also the pref not existing + showEachTime.setSelected("true".equals(Preferences.get("welcome.show"))); + showEachTime.setFont(bodyFont); + showEachTime.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + Preferences.setBoolean("welcome.show", true); + } else if (e.getStateChange() == ItemEvent.DESELECTED) { + Preferences.setBoolean("welcome.show", false); + } + } + }); + // set default +// dict.set("show_each_time", "on"); + c.gridx = 0; + c.gridy = 6; + panel.add(showEachTime, c); + + // get started (submit) button + JButton getStarted = new JButton("Get Started"); + getStarted.setFont(bodyFont); + getStarted.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleClose(); + } + }); + c.fill = GridBagConstraints.NONE; + c.gridx = 0; + c.gridy = 7; + c.anchor = GridBagConstraints.LAST_LINE_END; + panel.add(getStarted, c); + + add(panel); + pack(); + + Toolkit.registerWindowCloseKeys(getRootPane(), new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleClose(); + } + }); + + // center window on the screen + setLocationRelativeTo(null); + + setVisible(true); + } + + + /** + * Callback for the folder selector, used when user chooses + * a new sketchbook for Processing 3 + * @param folder the path to the new sketcbook + */ + public void sketchbookCallback(File folder) { + if (folder != null) { + if (base != null) { + base.setSketchbookFolder(folder); + } else { + System.out.println("user selected " + folder); + } + } + } + + + /** + * Closes the window + */ + public void handleClose() { + Preferences.save(); // save the "show this" setting + + if (newSketchbook) { + File folder = new File(Preferences.getSketchbookPath()).getParentFile(); + PApplet.selectFolder(Language.text("preferences.sketchbook_location.popup"), + "sketchbookCallback", folder, this, this); + } + dispose(); + } +} diff --git a/app/src/processing/app/ui/ZoomTreeCellRenderer.java b/app/src/processing/app/ui/ZoomTreeCellRenderer.java new file mode 100644 index 0000000000..616b63dbe9 --- /dev/null +++ b/app/src/processing/app/ui/ZoomTreeCellRenderer.java @@ -0,0 +1,63 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2017-19 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app.ui; + +import java.awt.*; +import java.util.Optional; + +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; + +import processing.app.Mode; + + +public class ZoomTreeCellRenderer extends DefaultTreeCellRenderer { + + public ZoomTreeCellRenderer(Mode mode) { + setFont(mode.getFont("tree.font")); + } + + @Override + public Dimension getPreferredSize() { + return Optional.ofNullable(super.getPreferredSize()) + .map(d -> new Dimension(d.width, (int) (d.height * 1.15f))) + .orElse(null); + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean selected, + boolean expanded, + boolean leaf, int row, + boolean hasFocus) { + + // Adjust height for magnified displays. The font is scaled properly, + // but the rows don't automatically use the scaled preferred size. + // https://github.com/processing/processing/issues/4936 + // Using setRowHeight(0) to force using this cell renderer's preferred height + // https://github.com/processing/processing/issues/5246#issuecomment-379503233 + tree.setRowHeight(0); + return super.getTreeCellRendererComponent(tree, value, selected, + expanded, leaf, row, hasFocus); + } +} \ No newline at end of file diff --git a/build/build.xml b/build/build.xml index eaaf4dc94f..5b944c08b8 100644 --- a/build/build.xml +++ b/build/build.xml @@ -1,13 +1,13 @@ - + - + - + @@ -32,47 +32,68 @@ + + + + + + + + - + + + + + + - - - - - - - - - + + + + + + + + + - + - - - + + + + + + @@ -130,7 +151,7 @@ - - @@ -197,7 +218,7 @@ - + @@ -206,9 +227,9 @@ - + - + path="${jre.tgz.path}" /> - - + - - + - - + @@ -269,7 +292,7 @@ - + @@ -291,9 +314,16 @@ + + + + + - @@ -314,11 +344,11 @@ - + - + @@ -334,7 +364,7 @@ - + @@ -347,26 +377,28 @@ + - - + + + - + - - + - + - + @@ -377,17 +409,24 @@ - + - - + + + + + + - @@ -406,13 +445,13 @@ - + - + + - @@ -429,9 +468,9 @@ - + - @@ -442,20 +481,20 @@ - + - + - - - + + @@ -466,18 +505,18 @@ - + ======================================================= Processing for Mac OS X can only be built on Mac OS X. - - Bye. + + Bye. ======================================================= - + - @@ -530,7 +569,7 @@ - @@ -542,7 +581,7 @@ - + Android signing works properly. (Not modifying our appbundler since + most of the time that appbundler is used, keytool isn't needed). + Also, because Ant's copy task does not retain file permissions on + Unix systems, we need to use instead --> - - + - + - + - - - - + + + + + + - + - + - - + + + + + + + - - + + + + + + + Code signing will only work if you have a $99/yr Apple developer ID. @@ -683,7 +744,7 @@ - - - - - - - - @@ -720,43 +770,43 @@ ======================================================= Processing for Mac OS X was built. Grab it from - + macosx/processing-${version}-macosx.zip ======================================================= - + - + - + ======================================================= Processing for Linux can only be built on *nix systems. - - Bye. + + Bye. ======================================================= - + - - + + - - + + - + @@ -765,13 +815,15 @@ - + + - - @@ -783,8 +835,8 @@ - - + + @@ -795,17 +847,31 @@ - + + + + + + - @@ -815,7 +881,7 @@ @@ -823,11 +889,6 @@ - - @@ -857,20 +918,15 @@ --> - - - - - - - - - + + @@ -916,13 +972,13 @@ - - @@ -930,23 +986,29 @@ - + + + - + + + + - + @@ -987,23 +1049,23 @@ - + ======================================================== - Processing for Debian Linux was built. Grab the deb from - + Processing for Debian Linux was built. Grab the deb from + ${linux.deb} ======================================================== - + - + @@ -1011,32 +1073,32 @@ - + ======================================================= Processing for Windows can only be built on windows. - - Bye. + + Bye. ======================================================= - + - + - + - + - + @@ -1049,11 +1111,11 @@ - - + + - + @@ -1077,12 +1139,12 @@ - - - @@ -1094,21 +1156,21 @@ - - @@ -1119,61 +1181,57 @@ --> - - - - - - - - - - + ======================================================= - Processing for Windows was built. Grab the archive from + Processing for Windows was built. Grab the archive from ${windows.dist} ======================================================= - + - + - + - + @@ -1277,8 +1335,8 @@ remove the spaces for depth since it should be double dash, but screws up commen - + @@ -1303,9 +1361,9 @@ remove the spaces for depth since it should be double dash, but screws up commen @@ -1321,7 +1379,7 @@ remove the spaces for depth since it should be double dash, but screws up commen - + @@ -1343,9 +1401,9 @@ remove the spaces for depth since it should be double dash, but screws up commen - + --> @@ -1363,7 +1421,7 @@ remove the spaces for depth since it should be double dash, but screws up commen - + @@ -1403,9 +1461,9 @@ remove the spaces for depth since it should be double dash, but screws up commen @@ -1440,12 +1498,12 @@ remove the spaces for depth since it should be double dash, but screws up commen --> - + - - diff --git a/build/jre/build.xml b/build/jre/build.xml index 4fdbee5f0e..c12776eff2 100644 --- a/build/jre/build.xml +++ b/build/jre/build.xml @@ -3,31 +3,45 @@ + + + + + + + + + + - + target="1.8" + srcdir="src" + destdir="bin" + debug="true" + includeantruntime="true" + nowarn="true"> + + - + - + - - + - + diff --git a/build/jre/src/Downloader.java b/build/jre/src/Downloader.java index 4402321a6f..0eab58acee 100644 --- a/build/jre/src/Downloader.java +++ b/build/jre/src/Downloader.java @@ -8,25 +8,28 @@ /** * Ant Task for downloading the latest JRE or JDK from Oracle. + * This was used to set a cookie properly to retrieve a JRE. + * Nowadays the older versions have been removed from Oracle's site, + * so this is hard wired it to use download.processing.org instead. */ public class Downloader extends Task { + static final boolean ORACLE_SUCKS = true; // that's final + static final String COOKIE = - "gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; " + "oraclelicense=accept-securebackup-cookie"; private int version; // Java 8 - private int update; // Update 31 - private int build; // Build 13 + private int update; // Update 131 + private int build; // Build 11 + // https://gist.github.com/P7h/9741922 + // http://stackoverflow.com/q/10268583 + private String hash; // d54c1d3a095b4ff2b6607d096fa80163 private boolean jdk; // false if JRE -// private String platform; // macosx, windows, linux -// private String bits; // i586 or x64 private String flavor; private String path; // target path -// private File baseDir; -// private boolean includeRecorder; public Downloader() { } @@ -47,19 +50,15 @@ public void setBuild(int build) { } - public void setJDK(boolean jdk) { - this.jdk = jdk; + public void setHash(String hash) { + this.hash = hash; } -// public void setPlatform(String platform) { -// this.platform = platform; -// } - + public void setJDK(boolean jdk) { + this.jdk = jdk; + } -// public void setBits(String bits) { -// this.bits = bits; -// } public void setFlavor(String flavor) { this.flavor = flavor; @@ -72,87 +71,69 @@ public void setPath(String path) { public void execute() throws BuildException { - //if (baseDir == null) { - // throw new BuildException("dir parameter must be set!"); - //} - if (version == 0) { - throw new BuildException("version (i.e. 7 or 8) must be set"); + throw new BuildException("Version (i.e. 7 or 8) must be set"); } if (build == 0) { - throw new BuildException("build number must be set"); + throw new BuildException("Build number must be set"); } if (flavor == null) { - throw new BuildException("you've gotta choose a flavor (macosx-x64.dmg, windows-x64.exe..."); + throw new BuildException("You've gotta choose a flavor (macosx-x64.dmg, windows-x64.exe...)"); + } + + if (update >= 121 && hash == null) { + throw new BuildException("Starting with 8u121, a hash is required, see https://gist.github.com/P7h/9741922"); } -// if (bits == null) { -// throw new BuildException("bits must be set (x64 or i586)"); -// } - //download(path, jdk, platform, bits, version, update, build); try { download(); } catch (IOException e) { throw new BuildException(e); } - - /* - downloadJRE("linux-i586.tar.gz"); - downloadJRE("linux-x64.tar.gz"); - downloadJRE("windows-i586.tar.gz"); - downloadJRE("windows-x64.tar.gz"); - downloadJRE("windows-i586.exe"); - downloadJRE("windows-x64.exe"); - downloadJRE("macosx-x64.dmg"); - downloadJRE("macosx-x64.tar.gz"); - - downloadJDK("linux-i586.tar.gz"); - downloadJDK("linux-x64.tar.gz"); - downloadJDK("windows-i586.exe"); - downloadJDK("windows-x64.exe"); - downloadJDK("macosx-x64.dmg"); - */ } -// static void download(String path, //File folder, String filename, -// boolean jdk, String platform, String bits, -// int version, int update, int build) { void download() throws IOException { - //HttpURLConnection.setFollowRedirects(true); String filename = (jdk ? "jdk" : "jre") + (update == 0 ? String.format("-%d-%s", version, flavor) : String.format("-%du%d-%s", version, update, flavor)); if (path == null) { - path = filename; //System.getProperty("user.dir"); + path = filename; } - //String url = "http://download.oracle.com/otn-pub/java/jdk/" + - // https://edelivery.oracle.com/otn-pub/java/jdk/7u45-b18/jre-7u45-linux-i586.tar.gz - String url = "https://edelivery.oracle.com/otn-pub/java/jdk/" + - //String url = "https://download.oracle.com/otn-pub/java/jdk/" + + String url = "http://download.oracle.com/otn-pub/java/jdk/" + (update == 0 ? String.format("%d-b%02d/", version, build) : - String.format("%du%d-b%02d/", version, update, build)) + filename; -// System.out.println(url); + String.format("%du%d-b%02d/", version, update, build)); + + // URL format changed starting with 8u121 + if (update >= 121) { + url += hash + "/"; + } + + if (ORACLE_SUCKS) { + url = "https://download.processing.org/java/"; + } + + // Finally, add the filename to the end + url += filename; HttpURLConnection conn = - (HttpURLConnection) new URL(url).openConnection(); - //conn.setRequestProperty("Cookie", "name1=value1; name2=value2"); + (HttpURLConnection) new URL(url).openConnection(); conn.setRequestProperty("Cookie", COOKIE); - //conn.setRequestProperty("Cookie", "gpw_e24=http://www.oracle.com/"); //printHeaders(conn); //conn.connect(); - if (conn.getResponseCode() == 302) { + while (conn.getResponseCode() == 302 || conn.getResponseCode() == 301) { Map> headers = conn.getHeaderFields(); List location = headers.get("Location"); if (location.size() == 1) { url = location.get(0); + System.out.println("Redirecting to " + url); } else { throw new BuildException("Got " + location.size() + " locations."); } diff --git a/build/linux/.gitignore b/build/linux/.gitignore index 2cf458e239..fb7b3db738 100644 --- a/build/linux/.gitignore +++ b/build/linux/.gitignore @@ -1 +1,3 @@ -jre-*.tgz \ No newline at end of file +jre-*.tgz +/processing-*-*.deb +/processing-*-*.tgz diff --git a/build/linux/appdata.xml b/build/linux/appdata.xml new file mode 100644 index 0000000000..612d40d0e7 --- /dev/null +++ b/build/linux/appdata.xml @@ -0,0 +1,48 @@ + + + + org.processing.processingide.desktop + CC0-1.0 + GPL-2.0 + Processing Foundation + + Processing IDE + Open-source software prototyping platform + + +

+ Processing is the first easy-to-use software sketching platform + created by C. Reas and B. Fry and supported by the Processing + Foundation. +

+

+ Included is an integrated development environment that can be used + to develop interactive applications using different programming + languages but mainly Java, Android, Python, and Javascript. +

+
+ + + + https://upload.wikimedia.org/wikipedia/commons/6/6b/Processing_screen_shot.png + The Processing IDE showing a simple example program + + + + + + + + + + + + + http://www.processing.org/ + https://processing.org/reference/ + https://github.com/processing/processing/issues?q=is%3Aopen + https://github.com/processing/processing/tree/master/build/shared/lib/languages + https://processing.org/download/support.html + + foundation@processing.org +
diff --git a/build/linux/desktop.template b/build/linux/desktop.template new file mode 100644 index 0000000000..f8cf6d9624 --- /dev/null +++ b/build/linux/desktop.template @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +Name=Processing IDE +GenericName=Processing IDE +Comment=Open-source software prototyping platform +Exec= +Icon= +Terminal=false +Categories=Development;IDE;Programming; +MimeType=text/x-processing; +Keywords=sketching;software;animation;programming;coding; +StartupWMClass=processing-app-Base diff --git a/build/linux/install.sh b/build/linux/install.sh new file mode 100755 index 0000000000..bbe488f890 --- /dev/null +++ b/build/linux/install.sh @@ -0,0 +1,252 @@ +#!/bin/sh + +# This script adds a menu item, icons and mime type for Processing for +# the current user. If possible, it will use the xdg-utils - or fall back +# to just creating and copying a desktop file to the user's directory. +# If called with the "-u" option, it will uninstall. + +# Resource name to use (including vendor prefix) +RESOURCE_NAME=processing-pde + +# Get absolute path from which this script file was executed +# (Could be changed to "pwd -P" to resolve symlinks to their target) +SCRIPT_PATH=$( cd $(dirname $0) ; pwd ) +cd "${SCRIPT_PATH}" + +# Default mode is to install. +UNINSTALL=false + +# If possible, get location of the desktop folder. Default to ~/Desktop +XDG_DESKTOP_DIR="${HOME}/Desktop" +if [ -f "${XDG_CONFIG_HOME:-${HOME}/.config}/user-dirs.dirs" ]; then + . "${XDG_CONFIG_HOME:-${HOME}/.config}/user-dirs.dirs" +fi + +# Install using xdg-utils +xdg_install_f() { + + # Create a temp dir accessible by all users + TMP_DIR=`mktemp --directory` + + # Create *.desktop file using the existing template file + sed -e "s,,${SCRIPT_PATH}/processing,g" \ + -e "s,,${RESOURCE_NAME},g" "${SCRIPT_PATH}/lib/desktop.template" > "${TMP_DIR}/${RESOURCE_NAME}.desktop" + + # Install the icon files using name and resolutions + xdg-icon-resource install --context mimetypes --size 16 "${SCRIPT_PATH}/lib/icons/pde-16.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 32 "${SCRIPT_PATH}/lib/icons/pde-32.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 48 "${SCRIPT_PATH}/lib/icons/pde-48.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 64 "${SCRIPT_PATH}/lib/icons/pde-64.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 128 "${SCRIPT_PATH}/lib/icons/pde-128.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 256 "${SCRIPT_PATH}/lib/icons/pde-256.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 512 "${SCRIPT_PATH}/lib/icons/pde-512.png" $RESOURCE_NAME + xdg-icon-resource install --context mimetypes --size 1024 "${SCRIPT_PATH}/lib/icons/pde-1024.png" $RESOURCE_NAME + + # Install the created *.desktop file + xdg-desktop-menu install "${TMP_DIR}/${RESOURCE_NAME}.desktop" + + # Create icon on the desktop + xdg-desktop-icon install "${TMP_DIR}/${RESOURCE_NAME}.desktop" + + # Install Processing mime type + xdg-mime install "${SCRIPT_PATH}/lib/${RESOURCE_NAME}.xml" + + # Install icons for mime type + xdg-icon-resource install --context mimetypes --size 16 "${SCRIPT_PATH}/lib/icons/pde-16.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 32 "${SCRIPT_PATH}/lib/icons/pde-32.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 48 "${SCRIPT_PATH}/lib/icons/pde-48.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 64 "${SCRIPT_PATH}/lib/icons/pde-64.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 128 "${SCRIPT_PATH}/lib/icons/pde-128.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 256 "${SCRIPT_PATH}/lib/icons/pde-256.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 512 "${SCRIPT_PATH}/lib/icons/pde-512.png" text-x-processing + xdg-icon-resource install --context mimetypes --size 1024 "${SCRIPT_PATH}/lib/icons/pde-1024.png" text-x-processing + + # Make the Processing Development Environment the default app for *.pde files + xdg-mime default ${RESOURCE_NAME}.desktop text/x-processing + + # Clean up + rm "${TMP_DIR}/${RESOURCE_NAME}.desktop" + rmdir "$TMP_DIR" + +} + +# Install by simply copying desktop file (fallback) +simple_install_f() { + + # Create a temp dir accessible by all users + TMP_DIR=`mktemp --directory` + + # Create *.desktop file using the existing template file + sed -e "s,,${SCRIPT_PATH}/processing,g" \ + -e "s,,${SCRIPT_PATH}/lib/icons/pde-128.png,g" "${SCRIPT_PATH}/lib/desktop.template" > "${TMP_DIR}/${RESOURCE_NAME}.desktop" + + mkdir -p "${HOME}/.local/share/applications" + cp "${TMP_DIR}/${RESOURCE_NAME}.desktop" "${HOME}/.local/share/applications/" + + mkdir -p "${HOME}/.local/share/metainfo" + cp "${SCRIPT_PATH}/lib/appdata.xml" "${HOME}/.local/share/metainfo/${RESOURCE_NAME}.appdata.xml" + + # Copy desktop icon if desktop dir exists (was found) + if [ -d "${XDG_DESKTOP_DIR}" ]; then + cp "${TMP_DIR}/${RESOURCE_NAME}.desktop" "${XDG_DESKTOP_DIR}/" + # Altering file permissions to avoid "Untrusted Application Launcher" error on Ubuntu + chmod u+x "${XDG_DESKTOP_DIR}/${RESOURCE_NAME}.desktop" + fi + + # Clean up temp dir + rm "${TMP_DIR}/${RESOURCE_NAME}.desktop" + rmdir "${TMP_DIR}" + +} + +# Uninstall using xdg-utils +xdg_uninstall_f() { + + # Remove *.desktop file + xdg-desktop-menu uninstall ${RESOURCE_NAME}.desktop + + # Remove icon from desktop + xdg-desktop-icon uninstall ${RESOURCE_NAME}.desktop + + # Remove icons + xdg-icon-resource uninstall --size 16 $RESOURCE_NAME + xdg-icon-resource uninstall --size 32 $RESOURCE_NAME + xdg-icon-resource uninstall --size 48 $RESOURCE_NAME + xdg-icon-resource uninstall --size 64 $RESOURCE_NAME + xdg-icon-resource uninstall --size 128 $RESOURCE_NAME + xdg-icon-resource uninstall --size 256 $RESOURCE_NAME + xdg-icon-resource uninstall --size 512 $RESOURCE_NAME + xdg-icon-resource uninstall --size 1024 $RESOURCE_NAME + + # Remove MIME type icons + xdg-icon-resource uninstall --size 16 text-x-processing + xdg-icon-resource uninstall --size 32 text-x-processing + xdg-icon-resource uninstall --size 48 text-x-processing + xdg-icon-resource uninstall --size 64 text-x-processing + xdg-icon-resource uninstall --size 128 text-x-processing + xdg-icon-resource uninstall --size 256 text-x-processing + xdg-icon-resource uninstall --size 512 text-x-processing + xdg-icon-resource uninstall --size 1024 text-x-processing + + # Remove MIME type + xdg-mime uninstall "${SCRIPT_PATH}/lib/${RESOURCE_NAME}.xml" + +} + +# Uninstall by simply removing desktop files (fallback), incl. old one +simple_uninstall_f() { + + # delete legacy cruft .desktop file + if [ -f "${HOME}/.local/share/applications/processing.desktop" ]; then + rm "${HOME}/.local/share/applications/processing.desktop" + fi + + # delete another legacy .desktop file + if [ -f "${HOME}/.local/share/applications/processing-processingide.desktop" ]; then + rm "${HOME}/.local/share/applications/processing-processingide.desktop" + fi + + if [ -f "${HOME}/.local/share/applications/${RESOURCE_NAME}.desktop" ]; then + rm "${HOME}/.local/share/applications/${RESOURCE_NAME}.desktop" + fi + + if [ -f "${HOME}/.local/share/metainfo/${RESOURCE_NAME}.appdata.xml" ]; then + rm "${HOME}/.local/share/metainfo/${RESOURCE_NAME}.appdata.xml" + fi + + if [ -f "${XDG_DESKTOP_DIR}/processing.desktop" ]; then + rm "${XDG_DESKTOP_DIR}/processing.desktop" + fi + + if [ -f "${XDG_DESKTOP_DIR}/${RESOURCE_NAME}.desktop" ]; then + rm "${XDG_DESKTOP_DIR}/${RESOURCE_NAME}.desktop" + fi + +} + +# Update desktop file and mime databases (if possible) +updatedbs_f() { + + if [ -d "${HOME}/.local/share/applications" ]; then + if command -v update-desktop-database > /dev/null; then + update-desktop-database "${HOME}/.local/share/applications" + fi + fi + + if [ -d "${HOME}/.local/share/mime" ]; then + if command -v update-mime-database > /dev/null; then + update-mime-database "${HOME}/.local/share/mime" + fi + fi + +} + +# Check availability of xdg-utils +xdg_exists_f() { + + if ! command -v xdg-icon-resource > /dev/null; then return 1; fi + if ! command -v xdg-desktop-menu > /dev/null; then return 1; fi + if ! command -v xdg-desktop-icon > /dev/null; then return 1; fi + if ! command -v xdg-mime > /dev/null; then return 1; fi + return 0 + +} + +# Shows a description of the available options +display_help_f() { + printf "\nThis script will add a Processing desktop shortcut, menu item,\n" + printf "icons and file associations for the current user.\n" + if ! xdg_exists_f; then + printf "\nxdg-utils are recommended to be installed, so this script can use them.\n" + fi + printf "\nOptional arguments are:\n\n" + printf "\t-u, --uninstall\t\tRemoves shortcut, menu item and icons.\n\n" + printf "\t-h, --help\t\tShows this help again.\n\n" +} + +# Check for provided arguments +while [ $# -gt 0 ] ; do + ARG="${1}" + case $ARG in + -u|--uninstall) + UNINSTALL=true + shift + ;; + -h|--help) + display_help_f + exit 0 + ;; + *) + printf "\nInvalid option -- '${ARG}'\n" + display_help_f + exit 1 + ;; + esac +done + +# If possible, use xdg-utils, if not, use a more basic approach +if xdg_exists_f; then + if [ ${UNINSTALL} = true ]; then + printf "Removing desktop shortcut and menu item for Processing..." + xdg_uninstall_f + simple_uninstall_f + else + printf "Adding desktop shortcut, menu item and file associations for Processing..." + xdg_uninstall_f + simple_uninstall_f + xdg_install_f + fi +else + if [ ${UNINSTALL} = true ]; then + printf "Removing desktop shortcut and menu item for Processing..." + simple_uninstall_f + else + printf "Adding desktop shortcut and menu item for Processing..." + simple_uninstall_f + simple_install_f + fi +fi +updatedbs_f +printf " done!\n" + +exit 0 diff --git a/build/linux/processing-pde.xml b/build/linux/processing-pde.xml new file mode 100644 index 0000000000..3b8a6837be --- /dev/null +++ b/build/linux/processing-pde.xml @@ -0,0 +1,42 @@ + + + + Processing source code + شفرة مصدر Processing + Kryničny kod Processing + Изходен код на Processing + codi font en Processing + Processingkildekode + Processing-Quelltext + πηγαίος κώδικας Processing + Processing source code + Processing-fontkodo + código fuente en Processing + Processing iturburu-kodea + Processing-lähdekoodi + code source Processing + cód foinseach Processing + Processing-forráskód + Kode program Processing + Codice sorgente Processing + Processing ソースコード + Processing pradinis kodas + Processing pirmkods + Kod sumber Processing + Processing-kildekode + Processing-broncode + Processing-kjeldekode + Kod źródłowy Processing + código fonte Processing + Código fonte Processing + исходный код Processing + Kod burues Processing + Processing-källkod + Вихідний код на мові Processing + Mã nguồn Processing + Processing 源代码 + Processing 源代碼 + + + + diff --git a/build/linux/uninstall.sh b/build/linux/uninstall.sh new file mode 100644 index 0000000000..d92eeada48 --- /dev/null +++ b/build/linux/uninstall.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +SCRIPT_PATH=$( cd $(dirname $0) ; pwd ) +cd "$SCRIPT_PATH" + +./install.sh -u diff --git a/build/macosx/appbundler.jar b/build/macosx/appbundler.jar index 0102f306a9..42cc8f18cd 100644 Binary files a/build/macosx/appbundler.jar and b/build/macosx/appbundler.jar differ diff --git a/build/macosx/appbundler/build.xml b/build/macosx/appbundler/build.xml index 9b48b2bb5c..4d02204175 100644 --- a/build/macosx/appbundler/build.xml +++ b/build/macosx/appbundler/build.xml @@ -33,8 +33,8 @@ questions. version=1.0ea --> - - + + @@ -73,7 +73,8 @@ questions.
- + + @@ -87,10 +88,10 @@ questions. - - + + diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 8009c78b25..df4c26bc73 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -458,6 +458,7 @@ private void copyResources(File resourcesDirectory) throws IOException { } finally { outputStream.close(); } + file.setLastModified(zipEntry.getTime()); } zipEntry = zipInputStream.getNextEntry(); } @@ -729,7 +730,9 @@ private static void delete(File file) throws IOException { private static void copy(URL location, File file) throws IOException { try (InputStream in = location.openStream()) { - Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.copy(in, file.toPath(), + // can't do attributes when coming from URL + StandardCopyOption.REPLACE_EXISTING); } } @@ -740,13 +743,15 @@ private static void copy(File source, File destination) throws IOException { destination.getParentFile().mkdirs(); - Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); + Files.copy(sourcePath, destinationPath, + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.COPY_ATTRIBUTES, + LinkOption.NOFOLLOW_LINKS); if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) { String[] files = source.list(); - for (int i = 0; i < files.length; i++) { - String file = files[i]; + for (String file : files) { copy(new File(source, file), new File(destination, file)); } } diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java index 94fdde05ec..7e26d4391c 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * + * */ package com.oracle.appbundler; @@ -32,90 +32,94 @@ * Represent a CFBundleDocument. */ public class BundleDocument { - private String name = "editor"; - private String role = ""; - private File icon = null; - private String[] extensions; - private boolean isPackage = false; - - static private String capitalizeFirst(String string) { - char[] stringArray = string.toCharArray(); - stringArray[0] = Character.toUpperCase(stringArray[0]); - return new String(stringArray); - } - - public void setExtensions(String extensionsList) { - if(extensionsList == null) { - throw new BuildException("Extensions can't be null"); - } - - extensions = extensionsList.split(","); - for (String extension : extensions) { - extension.trim().toLowerCase(); - } - } - - public void setIcon(File icon) { - this.icon = icon; - } - - public void setName(String name) { - this.name = name; - } + private String name = "editor"; + private String role = ""; + private File icon = null; + private String[] extensions; + private boolean isPackage = false; - public void setRole(String role) { - this.role = capitalizeFirst(role); - } - - public void setIsPackage(String isPackageString) { - if(isPackageString.trim().equalsIgnoreCase("true")) { - this.isPackage = true; - } else { - this.isPackage = false; - } - } - -// public String getIcon() { -// return icon; -// } - - public String getIconName() { - return icon.getName(); - } - - - public File getIconFile() { - return icon; - } - - public String getName() { - return name; - } - public String getRole() { - return role; - } - - public String[] getExtensions() { - return extensions; - } - - public boolean hasIcon() { - return icon != null; + static private String capitalizeFirst(String string) { + char[] stringArray = string.toCharArray(); + stringArray[0] = Character.toUpperCase(stringArray[0]); + return new String(stringArray); + } + + + public void setExtensions(String extensionsList) { + if (extensionsList == null) { + throw new BuildException("Extensions can't be null"); } - - public boolean isPackage() { - return isPackage; + + extensions = extensionsList.split(","); + for (int i = 0; i < extensions.length; i++) { + extensions[i] = extensions[i].trim().toLowerCase(); } + } + + + public void setIcon(File icon) { + this.icon = icon; + } + + + public void setName(String name) { + this.name = name; + } + + + public void setRole(String role) { + this.role = capitalizeFirst(role); + } + + + public void setIsPackage(String isPackageString) { + this.isPackage = isPackageString.trim().equalsIgnoreCase("true"); + } + + + public String getIconName() { + return icon.getName(); + } + + + public File getIconFile() { + return icon; + } + + + public String getName() { + return name; + } + + + public String getRole() { + return role; + } + + + public String[] getExtensions() { + return extensions; + } + + + public boolean hasIcon() { + return icon != null; + } + + + public boolean isPackage() { + return isPackage; + } + - @Override - public String toString() { - StringBuilder s = new StringBuilder(getName()); - s.append(" ").append(getRole()).append(" ").append(getIconName()). append(" "); - for(String extension : extensions) { - s.append(extension).append(" "); - } - - return s.toString(); + @Override + public String toString() { + StringBuilder s = new StringBuilder(getName()); + s.append(" ").append(getRole()).append(" ").append(getIconName()).append(" "); + for (String extension : extensions) { + s.append(extension).append(" "); } + return s.toString(); + } } diff --git a/build/macosx/language_gen.py b/build/macosx/language_gen.py index 463d28fd63..5b216ee4f8 100755 --- a/build/macosx/language_gen.py +++ b/build/macosx/language_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import os, re diff --git a/build/shared/lib/about-1x.png b/build/shared/lib/about-1x.png index 46d4ee681c..4224ee4e66 100644 Binary files a/build/shared/lib/about-1x.png and b/build/shared/lib/about-1x.png differ diff --git a/build/shared/lib/about-2x.png b/build/shared/lib/about-2x.png index ca21f08148..4da84d41c9 100644 Binary files a/build/shared/lib/about-2x.png and b/build/shared/lib/about-2x.png differ diff --git a/build/shared/lib/defaults.txt b/build/shared/lib/defaults.txt index f1663073b1..97381d81c9 100644 --- a/build/shared/lib/defaults.txt +++ b/build/shared/lib/defaults.txt @@ -74,8 +74,6 @@ recent.count = 10 # Default to the native (AWT) file selector where possible chooser.files.native = true -# native Linux file chooser is atrocious, use Swing instead -chooser.files.native.linux = false # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -105,6 +103,11 @@ editor.window.height.min.windows = 530 # tested with Raspberry Pi display editor.window.height.min.linux = 480 +# scaling for the interface (to handle Windows and Linux HiDPI displays) +editor.zoom = 100% +# automatically set based on system dpi (only helps on Windows) +editor.zoom.auto = true + # font size for editor #editor.font = Monospaced,plain,12 # Monaco is nicer on Mac OS X, so use that explicitly @@ -164,6 +167,9 @@ editor.watcher.debug = false # The window of time (in milliseconds) in which a change won't be counted editor.watcher.window = 1500 +# Format and search engine to use for online queries +search.format = https://google.com/search?q=%s + # font choice and size for the console #console.font = Monospaced,plain,11 #console.font.macosx = Monaco,plain,10 @@ -179,7 +185,8 @@ console.auto_clear = true # set the maximum number of lines remembered by the console # the default is 500, lengthen at your own peril -console.length = 500 +console.scrollback.lines = 500 +console.scrollback.chars = 40000 # Any additional Java options when running. # If you change this and can't run things, it's your own durn fault. @@ -300,9 +307,6 @@ preproc.substitute_floats = true #preproc.substitute_image = false #preproc.substitute_font = false -# auto-convert non-ascii chars to unicode escape sequences -preproc.substitute_unicode = true - # PdePreproc.java # writes out the parse tree as parseTree.xml, which can be usefully # viewed in (at least) Mozilla or IE. useful when debugging the preprocessor. @@ -347,6 +351,8 @@ proxy.socks.port= # Example of usage (replace 'http' with 'https' or 'socks' as needed) #proxy.http.host=proxy.example.com #proxy.http.port=8080 +# Whether to use the system proxy by default +proxy.system=true # PDE X pdex.autoSave.autoSaveByDefault=true diff --git a/build/shared/lib/fonts/AnonymousPro-Bold.ttf b/build/shared/lib/fonts/AnonymousPro-Bold.ttf deleted file mode 100644 index 985bd4002d..0000000000 Binary files a/build/shared/lib/fonts/AnonymousPro-Bold.ttf and /dev/null differ diff --git a/build/shared/lib/fonts/AnonymousPro-LICENSE.txt b/build/shared/lib/fonts/AnonymousPro-LICENSE.txt deleted file mode 100644 index 5ca1911b95..0000000000 --- a/build/shared/lib/fonts/AnonymousPro-LICENSE.txt +++ /dev/null @@ -1,94 +0,0 @@ -Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com), -with Reserved Font Name Anonymous Pro. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/build/shared/lib/fonts/AnonymousPro-Regular.ttf b/build/shared/lib/fonts/AnonymousPro-Regular.ttf deleted file mode 100644 index 06aafc0673..0000000000 Binary files a/build/shared/lib/fonts/AnonymousPro-Regular.ttf and /dev/null differ diff --git a/build/shared/lib/fonts/Carlito-Bold.ttf b/build/shared/lib/fonts/Carlito-Bold.ttf deleted file mode 100644 index b29a590511..0000000000 Binary files a/build/shared/lib/fonts/Carlito-Bold.ttf and /dev/null differ diff --git a/build/shared/lib/fonts/Carlito-LICENSE.txt b/build/shared/lib/fonts/Carlito-LICENSE.txt deleted file mode 100644 index e999b31837..0000000000 --- a/build/shared/lib/fonts/Carlito-LICENSE.txt +++ /dev/null @@ -1,95 +0,0 @@ -Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito". - -This Font Software is licensed under the SIL Open Font License, -Version 1.1 as shown below. - -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 - -PREAMBLE The goals of the Open Font License (OFL) are to stimulate -worldwide development of collaborative font projects, to support the font -creation efforts of academic and linguistic communities, and to provide -a free and open framework in which fonts may be shared and improved in -partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. -The fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply to -any document created using the fonts or their derivatives. - - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. -This may include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components -as distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting ? in part or in whole ? -any of the components of the Original Version, by changing formats or -by porting the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical writer -or other person who contributed to the Font Software. - - -PERMISSION & CONDITIONS - -Permission is hereby granted, free of charge, to any person obtaining a -copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components,in - Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, - redistributed and/or sold with any software, provided that each copy - contains the above copyright notice and this license. These can be - included either as stand-alone text files, human-readable headers or - in the appropriate machine-readable metadata fields within text or - binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font - Name(s) unless explicit written permission is granted by the - corresponding Copyright Holder. This restriction only applies to the - primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font - Software shall not be used to promote, endorse or advertise any - Modified Version, except to acknowledge the contribution(s) of the - Copyright Holder(s) and the Author(s) or with their explicit written - permission. - -5) The Font Software, modified or unmodified, in part or in whole, must - be distributed entirely under this license, and must not be distributed - under any other license. The requirement for fonts to remain under - this license does not apply to any document created using the Font - Software. - - - -TERMINATION -This license becomes null and void if any of the above conditions are not met. - - - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER -DEALINGS IN THE FONT SOFTWARE. - diff --git a/build/shared/lib/fonts/Carlito-Regular.ttf b/build/shared/lib/fonts/Carlito-Regular.ttf deleted file mode 100644 index 6b7e0e38e9..0000000000 Binary files a/build/shared/lib/fonts/Carlito-Regular.ttf and /dev/null differ diff --git a/build/shared/lib/fonts/SourceSansPro-LICENSE.txt b/build/shared/lib/fonts/ProcessingSansPro-LICENSE.txt similarity index 96% rename from build/shared/lib/fonts/SourceSansPro-LICENSE.txt rename to build/shared/lib/fonts/ProcessingSansPro-LICENSE.txt index df187637e1..caaf349732 100644 --- a/build/shared/lib/fonts/SourceSansPro-LICENSE.txt +++ b/build/shared/lib/fonts/ProcessingSansPro-LICENSE.txt @@ -1,3 +1,8 @@ +"Processing Sans" fonts are just "Source Sans", but renamed to +prevent conflicts on Windows with other versions of Source Sans. +https://github.com/processing/processing/issues/4747 + + Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. This Font Software is licensed under the SIL Open Font License, Version 1.1. diff --git a/build/shared/lib/fonts/ProcessingSansPro-Regular.ttf b/build/shared/lib/fonts/ProcessingSansPro-Regular.ttf new file mode 100644 index 0000000000..c7862f39af Binary files /dev/null and b/build/shared/lib/fonts/ProcessingSansPro-Regular.ttf differ diff --git a/build/shared/lib/fonts/ProcessingSansPro-Semibold.ttf b/build/shared/lib/fonts/ProcessingSansPro-Semibold.ttf new file mode 100644 index 0000000000..10465b81a5 Binary files /dev/null and b/build/shared/lib/fonts/ProcessingSansPro-Semibold.ttf differ diff --git a/build/shared/lib/fonts/SourceSansPro-Regular.ttf b/build/shared/lib/fonts/SourceSansPro-Regular.ttf deleted file mode 100644 index 44486cdc67..0000000000 Binary files a/build/shared/lib/fonts/SourceSansPro-Regular.ttf and /dev/null differ diff --git a/build/shared/lib/fonts/SourceSansPro-Semibold.ttf b/build/shared/lib/fonts/SourceSansPro-Semibold.ttf deleted file mode 100644 index 86b00c067e..0000000000 Binary files a/build/shared/lib/fonts/SourceSansPro-Semibold.ttf and /dev/null differ diff --git a/build/shared/lib/languages/PDE.properties b/build/shared/lib/languages/PDE.properties index f1c3eedb14..0f312730fd 100644 --- a/build/shared/lib/languages/PDE.properties +++ b/build/shared/lib/languages/PDE.properties @@ -31,6 +31,9 @@ menu.file.quit = Quit menu.edit = Edit menu.edit.undo = Undo menu.edit.redo = Redo +menu.edit.redo.keystroke.macosx = shift meta pressed Z +menu.edit.redo.keystroke.windows = ctrl pressed Y +menu.edit.redo.keystroke.linux = shift ctrl pressed Z menu.edit.action.addition = addition menu.edit.action.deletion = deletion menu.edit.cut = Cut @@ -40,8 +43,17 @@ menu.edit.paste = Paste menu.edit.select_all = Select All menu.edit.auto_format = Auto Format menu.edit.comment_uncomment = Comment/Uncomment -menu.edit.increase_indent = Increase Indent -menu.edit.decrease_indent = Decrease Indent +menu.edit.comment_uncomment.keystroke.macosx = meta pressed SLASH +menu.edit.comment_uncomment.keystroke.windows = ctrl pressed SLASH +menu.edit.comment_uncomment.keystroke.linux = ctrl pressed SLASH +menu.edit.increase_indent = → Increase Indent +menu.edit.increase_indent.keystroke.macosx = meta pressed CLOSE_BRACKET +menu.edit.increase_indent.keystroke.windows = ctrl pressed CLOSE_BRACKET +menu.edit.increase_indent.keystroke.linux = ctrl pressed CLOSE_BRACKET +menu.edit.decrease_indent = ← Decrease Indent +menu.edit.decrease_indent.keystroke.macosx = meta pressed OPEN_BRACKET +menu.edit.decrease_indent.keystroke.windows = ctrl pressed OPEN_BRACKET +menu.edit.decrease_indent.keystroke.linux = ctrl pressed OPEN_BRACKET menu.edit.find = Find... menu.edit.find_next = Find Next menu.edit.find_previous = Find Previous @@ -77,8 +89,17 @@ menu.debug.toggle_breakpoint = Toggle Breakpoint # --- # used for both menus and toolbars menu.debug.step = Step +menu.debug.step.keystroke.macosx = meta pressed J +menu.debug.step.keystroke.windows = ctrl pressed J +menu.debug.step.keystroke.linux = ctrl pressed J menu.debug.step_into = Step Into +menu.debug.step_into.keystroke.macosx = shift meta pressed J +menu.debug.step_into.keystroke.windows = shift ctrl pressed J +menu.debug.step_into.keystroke.linux = shift ctrl pressed J menu.debug.step_out = Step Out +menu.debug.step_out.keystroke.macosx = meta alt pressed J +menu.debug.step_out.keystroke.windows = ctrl alt pressed J +menu.debug.step_out.keystroke.linux = ctrl alt pressed J menu.debug.continue = Continue # --- #menu.debug.print_stack_trace = Print Stack Trace @@ -116,15 +137,15 @@ menu.help.tools_reference = Tools Reference menu.help.empty = (empty) menu.help.online = Online menu.help.getting_started = Getting Started -menu.help.getting_started.url = http://processing.org/learning/gettingstarted/ +menu.help.getting_started.url = https://processing.org/tutorials/gettingstarted/ menu.help.troubleshooting = Troubleshooting -menu.help.troubleshooting.url = http://wiki.processing.org/w/Troubleshooting +menu.help.troubleshooting.url = https://github.com/processing/processing/wiki/troubleshooting menu.help.faq = Frequently Asked Questions -menu.help.faq.url = http://wiki.processing.org/w/FAQ +menu.help.faq.url = https://github.com/processing/processing/wiki/FAQ menu.help.foundation = The Processing Foundation -menu.help.foundation.url = http://processing.org/foundation/ +menu.help.foundation.url = https://processing.foundation/ menu.help.visit = Visit Processing.org -menu.help.visit.url = http://processing.org/ +menu.help.visit.url = https://processing.org/ # --------------------------------------- @@ -166,6 +187,8 @@ preferences.editor_and_console_font = Editor and Console font preferences.editor_and_console_font.tip = Select the font used in the Editor and the Console.
Only monospaced (fixed-width) fonts may be used,
though the list may be imperfect. preferences.editor_font_size = Editor font size preferences.console_font_size = Console font size +preferences.zoom = Interface scale +preferences.zoom.auto = Automatic preferences.background_color = Background color when Presenting preferences.background_color.tip = Select the background color used when using Present.
Present is used to present a sketch in full-screen,
accessible from the Sketch menu. preferences.use_smooth_text = Use smooth text in editor window @@ -307,11 +330,18 @@ editor.header.new_tab = New Tab editor.header.rename = Rename editor.header.delete = Delete editor.header.previous_tab = Previous Tab +editor.header.previous_tab.keystroke.macosx = meta alt pressed LEFT +editor.header.previous_tab.keystroke.windows = ctrl pressed PAGE_UP +editor.header.previous_tab.keystroke.linux = ctrl pressed PAGE_UP editor.header.next_tab = Next Tab +editor.header.next_tab.keystroke.macosx = meta alt pressed RIGHT +editor.header.next_tab.keystroke.windows = ctrl pressed PAGE_DOWN +editor.header.next_tab.keystroke.linux = ctrl pressed PAGE_DOWN editor.header.delete.warning.title = Yeah, no. editor.header.delete.warning.text = You cannot delete the main tab of the only open sketch. # PopUp menu +editor.popup.jump_to_declaration = Jump to Declaration editor.popup.show_usage = Show Usage... editor.popup.rename = Rename... @@ -357,6 +387,7 @@ editor.status.missing.right_paren = Missing right parenthesis ")" editor.status.missing.left_curly_bracket = Missing left curly bracket "{" editor.status.missing.right_curly_bracket = Missing right curly bracket "}" editor.status.missing.add = Consider adding "%s" +editor.status.bad_curly_quote = Curly quotes like %s don't work. Use straight quotes. Ctrl-T to autocorrect. editor.status.reserved_words = "color" and "int" are reserved words & cannot be used as variable names editor.status.undefined_method = The function "%s(%s)" does not exist editor.status.undefined_constructor = The constructor "%s(%s)" does not exist @@ -366,11 +397,12 @@ editor.status.undef_global_var = The global variable "%s" does not exist editor.status.undef_class = The class "%s" does not exist editor.status.undef_var = The variable "%s" does not exist editor.status.undef_name = The name "%s" cannot be recognized +editor.status.unterm_string_curly = String literal is not closed by a straight double quote. Curly quotes like %s won't help. editor.status.type_mismatch = Type mismatch, "%s" does not match with "%s" editor.status.unused_variable = The value of the local variable "%s" is not used editor.status.uninitialized_variable = The local variable "%s" may not have been initialized editor.status.no_effect_assignment = The assignment to variable "%s" has no effect -editor.status.hiding_enclosing_type = The class "%s" cannot have the same name as your sketch or its' enclosing class +editor.status.hiding_enclosing_type = The class "%s" cannot have the same name as your sketch or its enclosing class # Footer buttons editor.footer.errors = Errors @@ -445,6 +477,18 @@ ensure_exist.messages.unrecoverable.description = Could not properly re-save the # Check name check_name.messages.is_name_modified = The sketch name had to be modified. Sketch names can only consist\nof ASCII characters and numbers (but cannot start with a number).\nThey should also be less than 64 characters long. +# External changes detector +change_detect.reload.title=Tab modified externally +change_detect.reload.question="%s" was modified by another program. +change_detect.reload.comment=Would you like to keep this version or load the new changes?\nEither way, the version you discard will be saved to your sketch folder. +change_detect.button.keep=Keep +change_detect.button.load_new=Load changes +change_detect.delete.title=Tab deleted externally +change_detect.delete.question="%s" has disappeared from the sketch folder. +change_detect.delete.comment=Would you like to re-save it or remove it from your sketch? +change_detect.button.discard=Remove permanently +change_detect.button.resave=Re-save + # --------------------------------------- # Contributions diff --git a/build/shared/lib/languages/PDE_ar.properties b/build/shared/lib/languages/PDE_ar.properties new file mode 100644 index 0000000000..008f027517 --- /dev/null +++ b/build/shared/lib/languages/PDE_ar.properties @@ -0,0 +1,590 @@ + + +# --------------------------------------- +# Language: Arabic (ar) | العربية +# --------------------------------------- + + +# --------------------------------------- +# Menu + +# | File | Edit | Sketch | Debug | Tools | Help | +# | File | +menu.file = ملف +menu.file.new = جديد +menu.file.open = افتح... +menu.file.recent = فتح من الملفات الأخيرة +menu.file.sketchbook = دفتر المخطوطات... +menu.file.sketchbook.empty = دفتر مخطوطات فارغ +menu.file.examples = أمثلة... +menu.file.close = إغلاق +menu.file.save = حفظ +menu.file.save_as = حفظ ك... +menu.file.export_application = تصدير التطبيق... +menu.file.page_setup = إعدادات الصفحة +menu.file.print = طباعة +menu.file.preferences = إعدادات... +menu.file.quit = خروج + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Edit | +menu.edit = تعديل +menu.edit.undo = تراجع +menu.edit.redo = إعادة +menu.edit.action.addition = إضافة +menu.edit.action.deletion = حذف +menu.edit.cut = قص +menu.edit.copy = نسخ +menu.edit.copy_as_html = نسخ ك HTML +menu.edit.paste = لصق +menu.edit.select_all = تحديد الكل +menu.edit.auto_format = فرمتة تلقائية +menu.edit.comment_uncomment = تعليق/إلغاء التعليق +menu.edit.increase_indent = زيادة المسافة البادئة → +menu.edit.decrease_indent = انقاص المسافة البادئة ← +menu.edit.find = بحث... +menu.edit.find_next = النتيجة التالية +menu.edit.find_previous = النتيجة السابقة +menu.edit.use_selection_for_find = ابحث عن المحدد + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Sketch | +menu.sketch.run = تشغيل +menu.sketch.present = تقديم +menu.sketch.tweak = تعديل +menu.sketch.stop = إيقاف +# --- +menu.library = استيراد مكتبة... +menu.library.add_library = إضافة مكتبة... +menu.library.contributed = مساهمات +menu.library.no_core_libraries = لا يوجد مكتبات أساسية لهذا الوضع +# --- +menu.sketch = المخطوط +menu.sketch.show_sketch_folder = إظهار ملف المخطوطات +menu.sketch.add_file = إضافة ملف.. + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Debug | +menu.debug = تنقيح +menu.debug.enable = تفعيل أداة التنقيح +menu.debug.disable = تعطيل أداة التنقيح +#menu.debug.show_debug_toolbar = إظهار شريط أدواة التنقيح +#menu.debug.debug = تنقيح +#menu.debug.stop = توقف +# --- +menu.debug.toggle_breakpoint = تبديل حالة نقطة الوقوف +#menu.debug.list_breakpoints = قائمة نقاط الوقوف +# --- +# used for both menus and toolbars +menu.debug.step = تقدم +menu.debug.step_into = تقدم إلى الأمام +menu.debug.step_out = تقدم إلى الخلف +menu.debug.continue = استمر +# --- +#menu.debug.print_stack_trace = طباعة أثر المكدس +#menu.debug.print_locals = طباعة المتغيرات المحلية +#menu.debug.print_fields = طباعة الحقول +#menu.debug.print_source_location = طباعة مكان المصدر +#menu.debug.print_threads = طباعة شرط التعليمات +# --- +#menu.debug.variable_inspector = مظهر المتغيرات +menu.debug.show_variables = إظهار المتغيرات +menu.debug.hide_variables = إخفاء المتغيرات +#menu.debug.show_sketch_outline = إظهار موجز المخطوط +#menu.debug.show_tabs_list = إظهار قائمة علامات التبويب + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Tools | +menu.tools = أدوات +menu.tools.color_selector = أداة اختيار الألوان... +menu.tools.create_font = أداة صناعة الخطوط +menu.tools.archive_sketch = أرشفة المخطوط +menu.tools.fix_the_serial_lbrary = إصلاح مكتبة الاتصالات التسلسلية +menu.tools.install_processing_java = تثبيت"processing-java" +menu.tools.add_tool = أضف أداة + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Help | +menu.help = مساعدة +menu.help.welcome = مرحباً بكم في Processing 3 +menu.help.about = عن Processing +menu.help.environment = البيئة +menu.help.reference = مراجع +menu.help.find_in_reference = إبحث في مرجع +menu.help.libraries_reference = مرجع المكتبات +menu.help.tools_reference = مرجع الأدوات +menu.help.empty = (فارغ) +menu.help.online = متصل +menu.help.getting_started = البدء +menu.help.getting_started.url = http://processing.org/learning/gettingstarted/ +menu.help.troubleshooting = اكتشاف الأخطاء وإصلاحها +menu.help.troubleshooting.url = http://wiki.processing.org/w/Troubleshooting +menu.help.faq = الأسئلة الشائعة +menu.help.faq.url = http://wiki.processing.org/w/FAQ +menu.help.foundation = Processing مؤسسة +menu.help.foundation.url = http://processing.org/foundation/ +menu.help.visit = Processing.org زيارة +menu.help.visit.url = http://processing.org/ + + +# --------------------------------------- +# Basics + +# Buttons +prompt.yes = نعم +prompt.no = لا +prompt.cancel = إلغاء +prompt.ok = موافق +prompt.browse = تصفح +prompt.export = تصدير + + +# --------------------------------------- +# Frames + +# Open (Frame) +open = فتح مخطوط بروسسنج... + +# Save (Frame) +save = حفظ ملف المخطوطات ك... +save.title = هل تريد حفظ التغييرات على %s
قبل الإغلاق؟ +save.hint = في حال عدم الحفظ, ستفقد كل التغييرات على الملف +save.btn.save = حفظ +save.btn.dont_save = عدم الحفظ + +# Close (Frame) also used to prompt on non-OS X machines +close.unsaved_changes = ؟%s هل تريد حفظ التغييرات على + +# Preferences (Frame) +preferences = الإعدادات +preferences.button.width = 80 +preferences.requires_restart = تلزم إعادة تشغيل Processing +preferences.sketchbook_location = موقع دفتر المخطوطات +preferences.sketchbook_location.popup = موقع دفتر المخطوطات +preferences.language = اللغة +preferences.editor_and_console_font = خط المحرر ووحدة الأوامر +preferences.editor_and_console_font.tip = .اختر خطاً لاستخدامه في المحرر ووحدة الأوامر.
يمكن استخدام الخطوط ذات الفراغات الموحدة فقط +preferences.editor_font_size = حجم خط المحرر +preferences.console_font_size = حجم خط وحدة الأوامر +preferences.zoom = حجم الواجهة +preferences.zoom.auto = تلقائي +preferences.background_color = لون الخلفية خلال وضعية التقديم +preferences.background_color.tip = اختر لون خلفية لاستخدامها في وضعية التقديم.
وضعية التقديم تقوم بعرض المخطوطة على ملء الشاشة.
يمكن تشغيل وضعية التقديم من نافذة المخطوط. +preferences.use_smooth_text = استخدام خط سلس في نافذة المحرر +preferences.enable_complex_text_input = تفعيل وضعية الإدخال المعقدة +preferences.enable_complex_text_input_example = يقصد هنا اللغة اليابانية +preferences.continuously_check = تحقق من الأخطاء بشكل دائم +preferences.show_warnings = أظهر التحذيرات +preferences.code_completion = إكمال شفرة المصدر باستخدام +preferences.trigger_with = تفعيل باستخدام +preferences.cmd_space = فراغ +preferences.suggest_imports = اقتراح أوامر استيراد المكتبات +preferences.increase_max_memory = زيادة الذاكرة المتاحة إلى +preferences.delete_previous_folder_on_export = حذف الملف السابق بعد التصدير +preferences.check_for_updates_on_startup = السماح بالبحث التلقائي عن التحديثات (راجع الأسئلة الشائعة لتفاصيل عن المعلومات المشاركة) +preferences.run_sketches_on_display = تشغيل المخطوط على الشاشة. +preferences.run_sketches_on_display.tip = لتحديد الشاشة التي ستستخدم لعرض المخطوط.
كالعادة, إذا تم تحريك النافذة, سيعاد فتحها في المرة القادمة
في نفس هذا المكان. لكن في حال تشغيل المخطوط في وضعية
العرض (الشاشة الملئة), سيتم استخدام هذه الشاشة المحددة للعرض. +preferences.automatically_associate_pde_files = تلقائياً مع بروسسنج .pde ربط الملفات بلاحقة +preferences.launch_programs_in = بدء البرنامج في +preferences.launch_programs_in.mode = الوضع +preferences.file = يمكن تعديل المزيد من الإعدادات في الملف +preferences.file.hint = قم بالتعديل عندما يكون Processing غير مفعل + +# Sketchbook Location (Frame) +sketchbook_location = اختر مكان جديد لكتاب المخطوطات + +# Sketchbook (Frame) +sketchbook = كتاب مخطوطات +sketchbook.tree = كتاب مخطوطات + +# Examples (Frame) +examples.title = أمثلة %s +examples.add_examples = أضف أمثلة... +examples.libraries = المكتبات المشاركة +examples.core_libraries = المكتبات +examples.contributed = الأمثلة المشاركة + +# Export (Frame) +export = خيارات التصدير +export.platforms = المنصات +export.options = الخيارات +export.options.present = وضعية التقديم +export.options.show_stop_button = إظهار زر التوقف +export.description.line1 = خيار "التصدير إلى تطبيق" ينتج برامج قابلة للتنفيذ, +export.description.line2 = برنامج منفصل لمنصات محددة. +export.unsaved_changes = حفظ التغييرات قبل التصدير؟ +export.notice.cancel.unsaved_changes = تم إلغاء التصدير. يجب حفظ التغييرات أولاً. +export.notice.exporting = يتم تصدير التطبيق +export.notice.exporting.done = تم التصدير. +export.notice.exporting.error = حصل خطأ خلال التصدير. +export.notice.exporting.cancel = تم إلغاء عملية التصدير. +export.tooltip.macosx = Mac OS X متاح فقط على Mac OS X التصدير ل +export.full_screen = ملء الشاشة +export.embed_java = تضمين جافا +export.embed_java.for = تضمين جافا ل +export.code_signing = توقيع الشفرة المصدرية +export.messages.is_read_only = هذا المخطوط للقراءة فقط +export.messages.is_read_only.description = بعض الملفات محددة ك "للقراءة فقط", \nستحتاج لإعادة حفظ المخطوطات في مكان آخر, \nوالمحاولة لاحقاً. +export.messages.cannot_export = لا يمكن التصدير +export.messages.cannot_export.description = لا يمكنك تصدير مخطوط لم يحفظ بعد. + +# Find (Frame) +find = البحث +find.find = ابحث عن: +find.replace_with = استبدل ب: +find.ignore_case = تجاهل الحالة (لا يلزم للغة العربية) +find.all_tabs = جميع علامات التبويب +find.wrap_around = طي النص حول +find.btn.replace_all = استبدال الكل +find.btn.replace = استبدال +find.btn.replace_and_find = استبدال وبحث +find.btn.previous = سابق +find.btn.find = ابحث + +# Find in reference (Frame) +find_in_reference = البحث في المرجع + +# File (Frame) +file = اختر صورة أو ملفات بيانات أخرى ليتم نسخها إلى مخطوطتك + +# Create Font (Frame) +create_font = اصنع خط جديد +create_font.label = استخدم هذه الأداة لتوليد خطوط لبرنامحك. \nاختر الخط والحجم المطلوب, وانقر على موافق لتوليد الخط. \nستتم إضافة الخط إلى ملف البيانات الخاص بالمخطوط الحالي. +create_font.size = الحجم +create_font.smooth = سلس +create_font.characters = الأحرف... +create_font.character_selector = أداة اختيار الأحرف +create_font.character_selector.label = الرموز الافتراضية ستتضمن أغلب الأشكال اللاتينية اللازمة لنظم تشغيل وينودوز وماك. \nتضمين جميع الرموز سيتطلب مساحة ذاكرة أكبر. \nلمزيد من التحكم, يمكنك اختيار أقسام معينة من تشفير يونيكود. +create_font.default_characters = الأحرف الافتراضية +create_font.all_characters = كل الأحرف +create_font.specific_unicode = مجموعات يونيكود محددة +create_font.filename = اسم الملف + +# Color Selector (Frame) +color_selector = أداة اختيار الألوان + +# Archive Sketch (Frame) +archive_sketch = أرشف المخطوط بإسم... + +# Tweak Mode +tweak_mode = وضع التعديل +tweak_mode.save_before_tweak = يرجى حفظ التغييرات قبل تفعيل وضع التعديل. +tweak_mode.keep_changes.line1 = هل تريد اللإبقاء على التغييرات؟ +tweak_mode.keep_changes.line2 = لقد تم تغيير بعض القيم في مخطوطتك. هل تريد حفظ التغييرات؟ + +# DebugTray +debugger.name = الإسم +debugger.value = القيمة +debugger.type = النوع + +# --------------------------------------- +# Toolbars + +# [Run/Present] [Stop] [New] [Open] [Save] +toolbar.run = تشغيل +toolbar.present = عرض +toolbar.stop = توقف +toolbar.debug = تنقيح +# --- +toolbar.new = جديد +toolbar.open = فتح +toolbar.save = حفظ +# toolbar.export_application = تصدير التطبيق +toolbar.add_mode = إضافة وضع جديد... + +# [Debug] [Continue] [Step] [Stop] [Toggle Breakpoints] [Variable Inspector] +#toolbar.debug.continue = الاستمرار +#toolbar.debug.step = خطوة +#toolbar.debug.step_into = تقدم نحو +#toolbar.debug.stop = توقف +#toolbar.debug.toggle_breakpoints = تبديل حالة نقطة التوقف +#toolbar.debug.variable_inspector = مظهر المتغيرات + + +# --------------------------------------- +# Editor + +# [Tab1] [Tab2] [v] +editor.header.new_tab = علامة تبويب حديدة +editor.header.rename = إعادة تسمية +editor.header.delete = حذف +editor.header.previous_tab = علامة التبويب السابقة +editor.header.next_tab = علامة التبويب اللاحقة +editor.header.delete.warning.title = هممم, لا. +editor.header.delete.warning.text = لا يمكنك حذف علامة التبويت الخاصة بالمخطوط الوحيد المفتوح. + +# PopUp menu +editor.popup.jump_to_declaration = القفز إلى التعريف. +editor.popup.show_usage = أظهر الاستخدام +editor.popup.rename = إعادة تسمية + +# Tabs +editor.tab.new = إسم جديد +editor.tab.new.description = إسم الملف الجديد +editor.tab.rename = إسم جديد +editor.tab.rename.description = إسم الملف الجديد + +# Sketch +editor.sketch.rename.description = إسم المخطوط الجديد + +editor.status.autoformat.no_changes = لم تلزم أية تغييرات من الفرمتة التلقائية +editor.status.autoformat.finished = إنتهت الفرمتة التلقائية. +editor.status.find_reference.select_word_first = اختر كلمة ليتم البحث عنها. +editor.status.find_reference.not_available = تعذر العثور على "%s" في المراجع. +editor.status.drag_and_drop.files_added.0 = لم تتم إضافة أية مخطوطات إلى الملف. +editor.status.drag_and_drop.files_added.1 = تم إضافة ملف واحد إلى المخطوط +editor.status.drag_and_drop.files_added.n = تم إضافة %d ملف إلى المخطوط. +editor.status.saving = يتم الحفظ... +editor.status.saving.done = تم الحفظ... +editor.status.saving.canceled = تم إلغاء الحفظ. +editor.status.printing = تتم الطباعة... +editor.status.printing.done = تمت الطباعة. +editor.status.printing.error = حدث خطأ خلال الطباعة. +editor.status.printing.canceled = تم إلغاء الطباعة. +editor.status.copy_as_html = تم نسخ شفرة مصدرية بتشفير HTML إلى لوح المقصوصات. +editor.status.debug.busy = أداة التنقيح مشغولة. +editor.status.debug.halt = أداة التنقيح متوقفة. +editor.status.archiver.create = ."%s" تم إنشاء الأرشيف +editor.status.archiver.cancel = تم إلغاء أرشفة المخطوط. + +# Errors +editor.status.warning = تحذير +editor.status.error = خطأ +editor.status.error_on = "%s" خطأ في +editor.status.missing.default = "%c" ينقص +editor.status.missing.semicolon = ";" تنقص فاصلة منقوطة +editor.status.missing.left_sq_bracket = يوجد قوص مربع يساري ناقص "[" +editor.status.missing.right_sq_bracket = يوجد قوص مربع يميني ناقص "]" +editor.status.missing.left_paren = يوجد قوص يساري ناقص "(" +editor.status.missing.right_paren = يوجد قوص يميني ناقص ")" +editor.status.missing.left_curly_bracket = يوجد قوص مجعد يساري ناقص "{" +editor.status.missing.right_curly_bracket = يوجد قوص مجعد يميني ناقص "}" +editor.status.missing.add = قد تحتاج لإضافة "%s" +editor.status.reserved_words = "color" و "int" من الكلمات المحجوزة ولا يمكن استخدامهما كأسماء متغيرات +editor.status.undefined_method = الدالة "%s(%s)" غير معرفة +editor.status.undefined_constructor = الباني "%s(%s)" غير معرف +editor.status.empty_param = الدالة "%s()" لا تحتاج لأية معطيات +editor.status.wrong_param = "%s(%s)" الدالة "%s()" تحتاج معطيات بشكل +editor.status.undef_global_var = المتغير العالمي "%s" غير موجود +editor.status.undef_class = الصنف "%s" غير موجود +editor.status.undef_var = المتغير "%s" غير موجود +editor.status.undef_name = تعذر العثور على الإسم "%s" +editor.status.type_mismatch = الأنواع غير متطابقة. "%s" لا يطابق "%s". +editor.status.unused_variable = قيمة المتغير المحلي "%s" غير مستخدمة +editor.status.uninitialized_variable = لم يتم تعريف المتغير المحلي "%s" +editor.status.no_effect_assignment = الإسناد للمتغير "%s" ليس لديه أي مفعول +editor.status.hiding_enclosing_type = لا يمكن أن يكون إسم الصنف "%s" كإسم المخطوط أو إسم الصنف المحتوي + +# Footer buttons +editor.footer.errors = أخطاء +editor.footer.errors.problem = مشاكل +editor.footer.errors.tab = علامات تبويب +editor.footer.errors.line = سطر +editor.footer.console = لوحة أوامر + +# New handler +new.messages.is_read_only = المخطوط للقراءة فقط. +new.messages.is_read_only.description = بعض الملفات للقراءة فقط. ستحتاج \nلإعادة حفظ الملف في مكان آخر, \nثم المحاولة لاحقاً. + +# Rename handler +rename.messages.is_untitled = المخطوط غير مسمى +rename.messages.is_untitled.description = ألا تريد حفظ المخطوط قبل إعادة التسمية؟ +rename.messages.is_modified = يرجى حفظ المخطوط قبل إعادة التسمية. +rename.messages.is_read_only = المخطوط للقراءة فقط. +rename.messages.is_read_only.description = بعض الملفات للقراءة فقط. ستحتاج \nلإعادة حفظ الملف في مكان آخر, \nثم المحاولة لاحقاً. + +# Naming handler +name.messages.problem_renaming = حدثت مشكلة خلال إعادة التسمية +name.messages.starts_with_dot.description = لا يمكن أن يبدأ الإسم بنقطة. +name.messages.invalid_extension.description = اللاحقة ".%s" غير صالحة +name.messages.main_java_extension.description = .%s علامة التبويب الأولى لا يمكن أن تكون لملف من نوع +name.messages.new_sketch_exists = لا +name.messages.new_sketch_exists.description = يوجد ملف بإسم "%s" في المكان المستهدف "%s" نفسه +name.messages.new_folder_exists = لا يمكن إعادة التسمية +name.messages.new_folder_exists.description = عفواً, يوجد ملف (أو مجلد) بنفس الإسم "%s" من قبل. +name.messages.error = خطأ +name.messages.no_rename_folder.description = تعذرت إعادة تسمية ملف المخطوطات +name.messages.no_rename_file.description = تعذرت إعادة تسمية "%s" إلى "%s". +name.messages.no_create_file.description = تعذر استحداث الملف "%s"\nفي "%s" + +# Delete handler +delete.messages.cannot_delete = لا يمكن الحذف +delete.messages.cannot_delete.description = لا يمكنك حذف مخطوط قبل حفظه +delete.messages.cannot_delete.file = لم أستطع فعل هذا +delete.messages.cannot_delete.file.description = تعذر الحذف +delete.messages.is_read_only = المخطوط للقراءة فقط. +delete.messages.is_read_only.description = بعض الملفات للقراءة فقط. ستحتاج \nلإعادة حفظ الملف في مكان آخر, \nثم المحاولة لاحقاً. + +# Save handler +save_file.messages.is_read_only = المخطوط للقراءة فقط. +save_file.messages.is_read_only.description = بعض الملفات للقراءة فقط. ستحتاج \nلإعادة حفظ الملف في مكان آخر. +save_file.messages.sketch_exists = تعذر الحفظ +save_file.messages.sketch_exists.description = يوجد ملف بإسم “%s” سلفاُ. +save_file.messages.tab_exists = نوب +save_file.messages.tab_exists.description = تعذر حفظ المخطوط بإسم "%s" ,لأن المخطوط فيه علامة تبويب بهذا الإسم حالياً. +save_file.messages.recursive_save = نوب نوب نوب +save_file.messages.recursive_save.description = لا يمكنك حفظ مخطوط في ملف داخل نفسه, هذا سيحدث العديد من المشاكل. + +# Add handler +add_file.messages.is_read_only = المخطوط للقراءة فقط. +add_file.messages.is_read_only.description = بعض الملفات للقراءة فقط. ستحتاج \nلإعادة حفظ الملف في مكان آخر, \nثم المحاولة لاحقاً. +add_file.messages.confirm_replace = هل تريد استبدال النسخة الحالية من %s؟ +add_file.messages.error_adding = حدث خطأ خلال إضافة الملف +add_file.messages.cannot_delete.description = تعذر حذف ملف '%s' +add_file.messages.cannot_add.description = فشلت إضافة '%s' إلى المخطوط +add_file.messages.same_file = لا يمكنك خداعي +add_file.messages.same_file.description = تم سابقاُ نسخ هذا الملف إلى نفس المكان المستهدف. + +# Temp folder creator +temp_dir.messages.bad_build_folder = ملف بناء المخطوط غير صالح +temp_dir.messages.bad_build_folder.description = تعذر العثور على مكان لبناء المخطوط. + +# Ensure Existance +ensure_exist.messages.missing_sketch = اختفى المخطوط +ensure_exist.messages.missing_sketch.description = تعذر العثور على ملف المخطوط. \nسيتم إعادة حفظ المخطوط في نفس المكان المحدد, \nلكن كل شيء عدا الشفرة المصدرية سيضيع. +ensure_exist.messages.unrecoverable = تعذرت إعادة الحفظ +ensure_exist.messages.unrecoverable.description = تعذرت إعادة حفظ المخطوط. لتجنب خسارة كل جهد حياتك على هذا الملف, \nقم بنسخ الشفرة المصدرية ولصقها في محرر نصوص آخر, إحتياطاً. + +# Check name +check_name.messages.is_name_modified = يجب تعديل اسم المخطوط. يمكن أن تحتوي الأسماء على \nرموز وأرقام بتشفير ASCII (بشرط أن لا تبدأ برقم). \nيجب أن يكون طول الإسم أقل من 64 رمزاً. + +# --------------------------------------- +# Contributions + +# Contribution Panel +contrib = مدير المشاركات +contrib.manager_title.update = مدير التحديثات +contrib.manager_title.mode = مدير الأوضاع +contrib.manager_title.tool = مدير الأدوات +contrib.manager_title.library = مدير المكتبات +contrib.manager_title.examples = مدير الأمثلة +contrib.category = الفئة: +contrib.filter_your_search = فلترة نتائج البحث.. +contrib.show_only_compatible.mode = إظهار الأوضاع المتوافقة فقط. +contrib.show_only_compatible.tool = إظهار الأدوات المتوافقة فقط. +contrib.show_only_compatible.library = إظهار المكتبات المتوافقة فقط. +contrib.show_only_compatible.examples = إظهار الأمثلة المتوافقة فقط. +contrib.show_only_compatible.update = إظهار التحديثات المتوافقة فقط. +contrib.restart = إعادة تشغيل Processing +contrib.unsaved_changes = يوجد تغييرات غير محفوظة +contrib.unsaved_changes.prompt = هل انت متأكد انك تريد إعادة تشغيل البرنامج قبل حفظ التغييرات أولاً؟ +contrib.messages.remove_restart = يرجى إعادة تشغيل البرنامح لإنهاء حذف هذا العنصر. +contrib.messages.install_restart = يرجى إعادة تشغيل البرنامح لإنهاء تثبيت هذا العنصر. +contrib.messages.update_restart = يرجى إعادة تشغيل البرنامح لإنهاء تحديث هذا العنصر. +contrib.errors.list_download = فشل تحميل قائمة المشاركات المتوفرة. +contrib.errors.list_download.timeout = حدث خطأ خلال تحميل قائمة المشاركات. +contrib.errors.download_and_install = . %s حدث خطأ خلال تحميل وتنزيل +contrib.errors.description_unavailable = لا يوجد وصف. +contrib.errors.malformed_url = الرابط الذي تم تحميله من Processing.org لا يعمل. \nبإمكانك تثبيت المكتبة بشكل يدوي عن طريق زيارة موقع المكتبة الإلكتروني. +contrib.errors.needs_repackage = يجب إعادة حزم %s وفقاً لشروط %s. +contrib.errors.no_contribution_found = تعذر العثور على %s في الملف المحمل. +contrib.errors.overwriting_properties = .properties حصل خلل خلال استبدال محتوى ملف +contrib.errors.install_failed = فشل التثبيت. +contrib.errors.update_on_restart_failed = فشل تحديث %s بعد إعادة التشغيل. +contrib.errors.temporary_directory = فشلت الكتابة في الملف المؤقت. +contrib.errors.contrib_download.timeout = حصلت مشكلة في اتصال الانترنت خلال تحميل %s. +contrib.errors.no_internet_connection = يبدو أنك غير متصل بالإنترنت... +contrib.status.downloading_list = يتم تحميل قائمة المشاركات... +contrib.status.connecting = يتم الاتصال... +contrib.status.done = تم الانتهاء +contrib.all = الكل +contrib.undo = تراجع +contrib.remove = إزالة +contrib.install = تثبيت +contrib.progress.installing = يتم تثبيت +contrib.progress.starting = يتم بدأ +contrib.progress.downloading = يتم تنزيل +contrib.download_error = حدث خطأ خلال تنزيل المشاركات +contrib.unsupported_operating_system = يبدو أن نظام التشغيل الخاص بك غير مدعوم. يرجى زيارة %s\ المكتبة للمزيد من المعلومات. +contrib.category.3d = 3D +contrib.category.animation = رسوم متحركة +contrib.category.data = بيانات ومعطيات +contrib.category.geometry = هندسيات +contrib.category.gui = واجهات مستخدم رسومية +contrib.category.hardware = عتاد مادي +contrib.category.i_o = مدخلات ومخرجات +contrib.category.math = رياضيات +contrib.category.simulation = محاكاة +contrib.category.sound = صوتيات +contrib.category.typography = تخطيط +contrib.category.utilities = خدمات +contrib.category.video_vision = فيديو ورؤية رقمية +contrib.category.other = آخر + +# Install on Startup +contrib.startup.errors.download_install = %s حدث خطأ خلال تحميل وتثبيت +contrib.startup.errors.temp_dir = فشل النسخ إلى ملف مؤقت خلال عملية تحميل وتنزيل %s +contrib.startup.errors.new_marker = يبدو أن هنالك مشكلة بين مؤشر المشاركات الغير محدثة و %s. قد تحتاج إلى تحديث المشاركة بشكل يدوي. + +# Install on Import +contrib.import.dialog.title = المكتبات المفقودة المتوفرة +contrib.import.dialog.primary_text = المكتبات المستوردة التالية متوفرة للتحميل, لكن لم يتم تثبيتها بعد. +contrib.import.dialog.secondary_text = هل تود تثبيتهم الآن؟ +contrib.import.progress.download = ...%s يتم تحميل +contrib.import.progress.install = ...%s يتم تثبيت +contrib.import.progress.done = .%s تم تثبيت +contrib.import.progress.final_list = تم تثبيت المكتبات التالية: +contrib.import.errors.link = يبدو أن رابط التحميل للمكتبة %s لا يعمل. + +# --------------------------------------- +# Warnings + +warn.delete = حذف +warn.delete.sketch = هل أنت متأكد انك تريد حذف هذا المخطوط؟ +warn.delete.file = هل انت متأكد أنك تود حذف "%s"؟ +warn.cannot_change_mode.title = لا يمكن تغيير الوضع +warn.cannot_change_mode.body = لا يمكنك تغيير الوضع, لأن وضع "%s" غير متوافق مع الوضع الحالي. + + +# --------------------------------------- +# Update Check + +update_check = تحديث +update_check.updates_available.core = يوجد نسخة جديدة من بروسسنج جاهزة للتحميل. \nهل تود زيارة الموقع الرسمي لتحميلها؟ +update_check.updates_available.contributions = يوجد تحديثات متوفرة لبعض المشاركات المثبتة. \nهل تريد الذهاب إلى مدير المشاركات الآن؟ + + +# --------------------------------------- +# Color Chooser + +color_chooser = أداة اختيار الألوان +color_chooser.select = تحديد + +# --------------------------------------- +# Movie Maker + +movie_maker = صانع الأفلام +movie_maker.title = QuickTime صانع أفلام +movie_maker.blurb = This tool creates a QuickTime movie from a sequence of images.

To avoid artifacts caused by re-compressing images as video,
use TIFF, TGA (from Processing), or PNG images as the source.

TIFF and TGA images will write more quickly, but require more disk:
saveFrame("frames/####.tif");
saveFrame("frames/####.tga");

PNG images are smaller, but your sketch will run more slowly:
saveFrame("frames/####.png");

This code is based on QuickTime Movie Maker 1.5.1 2011-01-17.
Copyright © 2010-2011 Werner Randelshofer. All rights reserved.
+movie_maker.image_folder_help_label = اسحب ملف يحتوي على الصور إلى الحقل السفلي: +movie_maker.choose_button = اختر... +movie_maker.select_image_folder = اختر ملف الصور... +movie_maker.sound_file_help_label = إلى الحقل السفلي: (.au, .aiff, .wav, .mp3) اسحب ملف يحتوي على ملفات صوت بصيغة +movie_maker.select_sound_file = اختر ملف الصوت... + +movie_maker.create_movie_button = فلم جديد... +movie_maker.save_dialog_prompt = حفظ الفلم ك... +movie_maker.width = العرض +movie_maker.height = الارتفاع +movie_maker.compression = الضغط +movie_maker.compression.animation = رسوم متحركة +movie_maker.compression.jpeg = JPEG +movie_maker.compression.png = PNG +movie_maker.framerate = تردد الأطر: +movie_maker.orig_size_button = نفس الحجم الأصلي +movie_maker.orig_size_tooltip = قم باختيار هذا المربع إذا كان الملف يحتوي على أطر فيديو بالتشفير والحجم المطلوب. + +movie_maker.error.avoid_tiff = حاول باستخدام صور بلاحقة TGA أو PNG بدل TIFF. +movie_maker.error.badnumbers = يجب أن تكون قيم الطول والعرض أعداد حقيقية أكبر من الصفر, ويحب أن يكون تردد الأطر أكبر من الصفر. +movie_maker.error.cannot_read = .%s تعذرت قراءة +movie_maker.error.cannot_read_maybe_bad = تعذرت قراءة %s, قد يكون الملف سيئاً. +movie_maker.error.movie_failed = .QuickTime فشل انتاج فلم من نوع +movie_maker.error.need_input = يجب عليك تحديد ملف يحتوي على ملفات صوتية, ملفات صور, أو كلاهما. +movie_maker.error.no_images_found = لم يتم العثور على ملفات صور هنا. +movie_maker.error.sorry = عذراً +movie_maker.error.unknown_tga_format = لاحقة الملف %s من نوع .tga غير معروفة. + +movie_maker.progress.creating_file_name = .%s يتم الآن إنتاج +movie_maker.progress.creating_output_file = يتم الآن إنتاج الملف +movie_maker.progress.initializing = بدء العملية... +movie_maker.progress.processing = .%s يتم معالجة diff --git a/build/shared/lib/languages/PDE_de.properties b/build/shared/lib/languages/PDE_de.properties index 978f69e34d..21d057439e 100644 --- a/build/shared/lib/languages/PDE_de.properties +++ b/build/shared/lib/languages/PDE_de.properties @@ -40,8 +40,8 @@ menu.edit.paste = Einfügen menu.edit.select_all = Alle auswählen menu.edit.auto_format = Autoformatierung menu.edit.comment_uncomment = Ein- und Auskommentieren -menu.edit.increase_indent = Ausrücken -menu.edit.decrease_indent = Einrücken +menu.edit.increase_indent = → Ausrücken +menu.edit.decrease_indent = ← Einrücken menu.edit.find = Suchen ... menu.edit.find_next = Weiter suchen menu.edit.find_previous = Vorher suchen @@ -267,7 +267,7 @@ toolbar.debug.variable_inspector = Variable-Inspector anzeigen/ausblenden # [Tab1] [Tab2] [v] editor.header.new_tab = Neuer Tab -editor.header.rename = Unbenennen +editor.header.rename = Umbenennen editor.header.delete = Löschen editor.header.previous_tab = Nächster Tab editor.header.next_tab = Vorheriger Tab @@ -310,7 +310,7 @@ new.messages.is_read_only = Sketch ist Read-Only new.messages.is_read_only.description = Einige Dateien sind als "read-only" markiert,\naus dem Grund musst du das Sketch an einer neuer\nStelle abspeichern, und es noch mal ausprobieren. # Rename handler -rename.messages.is_untitled = Unbenennen abgebrochen +rename.messages.is_untitled = Umbenennen abgebrochen rename.messages.is_untitled.description = Sketch muss zuvor abgespeichert werden\nbevor es unbenannt werden kann. rename.messages.is_modified = Speichere Sketch vor dem Umbenennen. rename.messages.is_read_only = Sketch ist Read-Only diff --git a/build/shared/lib/languages/PDE_el.properties b/build/shared/lib/languages/PDE_el.properties index dbdefe7b93..07c348ab2e 100644 --- a/build/shared/lib/languages/PDE_el.properties +++ b/build/shared/lib/languages/PDE_el.properties @@ -40,8 +40,8 @@ menu.edit.paste = Επικόλληση menu.edit.select_all = Επιλογή Όλων menu.edit.auto_format = Αυτόματη Μορφοποίηση menu.edit.comment_uncomment = Σχολιασμός/Αποσχολιασμός -menu.edit.increase_indent = Αύξηση Εσοχής -menu.edit.decrease_indent = Μείωση Εσοχής +menu.edit.increase_indent = → Αύξηση Εσοχής +menu.edit.decrease_indent = ← Μείωση Εσοχής menu.edit.find = Αναζήτηση... menu.edit.find_next = Αναζήτηση Επόμενου menu.edit.find_previous = Αναζήτηση Προηγούμενου @@ -215,7 +215,7 @@ export.tooltip.macosx = Η εξαγωγή Mac OS X είναι διαθέσιμη export.full_screen = Πλήρης Οθόνη export.embed_java = Ενσωματωμένη Java export.embed_java.for = Ενσωματωμένη Java για -export.code_signing = Υπογραφή Κώδικα +export.code_signing = Υπογραφή Κώδικα # Find (Frame) find = Αναζήτηση @@ -373,14 +373,14 @@ editor.footer.console = Κονσόλα # New handler new.messages.is_read_only = Το Σχέδιο είναι Μόνο για Ανάγνωση -new.messages.is_read_only.description = Μερικά αρχεία είναι σημειωμένα "Μόνο για Ανάγνωση", οπότε θα χρειαστεί να ξανα-αποθηκεύσεις το Σχέδιο σε διαφορετική θέση,\nκαι να προσπαθήσεις ξανά. +new.messages.is_read_only.description = Μερικά αρχεία είναι σημειωμένα "Μόνο για Ανάγνωση", οπότε θα χρειαστεί να ξανα-αποθηκεύσεις το Σχέδιο σε διαφορετική θέση,\nκαι να προσπαθήσεις ξανά. # Rename handler rename.messages.is_untitled = Το Σχέδιο Δεν έχει Τίτλο rename.messages.is_untitled.description = Τι θα έλεγες να αποθηκεύσεις το Σχέδιο\nπριν προσπαθήσεις να το μετονομάσεις; rename.messages.is_modified = Παρακαλώ αποθήκευσε το Σχέδιο πριν το μετονομάσεις. -rename.messages.is_read_only = Το Σχέδιο είναι Μόνο για Ανάγνωση -rename.messages.is_read_only.description = Μερικά αρχεία είναι σημειωμένα "Μόνο για Ανάγνωση", οπότε θα χρειαστεί να ξανα-αποθηκεύσεις το Σχέδιο σε διαφορετική θέση,\nκαι να προσπαθήσεις ξανά. +rename.messages.is_read_only = Το Σχέδιο είναι Μόνο για Ανάγνωση +rename.messages.is_read_only.description = Μερικά αρχεία είναι σημειωμένα "Μόνο για Ανάγνωση", οπότε θα χρειαστεί να ξανα-αποθηκεύσεις το Σχέδιο σε διαφορετική θέση,\nκαι να προσπαθήσεις ξανά. # Delete handler delete.messages.cannot_delete = Αποτυχία Διαγραφής @@ -409,7 +409,7 @@ contrib.show_only_compatible.library = Εμφάνιση Μόνο Συμβατώ contrib.show_only_compatible.examples = Εμφάνιση Μόνο Συμβατών Παραδειγμάτων contrib.show_only_compatible.update = Εμφάνιση Μόνο Συμβατών Ενημερώσεων contrib.restart = Επανεκκίνηση Processing -contrib.unsaved_changes = Βρέθηκαν μη αποθηκευμένες ενημερώσεις +contrib.unsaved_changes = Βρέθηκαν μη αποθηκευμένες ενημερώσεις contrib.unsaved_changes.prompt = Είσαι σίγουρος ότι θέλεις να κάνεις επανεκκίνηση της Processing χωρίς να αποθηκεύσεις τις αλλαγές; contrib.messages.remove_restart = Παρακαλώ κάνε επανεκκίνηση της Processing για να ολοκληρωθεί η αφαίρεση αυτού του αντικειμένου. contrib.messages.install_restart = Παρακαλώ κάνε επανεκκίνηση της Processing για να ολοκληρωθεί η εγκατάσταση αυτού του αντικειμένου. @@ -445,7 +445,7 @@ contrib.category.animation = Animation contrib.category.data = Δεδομένα contrib.category.geometry = Γεωμετρία contrib.category.gui = GUI -contrib.category.hardware = Υλικό +contrib.category.hardware = Υλικό contrib.category.i_o = Ε/Ε contrib.category.math = Μαθηματικά contrib.category.simulation = Προσομοίωση diff --git a/build/shared/lib/languages/PDE_es.properties b/build/shared/lib/languages/PDE_es.properties index 93c0feb394..8752a1bd0f 100644 --- a/build/shared/lib/languages/PDE_es.properties +++ b/build/shared/lib/languages/PDE_es.properties @@ -40,8 +40,8 @@ menu.edit.paste = Pegar menu.edit.select_all = Seleccionar todo menu.edit.auto_format = Autoformato menu.edit.comment_uncomment = Comentar/Descomentar -menu.edit.increase_indent = Aumentar indentación -menu.edit.decrease_indent = Reducir indentación +menu.edit.increase_indent = → Aumentar indentación +menu.edit.decrease_indent = ← Reducir indentación menu.edit.find = Buscar... menu.edit.find_next = Buscar siguiente menu.edit.find_previous = Buscar anterior @@ -60,7 +60,7 @@ menu.library.contributed = Contribuidas menu.library.no_core_libraries = el modo no tiene bibliotecas incluidas # --- menu.sketch = Sketch -menu.sketch.show_sketch_folder = Mostrar carpeta de sketches +menu.sketch.show_sketch_folder = Mostrar carpeta del sketch menu.sketch.add_file = Añadir archivo # | File | Edit | Sketch | Debug | Tools | Help | @@ -320,6 +320,10 @@ editor.header.next_tab = Pestaña siguiente editor.header.delete.warning.title = No editor.header.delete.warning.text = No puedes eliminar la última pestaña del último sketch abierto +# PopUp menu +editor.popup.show_usage = Mostrar uso... +editor.popup.rename = Renombrar... + # Tabs editor.tab.new = Nuevo nombre editor.tab.new.description = Nombre para el archivo nuevo @@ -375,6 +379,7 @@ editor.status.type_mismatch = Discrepancia de tipos, "%s" no coincide con "%s" editor.status.unused_variable = El valor de la variable local "%s" no se utiliza editor.status.uninitialized_variable = Puede que la variable local "%s" no haya sido inicializada editor.status.no_effect_assignment = La asignación a la variable "%s" no tiene ningún efecto +editor.status.hiding_enclosing_type = Las clase "%s" no puede tener el mismo nombre que el sketch o su clase envolvente # Footer buttons editor.footer.errors = Errores @@ -401,10 +406,10 @@ name.messages.invalid_extension.description = ".%s" no es una extensión válida name.messages.main_java_extension.description = La primera pestaña no puede ser un archivo .%s.\n(Puede que sea tiempo de graduarse\na un entorno de programación "real") name.messages.new_sketch_exists = No name.messages.new_sketch_exists.description = Un archivo llamado "%s" ya existe en\n"%s" -name.messages.new_folder_exists = No se puede cambiar de nombre +name.messages.new_folder_exists = No se puede cambiar de nombre name.messages.new_folder_exists.description = Un sketch (o directorio) con nombre "%s" ya existe. name.messages.error = Error -name.messages.no_rename_folder.description = No se pudo renombrar el directorio del sketch. +name.messages.no_rename_folder.description = No se pudo renombrar el directorio del sketch. name.messages.no_rename_file.description = No se pudo renombrar "%s" a "%s" name.messages.no_create_file.description = No se pudo crear el archivo "%s"\nen "%s" @@ -430,7 +435,7 @@ save_file.messages.recursive_save.description = No puedes guardar un sketch en u add_file.messages.is_read_only = El sketch es de sólo-lectura add_file.messages.is_read_only.description = Algunos archivos están marcados como de sólo-lectura, por\nlo que vas a tener que guardar el sketch en otra ubicación,\ne intentar de nuevo. add_file.messages.confirm_replace = ¿Reemplzara la versión existente de %s? -add_file.messages.error_adding = Error al añadir el archivo +add_file.messages.error_adding = Error al añadir el archivo add_file.messages.cannot_delete.description = No se pudo eliminar el archivo existente '%s'. add_file.messages.cannot_add.description = No se pudo añadir '%s' al sketch. add_file.messages.same_file = No puedes engañarme @@ -500,17 +505,17 @@ contrib.unsupported_operating_system = Tu sistema operativo no está soportado. contrib.category.3d = 3D contrib.category.animation = Animación contrib.category.data = Datos -contrib.category.geometry = Geometría +contrib.category.geometry = Geometría contrib.category.gui = Interfaz gráfica -contrib.category.hardware = Hardware +contrib.category.hardware = Hardware contrib.category.i_o = Entrada/Salida contrib.category.math = Matemáticas contrib.category.simulation = Simulación -contrib.category.sound = Sonido -contrib.category.typography = Tipografía -contrib.category.utilities = Utilidades +contrib.category.sound = Sonido +contrib.category.typography = Tipografía +contrib.category.utilities = Utilidades contrib.category.video_vision = Visión de video -contrib.category.other = Otros +contrib.category.other = Otros # Install on Startup contrib.startup.errors.download_install = Ocurrió un error al descargar e instalar %s @@ -533,6 +538,8 @@ contrib.import.errors.link = Error: La biblioteca %s tiene un enlace de descarga warn.delete = Eliminar warn.delete.sketch = ¿Seguro que deseas eliminar este sketch? warn.delete.file = ¿Seguro que deseas eliminar "%s"? +warn.cannot_change_mode.title = No se puede cambiar el modo +warn.cannot_change_mode.body = No se puede cambiar el modo porque\nel modo "%s" no es compatible con el modo actual. # --------------------------------------- @@ -573,8 +580,8 @@ movie_maker.orig_size_tooltip = Marca esta casilla si el directorio ya contiene movie_maker.error.avoid_tiff = Prueba usar imagenes TGA o PNG en lugar de TIFF. movie_maker.error.badnumbers = El ancho y alto deben ser números enteros mayores que cero; las imagenes por segundo deben ser un número mayor a cero. -movie_maker.error.cant_read = No se pudo leer %s. -movie_maker.error.cant_read_maybe_bad = No se pudo leer %s; puede que esté corrupto. +movie_maker.error.cannot_read = No se pudo leer %s. +movie_maker.error.cannot_read_maybe_bad = No se pudo leer %s; puede que esté corrupto. movie_maker.error.movie_failed = Falló la creación de la película QuickTime. movie_maker.error.need_input = Debes especificar el directorio con los archivos de imagen, el archivo de sonido, o ambos. movie_maker.error.no_images_found = No se encontraron archivos de imagen. diff --git a/build/shared/lib/languages/PDE_fr.properties b/build/shared/lib/languages/PDE_fr.properties index e09a33e075..37209e9991 100644 --- a/build/shared/lib/languages/PDE_fr.properties +++ b/build/shared/lib/languages/PDE_fr.properties @@ -40,8 +40,8 @@ menu.edit.paste = Coller menu.edit.select_all = Selectionner tout menu.edit.auto_format = Mise en forme automatique menu.edit.comment_uncomment = Commenter/Décommenter -menu.edit.increase_indent = Augmenter l'indentation -menu.edit.decrease_indent = Diminuer l'indentation +menu.edit.increase_indent = → Augmenter l'indentation +menu.edit.decrease_indent = ← Diminuer l'indentation menu.edit.find = Rechercher... menu.edit.find_next = Rechercher suivant menu.edit.find_previous = Rechercher précédent diff --git a/build/shared/lib/languages/PDE_it.properties b/build/shared/lib/languages/PDE_it.properties new file mode 100644 index 0000000000..4a1334e82d --- /dev/null +++ b/build/shared/lib/languages/PDE_it.properties @@ -0,0 +1,589 @@ +Annulla + +# --------------------------------------- +# Language: Italiano (Italian) (it) +# --------------------------------------- + + +# --------------------------------------- +# Menu + +# | File | Edit | Sketch | Debug | Tools | Help | +# | File | +menu.file = File +menu.file.new = Nuovo +menu.file.open = Apri... +menu.file.recent = Apri Recenti +menu.file.sketchbook = Cartelle degli Sketch... +menu.file.sketchbook.empty = Cartella degli Sketch vuota +menu.file.examples = Esempi... +menu.file.close = Chiudi +menu.file.save = Salva +menu.file.save_as = Salva con nome... +menu.file.export_application = Esporta Applicazione... +menu.file.page_setup = Imposta Pagina +menu.file.print = Stampa... +menu.file.preferences = Preferenze... +menu.file.quit = Esci + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Edit | +menu.edit = Modifica +menu.edit.undo = Annulla +menu.edit.redo = Ripeti +menu.edit.action.addition = addizione +menu.edit.action.deletion = cancellazione +menu.edit.cut = Taglia +menu.edit.copy = Copia +menu.edit.copy_as_html = Copia come HTML +menu.edit.paste = Incolla +menu.edit.select_all = Seleziona Tutto +menu.edit.auto_format = Formattazione Automatica +menu.edit.comment_uncomment = Commenta/Rimuovi commento +menu.edit.increase_indent = → Aumenta Indentazione +menu.edit.decrease_indent = ← Diminuisci Indentazione +menu.edit.find = Trova... +menu.edit.find_next = Trova Successivo +menu.edit.find_previous = Trova Puccessivo +menu.edit.use_selection_for_find = Trova Testo Selezionato + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Sketch | +menu.sketch.run = Esegui +menu.sketch.present = Presenta +menu.sketch.tweak = Tweak +menu.sketch.stop = Stop +# --- +menu.library = Importa Libreria... +menu.library.add_library = Aggiungi Libreria... +menu.library.contributed = Librerie di terze parti +menu.library.no_core_libraries = modalità senza librerie di default +# --- +menu.sketch = Sketch +menu.sketch.show_sketch_folder = Apri cartella dello Sketch +menu.sketch.add_file = Aggiungi File... + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Debug | +menu.debug = Debug +menu.debug.enable = Abilitare Debugger +menu.debug.disable = Disabilitare Debugger +#menu.debug.show_debug_toolbar = Show Debug Toolbar +#menu.debug.debug = Debug +#menu.debug.stop = Stop +# --- +menu.debug.toggle_breakpoint = Toggle Breakpoint +#menu.debug.list_breakpoints = List breakpoints +# --- +# used for both menus and toolbars +menu.debug.step = Step +menu.debug.step_into = Step Avanti +menu.debug.step_out = Step Indietro +menu.debug.continue = Continua +# --- +#menu.debug.print_stack_trace = Print Stack Trace +#menu.debug.print_locals = Print Locals +#menu.debug.print_fields = Print Fields +#menu.debug.print_source_location = Print Source Location +#menu.debug.print_threads = Print Threads +# --- +#menu.debug.variable_inspector = Variable Inspector +menu.debug.show_variables = Mostra Variabili +menu.debug.hide_variables = Nascondi Variabili +#menu.debug.show_sketch_outline = Show Sketch Outline +#menu.debug.show_tabs_list = Show Tabs List + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Tools | +menu.tools = Strumenti +menu.tools.color_selector = Selezionatore dei colori... +menu.tools.create_font = Crea Font... +menu.tools.archive_sketch = Archivia Sketch +menu.tools.fix_the_serial_lbrary = Ripara la "Serial Library" +menu.tools.install_processing_java = Installa "processing-java" +menu.tools.add_tool = Aggiungi Strumento... + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Help | +menu.help = Aiuto +menu.help.welcome = Benvenuto in Processing 3 +menu.help.about = Riguardo a Processing +menu.help.environment = Ambiente di Sviluppo +menu.help.reference = Guida di Riferimento +menu.help.find_in_reference = Cerca nella Guida +menu.help.libraries_reference = Guida delle Librerie +menu.help.tools_reference = Guida degli Strumenti +menu.help.empty = (vuoto) +menu.help.online = Online +menu.help.getting_started = Primi Passi +menu.help.getting_started.url = http://processing.org/learning/gettingstarted/ +menu.help.troubleshooting = Risoluzione dei Problemi +menu.help.troubleshooting.url = http://wiki.processing.org/w/Troubleshooting +menu.help.faq = Domande Frequenti +menu.help.faq.url = http://wiki.processing.org/w/FAQ +menu.help.foundation = La Processing Foundation +menu.help.foundation.url = http://processing.org/foundation/ +menu.help.visit = Visita Processing.org +menu.help.visit.url = http://processing.org/ + + +# --------------------------------------- +# Basics + +# Buttons +prompt.yes = Si +prompt.no = No +prompt.cancel = Cancella +prompt.ok = Ok +prompt.browse = Naviga +prompt.export = Esporta + + +# --------------------------------------- +# Frames + +# Open (Frame) +open = Apri uno sketch di Processing... + +# Save (Frame) +save = Salva la cartella degli sketch con nome... +save.title = Vuoi salvare le modifiche di %s
prima di chiudere? +save.hint = Se non salverai, le tue modifiche verranno perse. +save.btn.save = Salva +save.btn.dont_save = Non salvare + +# Close (Frame) also used to prompt on non-OS X machines +close.unsaved_changes = Salvare le modifiche di %s? + +# Preferences (Frame) +preferences = Preferenze +preferences.button.width = 80 +preferences.requires_restart = richiede il riavvio di Processing +preferences.sketchbook_location = Percorso della cartella degli sketch +preferences.sketchbook_location.popup = Percorso della cartella degli sketch +preferences.language = Lingua +preferences.editor_and_console_font = Font dell'Editor e della Console +preferences.editor_and_console_font.tip = Scegli il font usato dall'Editor e dalla Console.
Solo font monospaced (larghezza fissa) possono essere usati,
sebbene la lista possa essere imperfetta. +preferences.editor_font_size = Dimensione del font dell'Editor +preferences.console_font_size = Dimensione del font della Console +preferences.zoom = Scala dell'interfaccia +preferences.zoom.auto = Automatica +preferences.background_color = Colore di sfondo durante la modalità "Presenta" +preferences.background_color.tip = Scegli il colore di sfondo durante la modalità "Presenta".
Questa modalità è utilizzata per mostrare uno sketch a tutto schermo;
è accessibile dal menù Sketch. +preferences.use_smooth_text = Usa un font semplice nell'Editor +preferences.enable_complex_text_input = Abilita la possibilità di usare caratteri complessi +preferences.enable_complex_text_input_example = per esempio Giapponese +preferences.continuously_check = Controlla continuamente la presenza di errori +preferences.show_warnings = Mostra Avvisi +preferences.code_completion = Completamento del codice con +preferences.trigger_with = Abilita con +preferences.cmd_space = spazio +preferences.suggest_imports = Suggerisci il codice di import +preferences.increase_max_memory = Aumenta la massima memoria disponibile a +preferences.delete_previous_folder_on_export = Elimina le cartelle precedenti dopo l'export +preferences.check_for_updates_on_startup = Consenti di controllare la presenza di aggiornamenti (vedi le FAQ per le informazioni condivise) +preferences.run_sketches_on_display = Esegui Sketch nel monitor +preferences.run_sketches_on_display.tip = Stabilisce il monitor nel quale gli sketch vengono inizalmente visualizzati.
Come al solito, se la finestra dello sketch viene spostata, si riaprirà nella
stessa posizione, tuttavia quando si esegue nella modalità "Presenta"
(tutto schermo), questo monitor verrà sempre utilizzato. +preferences.automatically_associate_pde_files = Associa automaticamente i file .pde con Processing +preferences.launch_programs_in = Lancia programmi in +preferences.launch_programs_in.mode = modalità +preferences.file = Più preferenze possono essere modificate nel file +preferences.file.hint = modificalo solo quando Processing non è aperto + +# Sketchbook Location (Frame) +sketchbook_location = Seleziona la nuova posizione della cartella degli Sketch + +# Sketchbook (Frame) +sketchbook = Cartella degli Sketch +sketchbook.tree = Cartella degli Sketch + +# Examples (Frame) +examples.title = %s Esempi +examples.add_examples = Aggiungi Esempi... +examples.libraries = Librerie di terze parti +examples.core_libraries = Librerie +examples.contributed = Esempi di terze parti + +# Export (Frame) +export = Opzioni di esportazione +export.platforms = Piattaforme +export.options = Opzioni +export.options.present = Modalità "Presenta" +export.options.show_stop_button = Mostra il bottone di Stop +export.description.line1 = Esporta come applicazione creerà +export.description.line2 = delle applicazioni esegubili per la piattaforma scelta. +export.unsaved_changes = Salvare le modifiche prima di esportare? +export.notice.cancel.unsaved_changes = Esportazione cancellata, prima di eseguirlo è necessario salvare. +export.notice.exporting = Esportando l'applicazione +export.notice.exporting.done = Esportazione eseguita. +export.notice.exporting.error = Errore durante l'esportazione. +export.notice.exporting.cancel = Esportazione come applicazione cancellata. +export.tooltip.macosx = L'esportazione per Mac OS X è disponibile solo su Mac OS X +export.full_screen = Tutto Schermo +export.embed_java = Embed Java +export.embed_java.for = Embed Java for +export.code_signing = Code Signing +export.messages.is_read_only = Sketch è in modalità di sola lettura +export.messages.is_read_only.description = Alcuni files sono in modalità sola lettura, quindi dovrai\nsalvare lo Sketch in un'altra posizione\ne provare di nuovo. +export.messages.cannot_export = Non è possibile esportare +export.messages.cannot_export.description = Non puoi esportare uno Sketch che non è ancora stato salvato. + +# Find (Frame) +find = Trova +find.find = Trova: +find.replace_with = Sostituisci con: +find.ignore_case = Ignora maiuscole / minuscole +find.all_tabs = Cerca in tutte le schede +find.wrap_around = Prosegui dall'inizio +find.btn.replace_all = Sostituisci tutto +find.btn.replace = Sostituisci +find.btn.replace_and_find = Trova e sostituisci +find.btn.previous = Trova precedente +find.btn.find = Trova + +# Find in reference (Frame) +find_in_reference = Trova nella guida + +# File (Frame) +file = Seleziona un'immagine o un altro file da copiare nel tuo sketch + +# Create Font (Frame) +create_font = Crea un Font +create_font.label = Usa questo strumento per creare dei font bitmap per il tuo programma.\nSeleziona un font e la dimensione, poi clicca su 'Ok' per generare il font.\nSarà aggiunto alla cartella dei dati del tuo sketch. +create_font.size = Dimensione +create_font.smooth = Caratteri semplici +create_font.characters = Caratteri... +create_font.character_selector = Selezionatore dei caratteri +create_font.character_selector.label = I caratteri di default includono gran parte dei caratteri bitmap per Mac OS\ne Windows Latin scripts. Includere tutti i caratteri può\nrichiedere una grande quantità di memoria per tutti i bitmap.\nPEr un controllo maggiore puoi selezionare ogni specifico blocco Unicode. +create_font.default_characters = Caratteri di default +create_font.all_characters = Tutti i caratteri +create_font.specific_unicode = Blocchi specifici Unicode +create_font.filename = Nome del file + +# Color Selector (Frame) +color_selector = Selezionatore dei colori + +# Archive Sketch (Frame) +archive_sketch = Archivia sketch come... + +# Tweak Mode +tweak_mode = Modalità Tweak +tweak_mode.save_before_tweak = Per favore salva lo sketch prima di avviare la modalità Tweak. +tweak_mode.keep_changes.line1 = Salvare le modifiche? +tweak_mode.keep_changes.line2 = Hai cambiato alcuni valori nello sketch. Vuoi salvare le modifiche? + +# DebugTray +debugger.name = Nome +debugger.value = Valore +debugger.type = Tipo + +# --------------------------------------- +# Toolbars + +# [Run/Present] [Stop] [New] [Open] [Save] +toolbar.run = Esegui +toolbar.present = Presenta +toolbar.stop = Stop +toolbar.debug = Debug +# --- +toolbar.new = Nuovo +toolbar.open = Apri +toolbar.save = Salva +# toolbar.export_application = Export Application +toolbar.add_mode = Aggiungi modalità... + +# [Debug] [Continue] [Step] [Stop] [Toggle Breakpoints] [Variable Inspector] +#toolbar.debug.continue = Continue +#toolbar.debug.step = Step +#toolbar.debug.step_into = Step Into +#toolbar.debug.stop = Stop +#toolbar.debug.toggle_breakpoints = Toggle Breakpoint +#toolbar.debug.variable_inspector = Variable Inspector + + +# --------------------------------------- +# Editor + +# [Tab1] [Tab2] [v] +editor.header.new_tab = Nuova scheda +editor.header.rename = Rinomina +editor.header.delete = Elimina +editor.header.previous_tab = Scheda precedente +editor.header.next_tab = Scheda successiva +editor.header.delete.warning.title = No. +editor.header.delete.warning.text = Non puoi eliminare la scheda principale del tuo unico sketch aperto.. + +# PopUp menu +editor.popup.jump_to_declaration = Vai alla Dichiarazione +editor.popup.show_usage = Mostra utilizzo... +editor.popup.rename = Rinomina... + +# Tabs +editor.tab.new = Nuovo Nome +editor.tab.new.description = Nome del nuovo file +editor.tab.rename = Nuovo Nome +editor.tab.rename.description = Nuovo nome del file + +# Sketch +editor.sketch.rename.description = Nuovo nome dello scketch + +editor.status.autoformat.no_changes = Nessuna modifica necessaria per l'Auto Format. +editor.status.autoformat.finished = Auto Format terminato. +editor.status.find_reference.select_word_first = Per prima cosa selezionare una parola da trovare nella guida. +editor.status.find_reference.not_available = Nessuna referenza disponibile per "%s". +editor.status.drag_and_drop.files_added.0 = Nessun file aggiunto allo sketch. +editor.status.drag_and_drop.files_added.1 = Un file aggiunto allo sketch. +editor.status.drag_and_drop.files_added.n = %d file aggiunti allo sketch. +editor.status.saving = Salvataggio... +editor.status.saving.done = Salvataggio eseguito. +editor.status.saving.canceled = Salvataggio annullato. +editor.status.printing = Stampa in corso... +editor.status.printing.done = Stampa eseguita. +editor.status.printing.error = Errore durante la stampa. +editor.status.printing.canceled = Stampa annullata. +editor.status.copy_as_html = Il codice formattato in HTML è stato copiato. +editor.status.debug.busy = Debugger occupato... +editor.status.debug.halt = Debugger bloccato. +editor.status.archiver.create = Creato archivio "%s". +editor.status.archiver.cancel = Archivio sketch annullato. + +# Errors +editor.status.warning = Avviso +editor.status.error = Errore +editor.status.error_on = Errore su "%s" +editor.status.missing.default = Manca "%c" +editor.status.missing.semicolon = Manca un punto e virgola ";" +editor.status.missing.left_sq_bracket = Manca parentesi quadra sinistra "[" +editor.status.missing.right_sq_bracket = Manca parentesi quadra destra "]" +editor.status.missing.left_paren = Manca parentesi sinistra "(" +editor.status.missing.right_paren = Manca parentesi destra ")" +editor.status.missing.left_curly_bracket = Manca parentesi graffa sinistra "{" +editor.status.missing.right_curly_bracket = Manca parentesi graffa destra "}" +editor.status.missing.add = Considera di aggiungere "%s" +editor.status.reserved_words = "color" e "int" sono parole riservate e non possono essere usate come nome di una variabile +editor.status.undefined_method = La funzione "%s(%s)" non esiste +editor.status.undefined_constructor = Il costruttore "%s(%s)" non esiste +editor.status.empty_param = La funzione "%s()" non richiede alcun parametro +editor.status.wrong_param = La funzione "%s()" si aspetta dei parametri come: "%s(%s)" +editor.status.undef_global_var = La variabile globale "%s" non esiste +editor.status.undef_class = La classe "%s" non esiste +editor.status.undef_var = La variabile "%s" non esiste +editor.status.undef_name = Il nome "%s" non può essere riconosciuto +editor.status.type_mismatch = Errore di battitura, "%s" non combacia con "%s" +editor.status.unused_variable = Il valore della variabile locale "%s" non è usato +editor.status.uninitialized_variable = La variabile locale "%s" potrebbe non essere stata inizializzata +editor.status.no_effect_assignment = L'assegnazione alla variabile "%s" non ha effetto +editor.status.hiding_enclosing_type = La classe "%s" non può avere lo stesso nome del tuo sketch o della classe che la contiene + +# Footer buttons +editor.footer.errors = Errori +editor.footer.errors.problem = Problemi +editor.footer.errors.tab = Tab +editor.footer.errors.line = Linea +editor.footer.console = Console + +# New handler +new.messages.is_read_only = Lo sketch è in modalità sola lettura. +new.messages.is_read_only.description = Alcuni files sono in sola lettura, quindi devi\nsalvare lo sketch in un'altra cartella,\ne provare di nuovo. + +# Rename handler +rename.messages.is_untitled = Sketch senza nome +rename.messages.is_untitled.description = Che ne dici di salvare lo sketch\nprima di provare a rinominarlo? +rename.messages.is_modified = Per favore salva lo sketch prima di rinominarlo. +rename.messages.is_read_only = Lo sketch è in modalità sola lettura. +rename.messages.is_read_only.description = Alcuni files sono in sola lettura, quindi devi\nsalvare lo sketch in un'altra cartella,\ne provare di nuovo. + +# Naming handler +name.messages.problem_renaming = Problema con nuovo nome +name.messages.starts_with_dot.description = Il nome non può iniziare con un punto. +name.messages.invalid_extension.description = ".%s" non è un'estensione valida. +name.messages.main_java_extension.description = La prima tab non può essere un file .%s.\n(Potrebbe essere il caso che tu passi a un\n"vero" ambiente di sviluppo.) +name.messages.new_sketch_exists = No +name.messages.new_sketch_exists.description = Un file chiamato "%s" esiste già in\n"%s" +name.messages.new_folder_exists = Impossibile rinominare +name.messages.new_folder_exists.description = Putroppo uno sketch (o cartella) chiamato "%s" esiste già. +name.messages.error = Errore +name.messages.no_rename_folder.description = Impossibile rinominare la cartella dello sketch. +name.messages.no_rename_file.description = Impossibile rinominare "%s" in "%s" +name.messages.no_create_file.description = Impossibile creare il file "%s"\nin "%s" + +# Delete handler +delete.messages.cannot_delete = Impossibile eliminare +delete.messages.cannot_delete.description = Non puoi eliminare uno sketch che non è stato salvato. +delete.messages.cannot_delete.file = Impossibile +delete.messages.cannot_delete.file.description = Impossibile eliminare +delete.messages.is_read_only = Lo sketch è in modalità sola lettura. +delete.messages.is_read_only.description = Alcuni files sono in sola lettura, quindi devi\nsalvare lo sketch in un'altra cartella,\ne provare di nuovo. + +# Save handler +save_file.messages.is_read_only = Lo sketch è in modalità sola lettura. +save_file.messages.is_read_only.description = Alcuni files sono in sola lettura, quindi devi\nsalvare questo sketch in un'altra cartella. +save_file.messages.sketch_exists = Impossibile salvare +save_file.messages.sketch_exists.description = Uno sketch con il nome\n“%s” esiste già. +save_file.messages.tab_exists = No +save_file.messages.tab_exists.description = Non puoi salvare lo sketch come "%s"\npoichè lo sketch ha già una tab con quel nome. +save_file.messages.recursive_save = Sei amico di Borges +save_file.messages.recursive_save.description = Non puoi salvare lo sketch in una cartella\ndentro se stessa: andrebbe avanti all'infinito. + +# Add handler +add_file.messages.is_read_only = Lo sketch è in modalità sola lettura. +add_file.messages.is_read_only.description = Alcuni files sono in sola lettura, quindi devi\nsalvare lo sketch in un'altra cartella,\ne provare di nuovo. +add_file.messages.confirm_replace = Sostituire l'esitente versione di %s? +add_file.messages.error_adding = Errore aggiungendo il file +add_file.messages.cannot_delete.description = Impossibile eliminare il corrente file '%s'. +add_file.messages.cannot_add.description = Impossibile aggiungere '%s' allo sketch. +add_file.messages.same_file = Non puoi fregarmi +add_file.messages.same_file.description = Questo file è già stato copiato nella\nquale tu stavic cercando di aggiugnerlo.\nNon lo farò. + +# Temp folder creator +temp_dir.messages.bad_build_folder = Errore nella compilazione della cartella +temp_dir.messages.bad_build_folder.description = Impossibile trovare una cartella dove compilare lo sketch. + +# Ensure Existance +ensure_exist.messages.missing_sketch = Sketch scomparso. +ensure_exist.messages.missing_sketch.description = Cartella dello sketch scomparsa.\nProverò a ri-salvarla nella stessa location,\nma qualsiasi cosa eccetto il codice verrà persa. +ensure_exist.messages.unrecoverable = Impossibile ri-salvare lo sketch. +ensure_exist.messages.unrecoverable.description = Impossibile ri-salvare correttamente lo sketch. Potresti incontrare qualche problema,\ne potrebbe essere l'ora di copiare e incollare il codice in un altro editor di testo. + +# Check name +check_name.messages.is_name_modified = Il nome dello sketch deve essere modificato. Il nome può consistere solo di\ncaratteri e numeri ASCII (ma non può cominciare con un numero).\nInoltre devono essere di lunghezza inferiore ai 64 caratteri. + +# --------------------------------------- +# Contributions + +# Contribution Panel +contrib = Manager dei Contributi +contrib.manager_title.update = Manager degli Aggiornamenti +contrib.manager_title.mode = Manager delle Modalità +contrib.manager_title.tool = Manager degli Strumenti +contrib.manager_title.library = Manager della Libreria +contrib.manager_title.examples = Manager degli esempi +contrib.category = Categoria: +contrib.filter_your_search = Filtra la tua ricerca... +contrib.show_only_compatible.mode = Mostra solo modalità compatibili +contrib.show_only_compatible.tool = Mostra solo strumenti compatibili +contrib.show_only_compatible.library = Mostra solo librerie compatibili +contrib.show_only_compatible.examples = Mostra solo esempi compatibili +contrib.show_only_compatible.update = Mostra solo aggiornamenti compatibili +contrib.restart = Riavvia Processing +contrib.unsaved_changes = Sono presenti modifiche non salvate +contrib.unsaved_changes.prompt = Sei sicuro di voler riavviare Processing senza salvare le modifiche? +contrib.messages.remove_restart = Per favore riavvia Processing per finire di rimuovere questo componente. +contrib.messages.install_restart = Per favore riavvia Processing per finire di installare questo componente. +contrib.messages.update_restart = Per favore riavvia Processing per finire di aggiornare questo componente. +contrib.errors.list_download = Impossibile scaricare la lista dei contributi disponibili. +contrib.errors.list_download.timeout = Connessione interrotta durante il download della lista dei contributi. +contrib.errors.download_and_install = Errore durante il download e l'installazione di %s. +contrib.errors.description_unavailable = Descrizione non disponibile. +contrib.errors.malformed_url = Il link ottenuto da Processing.org non è valido.\nPuoi comunque installare la libreria manualmente visitando\nil suo sito web. +contrib.errors.needs_repackage = %s necessita di ricreare il suo pacchetto secondo le %s lineeguida. +contrib.errors.no_contribution_found = Impossibile trovare un %s nel file scaricato. +contrib.errors.overwriting_properties = Errore sovrascrivendo il file .properties. +contrib.errors.install_failed = Installazione fallita +contrib.errors.update_on_restart_failed = L'aggiornamento al riavvio di %s è fallito. +contrib.errors.temporary_directory = Impossibile scrivere nella cartella temporanea. +contrib.errors.contrib_download.timeout = Connessione interrotta durante il download di %s. +contrib.errors.no_internet_connection = Sembra che tu non sia connesso a Internet. +contrib.status.downloading_list = Scaricando la lista dei contributi... +contrib.status.connecting = Connettendosi... +contrib.status.done = Fatto. +contrib.all = Tutti +contrib.undo = Annulla +contrib.remove = Rimuovi +contrib.install = Installa +contrib.progress.installing = Installando +contrib.progress.starting = Inizializzando +contrib.progress.downloading = Scaricando +contrib.download_error = Errore durante il download del contributo. +contrib.unsupported_operating_system = Il tuo sistema operativo sembra non essere supportato. Dovresti visitare %s della libreria per maggiori informazioni. +contrib.category.3d = 3D +contrib.category.animation = Animazione +contrib.category.data = Dati +contrib.category.geometry = Geometria +contrib.category.gui = GUI +contrib.category.hardware = Hardware +contrib.category.i_o = I/O +contrib.category.math = Matematica +contrib.category.simulation = Simulazione +contrib.category.sound = Suono +contrib.category.typography = Tipografia +contrib.category.utilities = Utilità +contrib.category.video_vision = Video & Grafica +contrib.category.other = Altro + +# Install on Startup +contrib.startup.errors.download_install = Errore durante il download e installazione di %s +contrib.startup.errors.temp_dir = Impossibile scrivere nella cartella temporanea durante il download e installazione di %s +contrib.startup.errors.new_marker = Il selezionatore dei contributi non aggiornato sembra non essere compatibile con %s. Dovresti installarlo manualmente per poterlo aggiornare... + +# Install on Import +contrib.import.dialog.title = Librerie mancanti disponibili +contrib.import.dialog.primary_text = Le seguenti librerie importate sono disponibili per il download, ma non sono state installate. +contrib.import.dialog.secondary_text = Vorresti installarle ora? +contrib.import.progress.download = Scaricando %s... +contrib.import.progress.install = Installando %s... +contrib.import.progress.done = %s è stato installato. +contrib.import.progress.final_list = LE seguenti librerie sono state installate: +contrib.import.errors.link = Errore: la libreria %s ha uno strano link di download. + +# --------------------------------------- +# Warnings + +warn.delete = Elimina +warn.delete.sketch = Sei sicuro di voler eliminare questo sketch? +warn.delete.file = Sei sicuro di voler eliminare "%s"? +warn.cannot_change_mode.title = Impossibile cambiare modalità +warn.cannot_change_mode.body = Impossibile cambiare modalità,\npoichè la modalità "%s" non è compatibile con quella corrente. + + +# --------------------------------------- +# Update Check + +update_check = Aggiorna +update_check.updates_available.core = Una nuova versione di Processing è disponibile,\nvuoi visitare la pagina di download del sito di Processing? +update_check.updates_available.contributions = Ci sono aggiornamenti disponibili per alcuni dei contributi installati,\nvorresti aprire il gestore dei contributi ora? + +# --------------------------------------- +# Color Chooser + +color_chooser = Selezionatore dei colori +color_chooser.select = Seleziona + +# --------------------------------------- +# Movie Maker + +movie_maker = Creatore di filmati +movie_maker.title = QuickTime Movie Maker +movie_maker.blurb = Questo strumento crea un filmato QuickTime a partire da una sequenza di immagini.

Per evitare artifatti causati dalla ri-compressone di immagini in video,
usa immagini TIFF, TGA (da Processing), o PNG come sorgenti.

Immagini TIFF e TGA verranno scritte più rapidamente, ma richiederanno più memoria:
saveFrame("frames/####.tif");
saveFrame("frames/####.tga");

Le immagini PNG sono più piccole, ma il tuo sketch verrà eseguito più lentamente:
saveFrame("frames/####.png");

This codice è basato su QuickTime Movie Maker 1.5.1 2011-01-17.
Copyright © 2010-2011 Werner Randelshofer. Tutti i diritti riservati
+movie_maker.image_folder_help_label = Trascina una cartella con immagini dentro il campo qui sotto: +movie_maker.choose_button = Scegli... +movie_maker.select_image_folder = Seleziona la cartella con le immagini... +movie_maker.sound_file_help_label = Trascina un file audio nel campo qui sotto (.au, .aiff, .wav, .mp3): +movie_maker.select_sound_file = Seleziona un file audio... + +movie_maker.create_movie_button = Crea filmato... +movie_maker.save_dialog_prompt = Salva filmato come... +movie_maker.width = Larghezza: +movie_maker.height = Altezza: +movie_maker.compression = Compressione: +movie_maker.compression.animation = Animazione +movie_maker.compression.jpeg = JPEG +movie_maker.compression.png = PNG +movie_maker.framerate = Fotogrammi al secondo: +movie_maker.orig_size_button = Stessa dimensione degli originali +movie_maker.orig_size_tooltip = Seleziona questa opzione se la cartalla contiene già fotogrammi della dimensione desiderata. + +movie_maker.error.avoid_tiff = Prova immagini TGA o PNG al posto di TIFF. +movie_maker.error.badnumbers = Larghezza e altezza devono essere numeri interi positivi; il numero di fotogrammi al secondo deve essere un numero positivo. +movie_maker.error.cannot_read = Impossibile leggere %s. +movie_maker.error.cannot_read_maybe_bad = Impossibile leggere %s; potrebbe non andare bene. +movie_maker.error.movie_failed = Creazione del filmato QuickTime fallita. +movie_maker.error.need_input = Dovresti specificare la cartella con i file delle immagini o dei suoni, o entrambe. +movie_maker.error.no_images_found = Nessun file immagine trovato. +movie_maker.error.sorry = Mi dispiace +movie_maker.error.unknown_tga_format = Sconosciuto formato di file .tga per %s. + +movie_maker.progress.creating_file_name = Creando %s. +movie_maker.progress.creating_output_file = Creando il file di output +movie_maker.progress.initializing = Inizializzando... +movie_maker.progress.processing = Processando %s. diff --git a/build/shared/lib/languages/PDE_ja.properties b/build/shared/lib/languages/PDE_ja.properties index bd59345f86..f0bc510298 100644 --- a/build/shared/lib/languages/PDE_ja.properties +++ b/build/shared/lib/languages/PDE_ja.properties @@ -40,8 +40,8 @@ menu.edit.paste = 貼り付け menu.edit.select_all = すべて選択 menu.edit.auto_format = 自動フォーマット menu.edit.comment_uncomment = コメント/アンコメント -menu.edit.increase_indent = インデントを増やす -menu.edit.decrease_indent = インデントを減らす +menu.edit.increase_indent = → インデントを増やす +menu.edit.decrease_indent = ← インデントを減らす menu.edit.find = 検索... menu.edit.find_next = 次を探す menu.edit.find_previous = 前を探す @@ -56,7 +56,7 @@ menu.sketch.stop = 停止 # --- menu.library = ライブラリをインポート... menu.library.add_library = ライブラリを追加... -menu.library.contributed = 貢献 +menu.library.contributed = Contributed menu.library.no_core_libraries = モードにコアライブラリがありません # --- menu.sketch = スケッチ @@ -158,7 +158,7 @@ close.unsaved_changes = %s への変更を保存しますか? # Preferences (Frame) preferences = 設定 preferences.button.width = 120 -preferences.requires_restart = Processing の再起動が必要です +preferences.requires_restart = Processingの再起動が必要です preferences.sketchbook_location = スケッチブックの場所 preferences.sketchbook_location.popup = スケッチブックの場所 preferences.language = 言語 @@ -166,6 +166,8 @@ preferences.editor_and_console_font = エディタとコンソールのフォン preferences.editor_and_console_font.tip = Select the font used in the Editor and the Console.
Only monospaced (fixed-width) fonts may be used,
though the list may be imperfect. preferences.editor_font_size = エディタフォントサイズ preferences.console_font_size = コンソールフォントサイズ +preferences.zoom = インターフェース拡大率 +preferences.zoom.auto = 自動 preferences.background_color = プレゼンテーションの背景色 preferences.background_color.tip = Select the background color used when using Present.
Present is used to present a sketch in full-screen,
accessible from the Sketch menu. preferences.use_smooth_text = エディタウィンドウでスムーズテキストを使う @@ -179,7 +181,7 @@ preferences.cmd_space = space preferences.suggest_imports = import 宣言をサジェストする preferences.increase_max_memory = 有効な最大メモリを増やす preferences.delete_previous_folder_on_export = エクスポート時に以前のフォルダーを削除する -preferences.check_for_updates_on_startup = 起動時にアップデートをチェックする +preferences.check_for_updates_on_startup = 起動時に更新をチェックする preferences.run_sketches_on_display = スケッチを実行するディスプレイ preferences.run_sketches_on_display.tip = スケッチが最初に置かれるディスプレイをセットして下さい。
通常、スケッチウィンドウを動かすと、同じ位置に再び開かれますが、
プレゼンテーション(フルスクリーン)モードで実行している場合、
このディスプレイが常に使用されます。 preferences.automatically_associate_pde_files = 自動的に .pde ファイルを Processing に関連付ける @@ -255,7 +257,7 @@ create_font.character_selector = 文字選択 create_font.character_selector.label = Default characters will include most bitmaps for Mac OS\nand Windows Latin scripts. Including all characters may\nrequire large amounts of memory for all of the bitmaps.\nFor greater control, you can select specific Unicode blocks. create_font.default_characters = デフォルトの文字 create_font.all_characters = すべての文字 -create_font.specific_unicode = Specific Unicode Blocks +create_font.specific_unicode = 特定のUnicodeブロック create_font.filename = ファイル名 # Color Selector (Frame) @@ -312,6 +314,7 @@ editor.header.delete.warning.title = いや、うん。 editor.header.delete.warning.text = 開いただけのスケッチのメインタブは削除できません。 # PopUp menu +editor.popup.jump_to_declaration = 宣言に移動 editor.popup.show_usage = 用法の表示... editor.popup.rename = 名前の変更... @@ -327,10 +330,10 @@ editor.sketch.rename.description = スケッチの新しい名前 editor.status.autoformat.no_changes = No changes necessary for Auto Format. editor.status.autoformat.finished = 自動フォーマットが完了しました。 editor.status.find_reference.select_word_first = First select a word to find in the reference. -editor.status.find_reference.not_available = No reference available for "%s". -editor.status.drag_and_drop.files_added.0 = No files were added to the sketch. -editor.status.drag_and_drop.files_added.1 = One file added to the sketch. -editor.status.drag_and_drop.files_added.n = %d files added to the sketch. +editor.status.find_reference.not_available = "%s" のリファレンスは利用できません。 +editor.status.drag_and_drop.files_added.0 = スケッチに追加されたファイルはありませんでした。 +editor.status.drag_and_drop.files_added.1 = 1 個のファイルがスケッチに追加されました。 +editor.status.drag_and_drop.files_added.n = %d 個のファイルがスケッチに追加されました。 editor.status.saving = 保存しています... editor.status.saving.done = 保存が完了しました。 editor.status.saving.canceled = 保存がキャンセルされました。 @@ -338,7 +341,7 @@ editor.status.printing = 印刷しています... editor.status.printing.done = 印刷が完了しました。 editor.status.printing.error = 印刷中にエラーが発生しました。 editor.status.printing.canceled = 印刷がキャンセルされました。 -editor.status.copy_as_html = Code formatted as HTML has been copied to the clipboard. +editor.status.copy_as_html = HTMLとしてフォーマットされたコードがクリップボードにコピーされました。 editor.status.debug.busy = Debugger busy... editor.status.debug.halt = Debugger halted. editor.status.archiver.create = アーカイブ "%s" を作成しました。 @@ -356,10 +359,10 @@ editor.status.missing.left_paren = Missing left parenthesis "(" editor.status.missing.right_paren = Missing right parenthesis ")" editor.status.missing.left_curly_bracket = Missing left curly bracket "{" editor.status.missing.right_curly_bracket = Missing right curly bracket "}" -editor.status.missing.add = Consider adding "%s" +editor.status.missing.add = "%s" の追加を考えてください editor.status.reserved_words = "color" and "int" are reserved words & cannot be used as variable names editor.status.undefined_method = 関数 "%s(%s)" は存在しません -editor.status.undefined_constructor = The constructor "%s(%s)" does not exist +editor.status.undefined_constructor = コンストラクター "%s(%s)" は存在しません editor.status.empty_param = The function "%s()" does not expect any parameters editor.status.wrong_param = The function "%s()" expects parameters like: "%s(%s)" editor.status.undef_global_var = グローバル変数 "%s" は存在しません @@ -367,7 +370,7 @@ editor.status.undef_class = クラス "%s" は存在しません editor.status.undef_var = 変数 "%s" は存在しません editor.status.undef_name = The name "%s" cannot be recognized editor.status.type_mismatch = Type mismatch, "%s" does not match with "%s" -editor.status.unused_variable = The value of the local variable "%s" is not used +editor.status.unused_variable = ローカル変数 "%s" の値は使われていません editor.status.uninitialized_variable = The local variable "%s" may not have been initialized editor.status.no_effect_assignment = The assignment to variable "%s" has no effect @@ -399,13 +402,13 @@ name.messages.new_sketch_exists.description = A file named "%s" already exists a name.messages.new_folder_exists = 名前を変更できません name.messages.new_folder_exists.description = Sorry, a sketch (or folder) named "%s" already exists. name.messages.error = エラー -name.messages.no_rename_folder.description = Could not rename the sketch folder. +name.messages.no_rename_folder.description = スケッチフォルダー名を変更できませんでした。 name.messages.no_rename_file.description = Could not rename "%s" to "%s" name.messages.no_create_file.description = Could not create the file "%s"\nin "%s" # Delete handler delete.messages.cannot_delete = 削除できません -delete.messages.cannot_delete.description = You cannot delete a sketch that has not been saved. +delete.messages.cannot_delete.description = 保存されていないスケッチを削除することはできません。 delete.messages.cannot_delete.file = Could not do it delete.messages.cannot_delete.file.description = 削除できませんでした delete.messages.is_read_only = スケッチが読込み専用です @@ -475,21 +478,21 @@ contrib.errors.malformed_url = The link fetched from Processing.org is not valid contrib.errors.needs_repackage = %s needs to be repackaged according to the %s guidelines. contrib.errors.no_contribution_found = Could not find a %s in the downloaded file. contrib.errors.overwriting_properties = Error overwriting .properties file. -contrib.errors.install_failed = Install failed. +contrib.errors.install_failed = インストールに失敗しました。 contrib.errors.update_on_restart_failed = Update on restart of %s failed. -contrib.errors.temporary_directory = Could not write to temporary directory. -contrib.errors.contrib_download.timeout = Connection timed out while downloading %s. -contrib.errors.no_internet_connection = You do not seem to be connected to the Internet. +contrib.errors.temporary_directory = 一時ディレクトリに書き込めませんでした。 +contrib.errors.contrib_download.timeout = %sをダウンロード中に接続がタイムアウトしました。 +contrib.errors.no_internet_connection = インターネットに接続されていないようです。 contrib.status.downloading_list = Downloading contribution list... -contrib.status.connecting = Connecting... +contrib.status.connecting = 接続しています... contrib.status.done = Done. -#contrib.all = すぺて -#contrib.undo = 元に戻す -#contrib.remove = 削除 -#contrib.install = インストール -contrib.progress.installing = Installing -contrib.progress.starting = Starting -contrib.progress.downloading = Downloading +contrib.all = すべて +contrib.undo = 元に戻す +contrib.remove = 削除 +contrib.install = インストール +contrib.progress.installing = インストール中 +contrib.progress.starting = 開始中 +contrib.progress.downloading = ダウンロード中 contrib.download_error = An error occured while downloading the contribution. contrib.unsupported_operating_system = Your operating system does not appear to be supported. You should visit the %s\'s library for more info. contrib.category.3d = 3D @@ -516,18 +519,18 @@ contrib.startup.errors.new_marker = The unupdated contribution marker seems to n contrib.import.dialog.title = Missing Libraries Available contrib.import.dialog.primary_text = The following imported libraries are available for download, but have not been installed. contrib.import.dialog.secondary_text = Would you like to install them now? -contrib.import.progress.download = Downloading %s... -contrib.import.progress.install = Installing %s... -contrib.import.progress.done = %s has been installed. +contrib.import.progress.download = %sをダウンロードしています... +contrib.import.progress.install = %sをインストールしています... +contrib.import.progress.done = %sがインストールされました。 contrib.import.progress.final_list = The following libraries have been installed: contrib.import.errors.link = Error: The library %s has a strange looking download link. # --------------------------------------- # Warnings -warn.delete = Delete -warn.delete.sketch = Are you sure you want to delete this sketch? -warn.delete.file = Are you sure you want to delete "%s"? +warn.delete = 削除 +warn.delete.sketch = このスケッチを削除してもよろしいですか? +warn.delete.file = "%s"を削除してもよろしいですか? warn.cannot_change_mode.title = モード変更失敗 warn.cannot_change_mode.body = 互換性がないため、"%s"モードに切り替えられません。 @@ -535,16 +538,16 @@ warn.cannot_change_mode.body = 互換性がないため、"%s"モードに切り # --------------------------------------- # Update Check -update_check = Update -update_check.updates_available.core = A new version of Processing is available,\nwould you like to visit the Processing download page? +update_check = 更新 +update_check.updates_available.core = 新しいバージョンのProcessingが利用可能です。\nProcessingのダウンロードページにアクセスしますか? update_check.updates_available.contributions = There are updates available for some of the installed contributions,\nwould you like to open the the Contribution Manager now? # --------------------------------------- # Color Chooser -color_chooser = Color Selector -color_chooser.select = Select +color_chooser = カラーセレクター +color_chooser.select = 選択 # --------------------------------------- # Movie Maker @@ -554,20 +557,20 @@ movie_maker.title = QuickTime ムービーメーカー movie_maker.blurb = This tool creates a QuickTime movie from a sequence of images.

To avoid artifacts caused by re-compressing images as video,
use TIFF, TGA (from Processing), or PNG images as the source.

TIFF and TGA images will write more quickly, but require more disk:
saveFrame("frames/####.tif");
saveFrame("frames/####.tga");

PNG images are smaller, but your sketch will run more slowly:
saveFrame("frames/####.png");

This code is based on QuickTime Movie Maker 1.5.1 2011-01-17.
Copyright © 2010-2011 Werner Randelshofer. All rights reserved.
movie_maker.image_folder_help_label = Drag a folder with image files into the field below: movie_maker.choose_button = 選択... -movie_maker.select_image_folder = Select image folder... +movie_maker.select_image_folder = 画像フォルダーを選択... movie_maker.sound_file_help_label = Drag a sound file into the field below (.au, .aiff, .wav, .mp3): -movie_maker.select_sound_file = Select sound file... +movie_maker.select_sound_file = 音声ファイルを選択... -movie_maker.create_movie_button = Create movie... +movie_maker.create_movie_button = 動画を作成... movie_maker.save_dialog_prompt = Save movie as... movie_maker.width = 幅: movie_maker.height = 高さ: -movie_maker.compression = Compression: +movie_maker.compression = 圧縮: movie_maker.compression.animation = Animation movie_maker.compression.jpeg = JPEG movie_maker.compression.png = PNG -movie_maker.framerate = Framerate: -movie_maker.orig_size_button = Same size as originals +movie_maker.framerate = フレームレート: +movie_maker.orig_size_button = オリジナルと同じサイズ movie_maker.orig_size_tooltip = Check this box if the folder contains already encoded video frames in the desired size. movie_maker.error.avoid_tiff = Try TGA or PNG images instead of TIFF. diff --git a/build/shared/lib/languages/PDE_ko.properties b/build/shared/lib/languages/PDE_ko.properties index 9043303ec4..e60e088be7 100644 --- a/build/shared/lib/languages/PDE_ko.properties +++ b/build/shared/lib/languages/PDE_ko.properties @@ -15,7 +15,7 @@ menu.file.new = 새 스케치 menu.file.open = 열기... menu.file.recent = 최근 스케치 menu.file.sketchbook = 스케치북 -menu.file.sketchbook.empty = 빈 스케치북 +menu.file.sketchbook.empty = 빈 스케치북 menu.file.examples = 예제... menu.file.close = 닫기 menu.file.save = 저장 @@ -38,8 +38,8 @@ menu.edit.paste = 붙이기 menu.edit.select_all = 전체선택 menu.edit.auto_format = 자동 정렬 menu.edit.comment_uncomment = 주석 처리/해제 -menu.edit.increase_indent = 들여쓰기 -menu.edit.decrease_indent = 내어쓰기 +menu.edit.increase_indent = → 들여쓰기 +menu.edit.decrease_indent = ← 내어쓰기 menu.edit.find = 찾기... menu.edit.find_next = 다음 찾기 menu.edit.find_previous = 이전 찾기 @@ -49,8 +49,8 @@ menu.edit.use_selection_for_find = 선택영역으로 찾기 # | Sketch | menu.sketch.run = 실행하기 menu.sketch.present = 전체화면 보기 -menu.sketch.tweak = 변수 조정하기 -menu.sketch.stop = 정지하기 +menu.sketch.tweak = 변수 조정하기 +menu.sketch.stop = 정지하기 # --- menu.library = 내부 라이브러리... menu.library.add_library = 라이브러리 추가하기... @@ -127,7 +127,7 @@ preferences.requires_restart = 프로세싱 재실행 시 적용 preferences.sketchbook_location = 스케치 폴더 위치 preferences.sketchbook_location.popup = 스케치 폴더 위치 preferences.language = 언어 -preferences.editor_and_console_font = 스케치 에디터와 콘솔 글꼴 선택 +preferences.editor_and_console_font = 스케치 에디터와 콘솔 글꼴 선택 preferences.editor_and_console_font.tip = \ 에디터와 콘솔에서 사용할 폰트 선택하기.
\ Monospaced (fixed-width) 폰트만 리스트에 나타나며,
\ @@ -153,7 +153,7 @@ preferences.check_for_updates_on_startup = 프로그램 시작 시 버전 업데 preferences.run_sketches_on_display = 실행 시 스케치창 디스플레이의 장치 설정 preferences.run_sketches_on_display.tip = \ 멀티스크린 사용 시 실행된 스케치 창을 보여줄 스크린 선택하기.
\ -일반적으로, 스케치 창을 커서로 드래그하여 이동하면 재 실행 시에는 해당 스크린에서 실행되지만
\ +일반적으로, 스케치 창을 커서로 드래그하여 이동하면 재 실행 시에는 해당 스크린에서 실행되지만
\ 전체화면 모드로 실행하는 경우에 설정된 스크린에서만 실행됩니다. preferences.automatically_associate_pde_files = .pde 파일 실행 시 프로세싱으로 자동 연결 preferences.launch_programs_in = 프로그램 실행 @@ -237,13 +237,13 @@ editor.header.delete.warning.title = Yeah, no. editor.header.delete.warning.text = 스케치의 마지막 탭은 삭제할 수 없습니다. # Tabs -editor.tab.new = 새 탭 이름 -editor.tab.new.description = 파일의 새 탭 이름 -editor.tab.rename = 새 탭 이름 -editor.tab.rename.description = 파일의 새 탭 이름 +editor.tab.new = 새 탭 이름 +editor.tab.new.description = 파일의 새 탭 이름 +editor.tab.rename = 새 탭 이름 +editor.tab.rename.description = 파일의 새 탭 이름 # Sketch -editor.sketch.rename.description = 새 스케치 이름 +editor.sketch.rename.description = 새 스케치 이름 editor.status.autoformat.no_changes = 변경할 서식이 없습니다. editor.status.autoformat.finished = 자동 서식 적용 완료 @@ -264,10 +264,10 @@ editor.status.printing.canceled = 인쇄 취소. # --------------------------------------- # Contribution Panel -contrib = 컨트리뷰션 매니저 +contrib = 컨트리뷰션 매니저 contrib.category = 카테고리: contrib.filter_your_search = 검색 필터... -contrib.restart = 프로세싱 다시 시작하기 +contrib.restart = 프로세싱 다시 시작하기 contrib.unsaved_changes = 저장되지 않은 변경 사항이 발견되었습니다. contrib.unsaved_changes.prompt = 정말 변경 사항을 저장하지 않고 프로세싱을 다시 시작하시겠습니까? contrib.messages.remove_restart = 해당 아이템이 완전히 삭제된 후 프로세싱을 다시 시작해 주세요. @@ -282,13 +282,13 @@ contrib.errors.needs_repackage = %s 라이브러리는 해당 프로세싱 버 contrib.errors.no_contribution_found = %s 파일을 다운로드 경로에서 찾을 수 없습니다. contrib.errors.overwriting_properties = .properties 파일 덮어쓰기에 실패하였습니다. contrib.errors.install_failed = 설치 오류 발생. -contrib.errors.update_on_restart_failed = %s 파일은 알 수 없는 오류로 재실행 후에도 사용할 수 없습니다. +contrib.errors.update_on_restart_failed = %s 파일은 알 수 없는 오류로 재실행 후에도 사용할 수 없습니다. contrib.errors.temporary_directory = 임시 디렉터리에 업데이트할 수 없습니다. contrib.all = All contrib.undo = 입력 취소 contrib.remove = 삭제 contrib.install = 설치 -contrib.progress.installing = 설치 중 +contrib.progress.installing = 설치 중 contrib.progress.starting = 시작 중 contrib.progress.downloading = 다운로드 중 contrib.download_error = 해당 파일 다운로드 중 에러 발생하였습니다. @@ -297,18 +297,18 @@ contrib.unsupported_operating_system = 해당 파일 해당 컴퓨터의 운영 # --------------------------------------- # Warnings -warn.delete = 삭제 +warn.delete = 삭제 warn.delete.sketch = 정말 해당 스케치를 삭제하시겠습니까? warn.delete.file = 정말 "%s"를 삭제하시겠습니까? # --------------------------------------- # Update Check -update_check = 업데이트 +update_check = 업데이트 update_check.updates_available.core = 새 버전의 프로세싱 설치가 가능합니다. \n해당 다운로드 페이지로 지금 이동하시겠습니까? update_check.updates_available.contributions = 설치된 컨트리뷰션(도구, 라이브러리, 모드, 예제) 중 일부가 업데이트되었습니다,\n 컨트리뷰션 매니저로 이동하여 확인하시겠습니까? # --------------------------------------- # Color Chooser -color_chooser = 색상 선택 \ No newline at end of file +color_chooser = 색상 선택 \ No newline at end of file diff --git a/build/shared/lib/languages/PDE_nl.properties b/build/shared/lib/languages/PDE_nl.properties index fb2634241a..ee753069f1 100644 --- a/build/shared/lib/languages/PDE_nl.properties +++ b/build/shared/lib/languages/PDE_nl.properties @@ -38,8 +38,8 @@ menu.edit.paste = Plakken menu.edit.select_all = Alles Selecteren menu.edit.auto_format = Automatische Opmaak menu.edit.comment_uncomment = Commentaar Aan/Uit -menu.edit.increase_indent = Inspringen Vergroten -menu.edit.decrease_indent = Inspringen Verkleinen +menu.edit.increase_indent = → Inspringen Vergroten +menu.edit.decrease_indent = ← Inspringen Verkleinen menu.edit.find = Zoeken... menu.edit.find_next = Volgende Zoeken menu.edit.find_previous = Vorige Zoeken diff --git a/build/shared/lib/languages/PDE_pt.properties b/build/shared/lib/languages/PDE_pt.properties index 7842a71830..e8f34420af 100644 --- a/build/shared/lib/languages/PDE_pt.properties +++ b/build/shared/lib/languages/PDE_pt.properties @@ -37,8 +37,8 @@ menu.edit.paste = Colar menu.edit.select_all = Seleccionar Tudo menu.edit.auto_format = Auto Formatar menu.edit.comment_uncomment = Comentar/Descomentar -menu.edit.increase_indent = Aumentar Indentação -menu.edit.decrease_indent = Diminuir Indentação +menu.edit.increase_indent = → Aumentar Indentação +menu.edit.decrease_indent = ← Diminuir Indentação menu.edit.find = Procurar... menu.edit.find_next = Procurar Seguinte menu.edit.find_previous = Procurar Anterior @@ -67,7 +67,7 @@ menu.sketch.add_file = Adicionar Ficheiro... # | File | Edit | Sketch | Debug | Tools | Help | # | Tools | menu.tools = Ferramentas -menu.tools.color_selector = Selector de Côr... +menu.tools.color_selector = Selector de Cor... menu.tools.create_font = Criar Fonte... menu.tools.archive_sketch = Arquivar Sketch menu.tools.fix_the_serial_lbrary = Corrijir a Biblioteca Serial @@ -204,7 +204,7 @@ toolbar.stop = Parar # --- toolbar.new = Novo toolbar.open = Abrir -toolbar.save = Guardr +toolbar.save = Guardar # toolbar.export_application = Exportar Aplicação toolbar.add_mode = Adicionar modo... @@ -218,14 +218,14 @@ editor.header.rename = Renomear editor.header.delete = Apagar editor.header.previous_tab = Aba Anterior editor.header.next_tab = Aba Seguinte -editor.header.delete.warning.title = Yah, não. -editor.header.delete.warning.text = Não pode apagar a última aba do último sketch aberto. +editor.header.delete.warning.title = Ah, não. +editor.header.delete.warning.text = Não se pode apagar a última aba do último sketch aberto. editor.status.autoformat.no_changes = Não foram necessárias alterações para a Auto Formatação. editor.status.autoformat.finished = Auto Formatação completa. editor.status.find_reference.select_word_first = Primeiro escolha uma palavra para procurar na referência. editor.status.find_reference.not_available = Não existe refrência disponivel para "%s". -editor.status.drag_and_drop.files_added.0 = Nenhuns ficheiros foram adicionados ao sketch. +editor.status.drag_and_drop.files_added.0 = Nenhum dos ficheiros foram adicionados ao sketch. editor.status.drag_and_drop.files_added.1 = Um ficheiro adicionado ao sketch. editor.status.drag_and_drop.files_added.n = %d ficheiros adicionados ao sketch. editor.status.saving = A Guardar... @@ -247,5 +247,5 @@ contrib.remove = Refazer contrib.install = Instalar contrib.progress.starting = A iniciar contrib.progress.downloading = A descarregar -contrib.download_error = Ocorreu um erro a descarregar a contribuição. +contrib.download_error = Ocorreu um erro ao descarregar a contribuição. contrib.unsupported_operating_system = O seu sistema operativo não parece ser suportado. Deve visitar a biblioteca %s para mais informação. diff --git a/build/shared/lib/languages/PDE_ru.properties b/build/shared/lib/languages/PDE_ru.properties new file mode 100644 index 0000000000..4995272df2 --- /dev/null +++ b/build/shared/lib/languages/PDE_ru.properties @@ -0,0 +1,604 @@ + + +# --------------------------------------- +# Language: Russian (Русский) (ru) +# --------------------------------------- + + +# --------------------------------------- +# Menu + +# | File | Edit | Sketch | Debug | Tools | Help | +# | File | +menu.file = Файл +menu.file.new = Создать +menu.file.open = Открыть... +menu.file.recent = Недавние +menu.file.sketchbook = Рабочая папка... +menu.file.sketchbook.empty = Пустая рабочая папка +menu.file.examples = Примеры... +menu.file.close = Закрыть +menu.file.save = Сохранить +menu.file.save_as = Сохранить как... +menu.file.export_application = Экспорт приложения... +menu.file.page_setup = Настройка страницы +menu.file.print = Печать... +menu.file.preferences = Параметры... +menu.file.quit = Выход + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Edit | +menu.edit = Правка +menu.edit.undo = Отменить +menu.edit.redo = Повторить +menu.edit.action.addition = добавление +menu.edit.action.deletion = удаление +menu.edit.cut = Вырезать +menu.edit.copy = Копировать +menu.edit.copy_as_html = Скопировать как HTML +menu.edit.paste = Вставить +menu.edit.select_all = Выделить всё +menu.edit.auto_format = Автоформатирование +menu.edit.comment_uncomment = Закомментировать/Раскомментировать +menu.edit.increase_indent = → Увеличить отступ +menu.edit.decrease_indent = ← Уменьшить отступ +menu.edit.find = Найти... +menu.edit.find_next = Найти следущее +menu.edit.find_previous = Найти предыдущее +menu.edit.use_selection_for_find = Найти выделенное + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Sketch | +menu.sketch.run = Запустить +menu.sketch.present = Режим презентации +menu.sketch.tweak = Изменить +menu.sketch.stop = Остановить +# --- +menu.library = Импортировать библиотеку... +menu.library.add_library = Добавить библиотеку... +menu.library.contributed = Вклад сообщества +menu.library.no_core_libraries = отсутствуют основные библиотеки +# --- +menu.sketch = Набросок +menu.sketch.show_sketch_folder = Показать папку с набросками +menu.sketch.add_file = Добавить файл... + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Debug | +menu.debug = Отладка +menu.debug.enable = Включить отладку +menu.debug.disable = Отключить отладку +#menu.debug.show_debug_toolbar = Показать панель отладки +#menu.debug.debug = Начать отладку +#menu.debug.stop = Остановить отладку +# --- +menu.debug.toggle_breakpoint = Поставить/снять точку останова +#menu.debug.list_breakpoints = Список точек останова +# --- +# used for both menus and toolbars +menu.debug.step = Шаг +menu.debug.step_into = Зайти в +menu.debug.step_out = Выйти из +menu.debug.continue = Продолжить +# --- +#menu.debug.print_stack_trace = Печать стека вызовов +#menu.debug.print_locals = Печать локальных переменных +#menu.debug.print_fields = Печать полей +#menu.debug.print_source_location = Печатать расположение источника +#menu.debug.print_threads = Друкувати потоки +# --- +#menu.debug.variable_inspector = Инспектор переменных +menu.debug.show_variables = Показать переменные +menu.debug.hide_variables = Спрятать переменные +#menu.debug.show_sketch_outline = Показать рамку наброска +#menu.debug.show_tabs_list = Показать список вкладок + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Tools | +menu.tools = Инструменты +menu.tools.color_selector = Выбрать цвет... +menu.tools.create_font = Создать шрифты... +menu.tools.archive_sketch = Архивировать набросок +menu.tools.fix_the_serial_lbrary = Исправить библиотеку Serial +menu.tools.install_processing_java = Установить "processing-java" +menu.tools.add_tool = Добавить инструмент... + +# | File | Edit | Sketch | Debug | Tools | Help | +# | Help | +menu.help = Помощь +menu.help.welcome = Добро пожаловать в Processing 3 +menu.help.about = О Processing +menu.help.environment = Среда +menu.help.reference = Документация +menu.help.find_in_reference = Найти в документации +menu.help.libraries_reference = Документация библиотек +menu.help.tools_reference = Документация инструментов +menu.help.empty = (пусто) +menu.help.online = Онлайн +menu.help.getting_started = Начало работы (англ.) +menu.help.getting_started.url = http://processing.org/learning/gettingstarted/ +menu.help.troubleshooting = Решение проблем (англ.) +menu.help.troubleshooting.url = http://wiki.processing.org/w/Troubleshooting +menu.help.faq = Часто задаваемые вопросы (англ.) +menu.help.faq.url = http://wiki.processing.org/w/FAQ +menu.help.foundation = The Processing Foundation (англ.) +menu.help.foundation.url = http://processing.org/foundation/ +menu.help.visit = Постетить Processing.org (англ.) +menu.help.visit.url = http://processing.org/ + + +# --------------------------------------- +# Basics + +# Buttons +prompt.yes = Да +prompt.no = Нет +prompt.cancel = Отменить +prompt.ok = ОК +prompt.browse = Просмотр +prompt.export = Экспорт + + +# --------------------------------------- +# Frames + +# Open (Frame) +open = Открыть в Processing... + +# Save (Frame) +save = Сохранить папку как... +save.title = Сохранить изменения %s
перед закрытием? +save.hint = Несохранённые изменения будут потеряны. +save.btn.save = Сохранить +save.btn.dont_save = Не сохранять + +# Close (Frame) also used to prompt on non-OS X machines +close.unsaved_changes = Сохранить изменения в %s? + +# Preferences (Frame) +preferences = Параметры +preferences.button.width = 95 +preferences.requires_restart = требуется перезапуск Processing +preferences.sketchbook_location = Расположение рабочей папки +preferences.sketchbook_location.popup = Расположение рабочей папки +preferences.language = Язык +preferences.editor_and_console_font = Шрифт редактора и консоли +preferences.editor_and_console_font.tip = Выбрать шрифт для использовании в редакторе и консоли.
Возможно использование только моноширинных шрифтов. +preferences.editor_font_size = Размер шрифта редактора +preferences.console_font_size = Размер шрифта консоли +preferences.zoom = Масштабирование интерфейса +preferences.zoom.auto = По умолчанию +preferences.background_color = Цвет фона в режиме презентации +preferences.background_color.tip = Выбрать фоновый цвет для режима презентации.
Режим презентации используется для полноэкранного просмотра
из меню набросок. +preferences.use_smooth_text = Рисовать сглаженный текст в окне редактора +preferences.enable_complex_text_input = Включить расширенное редактирование текста +preferences.enable_complex_text_input_example = напр. японский +preferences.continuously_check = Проверять на ошибки +preferences.show_warnings = Показать предупреждения +preferences.code_completion = Автодополнение кода +preferences.trigger_with = Запуск с помощью +preferences.cmd_space = Пробел +preferences.suggest_imports = Предлагать импорт +preferences.increase_max_memory = Увеличить лимит памяти для наброска +preferences.delete_previous_folder_on_export = Удалять предыдущую папку при экспорте +preferences.check_for_updates_on_startup = Разрешать проверку обновлений (см. ЧаВо для получения информации о используемых данных) +preferences.run_sketches_on_display = Запускать набросок на мониторе +preferences.run_sketches_on_display.tip = Задаёт монитор, на котором будут запускаться наброски.
Обычно, если окно перемещается, то оно будет перезапущено
на том месте, тем не менее при запуске в полноэкранном режиме
всегда используется выбранный монитор. +preferences.automatically_associate_pde_files = Автоматически ассоциировать файлы .pde с Processing +preferences.launch_programs_in = Запускать программы в +preferences.launch_programs_in.mode = Режим +preferences.file = В файле настроек можно найти больше параметров для настройки +preferences.file.hint = не редактируйте его при запущенном Processing + +# Sketchbook Location (Frame) +sketchbook_location = Выбрать новое раположение рабочей папки + +# Sketchbook (Frame) +sketchbook = Рабочая папка +sketchbook.tree = Рабочая папка + +# Examples (Frame) +examples.title = Примеры %s +examples.add_examples = Добавить... +examples.libraries = Библиотеки сообщества +examples.core_libraries = Библиотеки +examples.contributed = Примеры сообщества + +# Export (Frame) +export = Настройка экспорта +export.platforms = Платформы +export.options = Настройки +export.options.present = Режим презентации +export.options.show_stop_button = Показывать кнопку остановки +export.description.line1 = "Экспорт в приложение" создаёт интерактивное, +export.description.line2 = самостоятельное приложение для выбранных платформ. +export.unsaved_changes = Сохранить изменения перед экспортом? +export.notice.cancel.unsaved_changes = Экспорт отменён, сохраните сперва сделанные изменения. +export.notice.exporting = Экспорт приложения... +export.notice.exporting.done = Экспорт завершён. +export.notice.exporting.error = Ошибка при экспорте. +export.notice.exporting.cancel = Экспорт в приложение отменён. +export.tooltip.macosx = Экспорт для Mac OS X доступен только на Mac OS X +export.full_screen = Во весь экран +export.embed_java = Встроенная Java +export.embed_java.for = Встроить Java для +export.code_signing = Цифровая подпись +export.messages.is_read_only = Скетч доступен только для чтения +export.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nНужно сперва сохранить их в другом месте\nа затем попробовать заново. +export.messages.cannot_export = Экспорт невозможен +export.messages.cannot_export.description = Нельзя экспортировать несохранённый набросок. + +# Find (Frame) +find = Поиск +find.find = Найти: +find.replace_with = Заменить на: +find.ignore_case = Игнорировать регистр +find.all_tabs = Во всех вкладках +find.wrap_around = По всему документу +find.btn.replace_all = Заменить всё +find.btn.replace = Заменить +find.btn.replace_and_find = Найти и заменить +find.btn.previous = Предыдущий +find.btn.find = Найти + +# Find in reference (Frame) +find_in_reference = Найти в документации + +# File (Frame) +file = Выбрать + +# Create Font (Frame) +create_font = Создать шрифт +create_font.label = Этот инструмент предназначен для создания пользовательских шрифтов.\nВыберите шрифт, его размер и нажмите "ОК", для создания шрифта.\nОн будет сохранён в папке с наброском. +create_font.size = Размер +create_font.smooth = Сглаживание +create_font.characters = Символы... +create_font.character_selector = Выбор символа +create_font.character_selector.label = В стандартные набор символов включены bitmap-ы для Mac OS\nи Windows Latin. Включение всех символов увеличивает потребление памяти.\nДля улучшения ситуации подключайте необходимые блоки Unicode. +create_font.default_characters = Стандартные символы +create_font.all_characters = Все символы +create_font.specific_unicode = Определённые блоки Unicode +create_font.filename = Имя файла + +# Color Selector (Frame) +color_selector = Выбрать цвет + +# Archive Sketch (Frame) +archive_sketch = Архивировать скетч в... + +# Tweak Mode +tweak_mode = Режим редактирования +tweak_mode.save_before_tweak = Сохраните набросок перед переходом в режим редактирования. +tweak_mode.keep_changes.line1 = Сохранить изменения? +tweak_mode.keep_changes.line2 = Вы изменили настройки наброска. Желаете сохранить? + +# DebugTray +debugger.name = Имя +debugger.value = Значения +debugger.type = Тип + +# --------------------------------------- +# Toolbars + +# [Run/Present] [Stop] [New] [Open] [Save] +toolbar.run = Запустить +toolbar.present = Показать +toolbar.stop = Остановить +toolbar.debug = Отладить +# --- +toolbar.new = Новый +toolbar.open = Открыть +toolbar.save = Сохранить +# toolbar.export_application = Экспорт приложения +toolbar.add_mode = Добавить режим... + +# [Debug] [Continue] [Step] [Stop] [Toggle Breakpoints] [Variable Inspector] +#toolbar.debug.continue = Продолжить +#toolbar.debug.step = Шаг +#toolbar.debug.step_into = Зайти в +#toolbar.debug.stop = Остановить +#toolbar.debug.toggle_breakpoints = Поставить/Убрать точку останова +#toolbar.debug.variable_inspector = Экран переменных + + +# --------------------------------------- +# Editor + +# [Tab1] [Tab2] [v] +editor.header.new_tab = Новая вкладка +editor.header.rename = Переименовать +editor.header.delete = Удалить +editor.header.previous_tab = Предыдущая вкладка +editor.header.next_tab = Следующая вкладка +editor.header.delete.warning.title = Да, нет. +editor.header.delete.warning.text = Нельзя удалить основную вкладку открытого наброска. + +# PopUp menu +editor.popup.jump_to_declaration = Перейти к определению +editor.popup.show_usage = Найти использование... +editor.popup.rename = Переименовать... + +# Tabs +editor.tab.new = Новое имя +editor.tab.new.description = Имя нового файла +editor.tab.rename = Новое имя +editor.tab.rename.description = Новое имя файла + +# Sketch +editor.sketch.rename.description = Имя нового наброска + +editor.status.autoformat.no_changes = Автоформатирования не требуется. +editor.status.autoformat.finished = Автоформатирование завершено. +editor.status.find_reference.select_word_first = Сначала выделите слово для поиска в документации. +editor.status.find_reference.not_available = Документация для "%s" недоступна. +editor.status.drag_and_drop.files_added.0 = В скетч не добавлено файлов. +editor.status.drag_and_drop.files_added.1 = Файл добавлен в скетч. +editor.status.drag_and_drop.files_added.n = В скетч добавлено %d файла(-ов). +editor.status.saving = Сохранение... +editor.status.saving.done = Сохранение завершено. +editor.status.saving.canceled = Сохранение отменено. +editor.status.printing = Печать... +editor.status.printing.done = Печать завершена. +editor.status.printing.error = Ошибка печати. +editor.status.printing.canceled = Печать отменена. +editor.status.copy_as_html = Код, форматированный в HTML, скопирован в буфер обмена. +editor.status.debug.busy = Отладчик занят... +editor.status.debug.halt = Отладчик остановлен. +editor.status.archiver.create = "%s" создан. +editor.status.archiver.cancel = Архивирование отменено. + +# Errors +editor.status.warning = Предупреждение +editor.status.error = Ошибка +editor.status.error_on = Ошибка в "%s" +editor.status.missing.default = Пропущен "%c" +editor.status.missing.semicolon = Пропущена ";" +editor.status.missing.left_sq_bracket = Пропущена "[" +editor.status.missing.right_sq_bracket = Пропущена "]" +editor.status.missing.left_paren = Пропущена "(" +editor.status.missing.right_paren = Пропущена ")" +editor.status.missing.left_curly_bracket = Пропущена "{" +editor.status.missing.right_curly_bracket = Пропущена "}" +editor.status.missing.add = Добавьте "%s" +editor.status.bad_curly_quote = Косые кавычки %s не работают. Используйте прямые. Ctrl-T для автозамены. +editor.status.reserved_words = "color" и "int" - зарезервированы и не могут быть использованы в качестве имён переменных +editor.status.undefined_method = Функция "%s(%s)" не определена +editor.status.undefined_constructor = Конструктор "%s(%s)" не определён +editor.status.empty_param = Функция "%s()" не имеет параметров +editor.status.wrong_param = Функция "%s()" ожидает параметры: "%s(%s)" +editor.status.undef_global_var = Глобальная переменная "%s" не определена +editor.status.undef_class = Класс "%s" не определён +editor.status.undef_var = Переменная "%s" не определена +editor.status.undef_name = Имя "%s" не может быть распознано +editor.status.unterm_string_curly = Строковый литерал не заключён в двойные кавычки. Косые кавычки %s не применимы. +editor.status.type_mismatch = Несовпадение типов "%s" и "%s" +editor.status.unused_variable = Локальная переменная "%s" нигде не используется +editor.status.uninitialized_variable = Локальная переменная "%s" не инициализирована +editor.status.no_effect_assignment = Присвоение переменной "%s" не имеет эффекта +editor.status.hiding_enclosing_type = Класс "%s" не может иметь имя наброска + +# Footer buttons +editor.footer.errors = Ошибки +editor.footer.errors.problem = Проблема +editor.footer.errors.tab = Вкладка +editor.footer.errors.line = Строка +editor.footer.console = Консоль + +# New handler +new.messages.is_read_only = Набросок только для чтения +new.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nСохраните их в другом месте и попробуйте снова. + +# Rename handler +rename.messages.is_untitled = Набросок без названия +rename.messages.is_untitled.description = Сперва сохраните набросок, перед\n тем как его переименовывать +rename.messages.is_modified = Сохраните набросок, перед его переименованием. +rename.messages.is_read_only = Набросок только для чтения +rename.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nСохраните их в другом месте и попробуйте снова. + +# Naming handler +name.messages.problem_renaming = Проблема переименования +name.messages.starts_with_dot.description = Имя не может начинаться с точки +name.messages.invalid_extension.description = ".%s" не допустимое расширениие. +name.messages.main_java_extension.description = Первая вкладка не может быть %s файлом.\n(Воспользуйтесь другой, "правильной" средой\nпрограммирования?) +name.messages.new_sketch_exists = Переименование невозможно +name.messages.new_sketch_exists.description = Файл "%s" уже существует в\n"%s" +name.messages.new_folder_exists = Переименование невозможно +name.messages.new_folder_exists.description = Набросок(или папка) "%s" уже существует. +name.messages.error = Ошибка +name.messages.no_rename_folder.description = Не удалось переименовать папку наброска. +name.messages.no_rename_file.description = Не удалось переименовать "%s" на "%s" +name.messages.no_create_file.description = Не удалось создать файл "%s"\nв "%s" + +# Delete handler +delete.messages.cannot_delete = Нельзя удалить +delete.messages.cannot_delete.description = Нельзя удалить несохранённый набросок. +delete.messages.cannot_delete.file = Не удалось +delete.messages.cannot_delete.file.description = Не получилось удалить +delete.messages.is_read_only = Набросок открыт "только для чтения" +delete.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nСохраните их в другом месте и попробуйте снова. + +# Save handler +save_file.messages.is_read_only = Набросок только для чтения +save_file.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nСохраните их в другом месте и попробуйте снова. +save_file.messages.sketch_exists = Набросок уже существует +save_file.messages.sketch_exists.description = Набросок с очищенным именем\n“%s” уже существует. +save_file.messages.tab_exists = Не удалось сохранить +save_file.messages.tab_exists.description = Нельзя сохранить набросок "%s"\n. Вкладка с таким именем уже открыта +save_file.messages.recursive_save = Сохранение в стиле Боргеса +save_file.messages.recursive_save.description = Нельзя сохранить набросок в папку внутри\nсамого себя. Будет циклическая зависимость. + +# Add handler +add_file.messages.is_read_only = Набросок "только для чтения" +add_file.messages.is_read_only.description = Некоторые файлы помечены "только для чтения".\nСохраните их в другом месте и попробуйте снова. +add_file.messages.confirm_replace = Заменить существующюю версию %s? +add_file.messages.error_adding = Ошибка при добавлении файла +add_file.messages.cannot_delete.description = Не получилось удалить существующий файл '%s'. +add_file.messages.cannot_add.description = Не удалось добавить '%s' в набросок. +add_file.messages.same_file = Меня не обдуришь +add_file.messages.same_file.description = Этот файл уже был скопирован в то место\nкуда вы пытаетесь его скопировать.\nНичего не будет сделано. + +# Temp folder creator +temp_dir.messages.bad_build_folder = Плохая папка сборки +temp_dir.messages.bad_build_folder.description = Не удалось найти место для сборки. + +# Ensure Existance +ensure_exist.messages.missing_sketch = Набросок не найден +ensure_exist.messages.missing_sketch.description = Папка с наброском не найдена.\nПопробуем сохранить заново, некоторые\nизменения возможно будут утрачены. +ensure_exist.messages.unrecoverable = Не удалось востановить набросок +ensure_exist.messages.unrecoverable.description = Не удалось повторно сохранить набросок. У вас могут возникнуть трудности,\nпри редактировании в внешнем текстовом редакторе. + +# Check name +check_name.messages.is_name_modified = Имя наброска было изменено. Имена набросков могут состоять\nтолько из ASCII-символов и цифр (но не могут начинаться с цифры).\nТакже имя не должно быть больше 64-ёх + +# External changes detector +change_detect.reload.title=Вкладка изменена вне приложения +change_detect.reload.question="%s" изменена другим приложением. +change_detect.reload.comment=Оставить или перезагрузить изменения?\nВ любом случае файл будет сохранён в папке с наброском. +change_detect.button.keep=Оставить +change_detect.button.load_new=Перезагрузить +change_detect.delete.title=Вкладка удалена вне программы +change_detect.delete.question="%s" пропала из папки с работами. +change_detect.delete.comment=Хотите пересохранить или удалить набросок? +change_detect.button.discard=Удалить +change_detect.button.resave=Пересохранить + +# --------------------------------------- +# Contributions + +# Contribution Panel +contrib = Управление расширениями +contrib.manager_title.update = Управление обновлениями +contrib.manager_title.mode = Управление режимами +contrib.manager_title.tool = Управление инструментами +contrib.manager_title.library = Управление библиотеками +contrib.manager_title.examples = Управление примерами +contrib.category = Категория: +contrib.filter_your_search = Фильтр поиска... +contrib.show_only_compatible.mode = Показать только совместимые режимы +contrib.show_only_compatible.tool = Показать только совместимые инструменты +contrib.show_only_compatible.library = Показать только совместимые библиотеки +contrib.show_only_compatible.examples = Показать только совместимые примеры +contrib.show_only_compatible.update = Показать только совместимые обновления +contrib.restart = Перезапустить Processing +contrib.unsaved_changes = Остались несохранённые изменения +contrib.unsaved_changes.prompt = Вы уверены, что хотите перезапустить Processing, не сохранив изменений? +contrib.messages.remove_restart = Перезапустите Processing, для завершения удаления расширения. +contrib.messages.install_restart = Перезапустите Processing, для завершения установки расширения. +contrib.messages.update_restart = Перезапустите Processing, для завершения обновления расширения. +contrib.errors.list_download = Ну удалось загрузить список доступных расширений. +contrib.errors.list_download.timeout = Тайм-аут соединения при загрузке списка расширений. +contrib.errors.download_and_install = Ошибка при загрузке и установке %s. +contrib.errors.description_unavailable = Описание недоступно. +contrib.errors.malformed_url = Ссылка полученная с Processing.org, не рабочая.\nЭту библиотеку всё ещё можно установить вручную\nзагрузив её с сайта. +contrib.errors.needs_repackage = %s требует правильной пересборки %s. +contrib.errors.no_contribution_found = Не удалось найти %s в загруженном файле. +contrib.errors.overwriting_properties = Ошибка сохранения файла .properties. +contrib.errors.install_failed = Установка не удалась. +contrib.errors.update_on_restart_failed = Не удалась установка обновления %s при перезапуске. +contrib.errors.temporary_directory = Не удалась запись во временную папку. +contrib.errors.contrib_download.timeout = Тайм-аут соединения при загрузке %s. +contrib.errors.no_internet_connection = Нет подключения к сети. +contrib.status.downloading_list = Список загрузок расширений... +contrib.status.connecting = Соединение... +contrib.status.done = Готово. +contrib.all = Всё +contrib.undo = Отменить +contrib.remove = Удалить +contrib.install = Установить +contrib.progress.installing = Установка +contrib.progress.starting = Начинаем +contrib.progress.downloading = Загрузка +contrib.download_error = Произошла ошибка при загрузке расширений. +contrib.unsupported_operating_system = Ваша система не поддерживается. Посетите %s для получения подробной информации. +contrib.category.3d = 3D +contrib.category.animation = Анимация +contrib.category.data = Данные +contrib.category.geometry = Геометрия +contrib.category.gui = Интерфейс +contrib.category.hardware = Аппаратное обеспечение +contrib.category.i_o = Ввод/Вывод +contrib.category.math = Математика +contrib.category.simulation = Симуляция +contrib.category.sound = Звук +contrib.category.typography = Типография +contrib.category.utilities = Утилиты +contrib.category.video_vision = Видео +contrib.category.other = Остальное + +# Install on Startup +contrib.startup.errors.download_install = Ошибка при загрузке и установке %s +contrib.startup.errors.temp_dir = Не удалась запись во временную папку при загрузке и установке %s +contrib.startup.errors.new_marker = Метка не обновлённых расширений не похожа на %s. Возможно потребуется обновление вручную... + +# Install on Import +contrib.import.dialog.title = Пропущены доступные бибиотеки +contrib.import.dialog.primary_text = Для следующие импортированных библиотек доступны обновления, которые ещё не установлены. +contrib.import.dialog.secondary_text = Хотите установить их сейчас? +contrib.import.progress.download = Загрузка %s... +contrib.import.progress.install = Установка %s... +contrib.import.progress.done = %s было установлено. +contrib.import.progress.final_list = Были устновлены следующие библиотеки: +contrib.import.errors.link = Ошибка: у библиотеки %s странная ссылка для загрузки. + +# --------------------------------------- +# Warnings + +warn.delete = Удалить +warn.delete.sketch = Вы уверены, что хотите удалить эскиз? +warn.delete.file = Вы уверены, что хотите удалить "%s"? +warn.cannot_change_mode.title = Нельзя сменить режим +warn.cannot_change_mode.body = Не получается изменить режим,\nтак как "%s" не совместим с текущим режимом. + + +# --------------------------------------- +# Update Check + +update_check = Обновить +update_check.updates_available.core = Доступна новая версия Processing,\nхотите перейти на страницу загрузки Processing? +update_check.updates_available.contributions = Доступны обновления сообщества,\nхотите перейти в менеджер обновлений сообщества? + + +# --------------------------------------- +# Color Chooser + +color_chooser = Выбрать цвет +color_chooser.select = Выбрать + +# --------------------------------------- +# Movie Maker + +movie_maker = Генератор видео +movie_maker.title = Генератор QuickTime +movie_maker.blurb = Этот инструмент делает QuickTime видео из последовательности изображений.

Для недопущения появления артефактов от пересжатеия изобажений в видео
используйте TIFF, TGA (из Processing) или PNG форматы.

Изображения TIFF и TGA обработаются быстрее, но получившееся видео будет занимать больше места на диске:
saveFrame("frames/####.tif");
saveFrame("frames/####.tga");

PNG изображения меньше, но набросок будет работать медленно:
saveFrame("frames/####.png");

Код на основе QuickTime Movie Maker 1.5.1 2011-01-17.
Copyright © 2010-2011 Werner Randelshofer. Все права защищены.
+movie_maker.image_folder_help_label = Перетяните папку с изображениями в поле ниже: +movie_maker.choose_button = Выбрать... +movie_maker.select_image_folder = Выбрать папку с изображениями... +movie_maker.sound_file_help_label = Перенесите файл (.au, .aiff, .wav, .mp3) в поле ниже: +movie_maker.select_sound_file = Выбрать звуковой файл... + +movie_maker.create_movie_button = Создать видео... +movie_maker.save_dialog_prompt = Сохранить видео как... +movie_maker.width = Ширина: +movie_maker.height = Высота: +movie_maker.compression = Сжатие: +movie_maker.compression.animation = Анимация +movie_maker.compression.jpeg = JPEG +movie_maker.compression.png = PNG +movie_maker.framerate = Частота кадров: +movie_maker.orig_size_button = Размер, как у оригинала +movie_maker.orig_size_tooltip = Отметьте флажок, если папка уже содержит видео правильного размера. + +movie_maker.error.avoid_tiff = Попробуйте TGA или PNG вместо TIFF. +movie_maker.error.badnumbers = Ширина и высота должны быть натуральными числами; частота кадров должна быть больше нуля. +movie_maker.error.cannot_read = Не удалось прочитать %s. +movie_maker.error.cannot_read_maybe_bad = Не удалось прочитать %s; файл может быть повреждён. +movie_maker.error.movie_failed = Не удалось создать видео QuickTime. +movie_maker.error.need_input = Нужно сначала выбрать папку с изображениями, звуковыми файлами или всем сразу. +movie_maker.error.no_images_found = Не найдены файлы изображений. +movie_maker.error.sorry = Извините +movie_maker.error.unknown_tga_format = Неизвестный формат .tga для %s. + +movie_maker.progress.creating_file_name = Создаётся %s. +movie_maker.progress.creating_output_file = Создаётся выходной файл +movie_maker.progress.initializing = Инициализация... +movie_maker.progress.processing = Обработка %s. diff --git a/build/shared/lib/languages/PDE_tr.properties b/build/shared/lib/languages/PDE_tr.properties index c7229aed60..8773b8860a 100644 --- a/build/shared/lib/languages/PDE_tr.properties +++ b/build/shared/lib/languages/PDE_tr.properties @@ -19,8 +19,8 @@ menu.file.sketchbook.empty = Boş Sketchbook menu.file.examples = Örnekler... menu.file.close = Kapat menu.file.save = Kaydet -menu.file.save_as = ... olarak Kaydet -menu.file.export_application = Aktar +menu.file.save_as = Farklı Kaydet +menu.file.export_application = Dışa Aktar menu.file.page_setup = Sayfa Yapısı menu.file.print = Yazdır menu.file.preferences = Tercihler @@ -38,8 +38,8 @@ menu.edit.paste = Yapıştır menu.edit.select_all = Tümünü Seç menu.edit.auto_format = Otomatik Biçimlendir menu.edit.comment_uncomment = Yorumla/Yorumu Kaldır -menu.edit.increase_indent = Girintiyi Artır -menu.edit.decrease_indent = Girintiyi Azalt +menu.edit.increase_indent = → Girintiyi Artır +menu.edit.decrease_indent = ← Girintiyi Azalt menu.edit.find = Bul.. menu.edit.find_next = Sonrakini Bul menu.edit.find_previous = Öncekini Bul @@ -48,8 +48,8 @@ menu.edit.use_selection_for_find = Seçimi Bul # | File | Edit | Sketch | Debug | Tools | Help | # | Sketch | menu.sketch.run = Çalıştır -menu.sketch.present = Sürmekte -menu.sketch.tweak = Tweak +menu.sketch.present = Sunum Yap +menu.sketch.tweak = Ayar Çek menu.sketch.stop = Durdur # --- menu.library = Kütüphane... @@ -104,7 +104,7 @@ prompt.no = Hayır prompt.cancel = İptal prompt.ok = Tamam prompt.browse = Gözat -prompt.export = Aktar +prompt.export = Dışa Aktar # --------------------------------------- @@ -201,7 +201,7 @@ archive_sketch = ... olarak Arşivle # [Run/Present] [Stop] [New] [Open] [Save] toolbar.run = Çalıştır -toolbar.present = Sürmekte +toolbar.present = Sunum Yap toolbar.stop = Durdur # --- toolbar.new = Yeni diff --git a/build/shared/lib/languages/PDE_uk.properties b/build/shared/lib/languages/PDE_uk.properties index 07ce05aa55..9eb9050fbb 100644 --- a/build/shared/lib/languages/PDE_uk.properties +++ b/build/shared/lib/languages/PDE_uk.properties @@ -31,6 +31,9 @@ menu.file.quit = Вийти menu.edit = Редагування menu.edit.undo = Скасувати menu.edit.redo = Повторити +menu.edit.redo.keystroke.macosx = shift meta pressed Z +menu.edit.redo.keystroke.windows = ctrl pressed Y +menu.edit.redo.keystroke.linux = shift ctrl pressed Z menu.edit.action.addition = додавання menu.edit.action.deletion = видалення menu.edit.cut = Вирізати @@ -40,8 +43,17 @@ menu.edit.paste = Вставити menu.edit.select_all = Виділити все menu.edit.auto_format = Автоформатування menu.edit.comment_uncomment = Коментувати/Розкоментувати -menu.edit.increase_indent = Збільшити відступ -menu.edit.decrease_indent = Зменшити відступ +menu.edit.comment_uncomment.keystroke.macosx = meta pressed SLASH +menu.edit.comment_uncomment.keystroke.windows = ctrl pressed SLASH +menu.edit.comment_uncomment.keystroke.linux = ctrl pressed SLASH +menu.edit.increase_indent = → Збільшити відступ +menu.edit.increase_indent.keystroke.macosx = meta pressed CLOSE_BRACKET +menu.edit.increase_indent.keystroke.windows = ctrl pressed CLOSE_BRACKET +menu.edit.increase_indent.keystroke.linux = ctrl pressed CLOSE_BRACKET +menu.edit.decrease_indent = ← Зменшити відступ +menu.edit.decrease_indent.keystroke.macosx = meta pressed OPEN_BRACKET +menu.edit.decrease_indent.keystroke.windows = ctrl pressed OPEN_BRACKET +menu.edit.decrease_indent.keystroke.linux = ctrl pressed OPEN_BRACKET menu.edit.find = Знайти... menu.edit.find_next = Знайти наступне menu.edit.find_previous = Знайти попереднє @@ -77,8 +89,17 @@ menu.debug.toggle_breakpoint = Додати / вилучити точку зуп # --- # used for both menus and toolbars menu.debug.step = Крок +menu.debug.step.keystroke.macosx = meta pressed J +menu.debug.step.keystroke.windows = ctrl pressed J +menu.debug.step.keystroke.linux = ctrl pressed J menu.debug.step_into = Крок із заходом +menu.debug.step_into.keystroke.macosx = shift meta pressed J +menu.debug.step_into.keystroke.windows = shift ctrl pressed J +menu.debug.step_into.keystroke.linux = shift ctrl pressed J menu.debug.step_out = Крок із виходом +menu.debug.step_out.keystroke.macosx = meta alt pressed J +menu.debug.step_out.keystroke.windows = ctrl alt pressed J +menu.debug.step_out.keystroke.linux = ctrl alt pressed J menu.debug.continue = Продовжити # --- #menu.debug.print_stack_trace = Друкувати стек викликів @@ -166,6 +187,8 @@ preferences.editor_and_console_font = Шрифт редактора і конс preferences.editor_and_console_font.tip = Виберіть шрифт, що використовуватиметься у редакторі та консолі.
Можна використовувати лише моноширинні шрифти. preferences.editor_font_size = Розмір шрифту редактора preferences.console_font_size = Розмір шрифту консолі +preferences.zoom = Розмір інтерфейсу +preferences.zoom.auto = Автоматичний preferences.background_color = Колір фону в режимі презентації preferences.background_color.tip = Виберіть фоновий колір для режиму презентації.
Режим презентації використовується для повноекранної презентації ескізу
і доступний з меню Ескіз. preferences.use_smooth_text = Використовувати згладжений текст у вікні редактора @@ -311,11 +334,18 @@ editor.header.new_tab = Нова вкладка editor.header.rename = Перейменувати editor.header.delete = Видалити editor.header.previous_tab = Попередня вкладка +editor.header.previous_tab.keystroke.macosx = meta alt pressed LEFT +editor.header.previous_tab.keystroke.windows = ctrl pressed PAGE_UP +editor.header.previous_tab.keystroke.linux = ctrl pressed PAGE_UP editor.header.next_tab = Наступна вкладка +editor.header.next_tab.keystroke.macosx = meta alt pressed RIGHT +editor.header.next_tab.keystroke.windows = ctrl pressed PAGE_DOWN +editor.header.next_tab.keystroke.linux = ctrl pressed PAGE_DOWN editor.header.delete.warning.title = Хех, ні. editor.header.delete.warning.text = Не можна видалити головну вкладку єдиного відкритого ескізу. # PopUp menu +editor.popup.jump_to_declaration = Перейти до визначення editor.popup.show_usage = Показати використання... editor.popup.rename = Перейменувати... @@ -361,6 +391,7 @@ editor.status.missing.right_paren = Відсутня ")" editor.status.missing.left_curly_bracket = Відсутня "{" editor.status.missing.right_curly_bracket = Відсутня "}" editor.status.missing.add = Спробуйте додати "%s" +editor.status.bad_curly_quote = Фігурні лапки %s не працюють. Використовуйте прямі лапки. Ctrl-T для автозаміни. editor.status.reserved_words = "color" і "int" - зарезервовані ідентифікатори і не можуть бути назвами змінних editor.status.undefined_method = Функція "%s(%s)" не існує editor.status.undefined_constructor = Конструктор "%s(%s)" не існує @@ -370,10 +401,12 @@ editor.status.undef_global_var = Глобальна змінна "%s" не іс editor.status.undef_class = Клас "%s" не існує editor.status.undef_var = Змінна "%s" не існує editor.status.undef_name = Ім’я "%s" не може бути розпізнано +editor.status.unterm_string_curly = Рядковий літерал не оточений прямими лапками. Фігурні лапки %s не працюють. editor.status.type_mismatch = Неспівпадіння типів "%s" та "%s" editor.status.unused_variable = Локальна змінна "%s" ніде не використовується editor.status.uninitialized_variable = Локальна змінна "%s" може бути не ініціалізована editor.status.no_effect_assignment = Присвоєння змінної "%s" не має чинності +editor.status.hiding_enclosing_type = Клас "%s" не може мати ім'я ескізу або батьківського класу. # Footer buttons editor.footer.errors = Помилки @@ -448,6 +481,18 @@ ensure_exist.messages.unrecoverable.description = Не вдалось повто # Check name check_name.messages.is_name_modified = Ім’я ескізу потрібно було змінити. Імена ескізів можуть містити\nтільки ASCII-символи і числа (але не можуть починатися з числа).\nКрім того, вони мають бути не довшими за 64 символи. +# External changes detector +change_detect.reload.title=Вкладка змінена ззовні +change_detect.reload.question="%s" була змінена іншою програмою. +change_detect.reload.comment=Бажаєте залишити цю версію чи завантажити зміни ззовні?\nТак чи інакше, файл буде збережено в папці з ескізами. +change_detect.button.keep=Залишити +change_detect.button.load_new=Завантажити зміни ззовні +change_detect.delete.title=Вкладка видалена +change_detect.delete.question="%s" зникла з папки з ескізами. +change_detect.delete.comment=Бажаєте повторно її зберегти чи видалити зі свого ескізу? +change_detect.button.discard=Видалити назавжди +change_detect.button.resave=Повторно зберегти + # --------------------------------------- # Contributions @@ -532,6 +577,8 @@ contrib.import.errors.link = Помилка: У бібліотеки %s неді warn.delete = Видалення warn.delete.sketch = Ви впевнені, що хочете видалити цей ескіз? warn.delete.file = Ви впевнені, що хочете видалити "%s"? +warn.cannot_change_mode.title = Зміна режиму неможлива +warn.cannot_change_mode.body = Зміна режиму неможлива,\nоскільки режим "%s" несумісний з поточним режимом. # --------------------------------------- diff --git a/build/shared/lib/languages/PDE_zh.properties b/build/shared/lib/languages/PDE_zh.properties index 6e97ee4188..8cf6da2166 100644 --- a/build/shared/lib/languages/PDE_zh.properties +++ b/build/shared/lib/languages/PDE_zh.properties @@ -37,8 +37,8 @@ menu.edit.paste = 黏贴 menu.edit.select_all = 全部选择 menu.edit.auto_format = 自动对齐 menu.edit.comment_uncomment = 注释/取消注释 -menu.edit.increase_indent = 增加缩进量 -menu.edit.decrease_indent = 减少缩进量 +menu.edit.increase_indent = → 增加缩进量 +menu.edit.decrease_indent = ← 减少缩进量 menu.edit.find = 查找... menu.edit.find_next = 查找下一个 menu.edit.find_previous = 查找上一个 @@ -48,7 +48,7 @@ menu.edit.use_selection_for_find = 使用当前选定查找 # | Sketch | menu.sketch.run = 运行 menu.sketch.present = 展示模式 -menu.sketch.tweak = Tweak +menu.sketch.tweak = 调整 menu.sketch.stop = 停止 # --- menu.library = 引用库文件... @@ -62,7 +62,23 @@ menu.sketch.add_file = 添加文件... # | File | Edit | Sketch | Debug | Tools | Help | # | Debug | -# ... +# | File | Edit | Sketch | Debug | Tools | Help | +# | Debug | +menu.debug = 调试 +menu.debug.enable = 启用调试器 +menu.debug.disable = 禁用调试器 +# --- +menu.debug.toggle_breakpoint = 切换断点 +# --- +# used for both menus and toolbars +menu.debug.step = 单步 (Step) +menu.debug.step_into = 单步进入 (Step Into) +menu.debug.step_out = 单步跳出 (Step Out) +menu.debug.continue = 继续 +# --- +#menu.debug.variable_inspector = Variable Inspector +menu.debug.show_variables = 显示变量 +menu.debug.hide_variables = 隐藏变量 # | File | Edit | Sketch | Debug | Tools | Help | # | Tools | @@ -129,8 +145,8 @@ preferences.language = 语言 preferences.editor_and_console_font = 编辑器和控制台字体 preferences.editor_and_console_font.tip = \ 为编辑器和控制台选择字体.
\ -Only monospaced (fixed-width) fonts may be used,
\ -though the list may be imperfect. +只允许使用等宽字体,
\ +此列表可能不完全。 preferences.editor_font_size = 编辑器字体大小 preferences.console_font_size = 控制台字体大小 preferences.background_color = 展示模式时的背景颜色 @@ -140,27 +156,27 @@ preferences.background_color.tip = \ 可从速写本菜单中访问. preferences.use_smooth_text = 在编辑器窗口中使用平滑字体 preferences.enable_complex_text_input = 启用复杂字体输入 -preferences.enable_complex_text_input_example = i.e. Japanese +preferences.enable_complex_text_input_example = 例如日文 preferences.continuously_check = 不断检查错误 preferences.show_warnings = 显示警告 -preferences.code_completion = Code completion -preferences.trigger_with = Trigger with -preferences.cmd_space = space +preferences.code_completion = 代码补全 +preferences.trigger_with = 触发开关 +preferences.cmd_space = 空格 preferences.increase_max_memory = 增加最大内存至 preferences.delete_previous_folder_on_export = 当导出时删除先前的文件夹 preferences.hide_toolbar_background_image = 隐藏标签/工具栏背景图片 preferences.check_for_updates_on_startup = 在启动时检查有无更新 -preferences.run_sketches_on_display = Run sketches on display +preferences.run_sketches_on_display = 在此显示器中运行速写本 preferences.run_sketches_on_display.tip = \ Sets the display where sketches are initially placed.
\ As usual, if the sketch window is moved, it will re-open
\ at the same location, however when running in present
\ (full screen) mode, this display will always be used. preferences.automatically_associate_pde_files = 自动关联 .pde 文件通过 Processing -preferences.launch_programs_in = Launch programs in +preferences.launch_programs_in = 加载程序的模式 preferences.launch_programs_in.mode = 模式 preferences.file = 更多选项可直接编辑该文件 -preferences.file.hint = 请在Processing不在运行时编辑该文件 +preferences.file.hint = 请在 Processing 未运行时编辑该文件 # Sketchbook Location (Frame) sketchbook_location = 选择新速写本位置 @@ -187,7 +203,7 @@ find.find = 搜索: find.replace_with = 替换为: find.ignore_case = 忽略大小写 find.all_tabs = 所有标签 -find.wrap_around = Wrap Around +find.wrap_around = 循环遍历 find.btn.replace_all = 全部替换 find.btn.replace = 替换 find.btn.find_and_replace = 搜索 & 替换 @@ -238,8 +254,8 @@ editor.header.rename = 重命名 editor.header.delete = 删除 editor.header.previous_tab = 前一个标签 editor.header.next_tab = 后一个标签 -editor.header.delete.warning.title = Yeah, no. -editor.header.delete.warning.text = You can't delete the last tab of the last open sketch. +editor.header.delete.warning.title = 这样不行 +editor.header.delete.warning.text = 无法删除最后一个速写本的最后一个标签 # Tabs editor.tab.new = 新文件名 @@ -248,15 +264,15 @@ editor.tab.rename = 新文件名 editor.tab.rename.description = 新文件名称 # Sketch -editor.sketch.rename.description = New name for sketch - -editor.status.autoformat.no_changes = No changes necessary for Auto Format. -editor.status.autoformat.finished = Auto Format finished. -editor.status.find_reference.select_word_first = First select a word to find in the reference. -editor.status.find_reference.not_available = No reference available for "%s". -editor.status.drag_and_drop.files_added.0 = No files were added to the sketch. -editor.status.drag_and_drop.files_added.1 = One file added to the sketch. -editor.status.drag_and_drop.files_added.n = %d files added to the sketch. +editor.sketch.rename.description = 速写本的新名称 + +editor.status.autoformat.no_changes = 自动格式化不需要做更改。 +editor.status.autoformat.finished = 自动格式化完成。 +editor.status.find_reference.select_word_first = 请首先选择要查找的关键字。 +editor.status.find_reference.not_available = 没有找到 "%s" 的引用。 +editor.status.drag_and_drop.files_added.0 = 未将任何文件添加到速写本。 +editor.status.drag_and_drop.files_added.1 = 将 1 个文件添加到速写本。 +editor.status.drag_and_drop.files_added.n = 将 %d 个文件添加到速写本。 editor.status.saving = 保存中... editor.status.saving.done = 保存完成. editor.status.saving.canceled = 取消保存. @@ -275,7 +291,7 @@ contrib.install = 安装 contrib.progress.starting = 开始 contrib.progress.downloading = 下载 contrib.download_error = 下载时出现问题. -contrib.unsupported_operating_system = 你当前的操作系统似乎不被支持. 你应该访问 %s's 该库文件地址得到更多信息. +contrib.unsupported_operating_system = 你当前的操作系统似乎不被支持. 你应该访问 %s 获取更多信息. # --------------------------------------- diff --git a/build/shared/lib/languages/languages.txt b/build/shared/lib/languages/languages.txt index e86d7da446..27ca7a6e8a 100644 --- a/build/shared/lib/languages/languages.txt +++ b/build/shared/lib/languages/languages.txt @@ -5,15 +5,18 @@ # Add new languages in alphabetical order to (slightly) # reduce the risk of merge conflicts +ar # Arabic de # German, Deutsch en # English, English el # Greek es # Spanish fr # French, Français, Langue française +it # Italiano, Italian ja # Japanese ko # Korean nl # Dutch, Nederlands pt # Portuguese +ru # Russian tr # Turkish uk # Ukrainian zh # Chinese diff --git a/build/shared/lib/theme.txt b/build/shared/lib/theme.txt index 06101c6a0c..88083bd240 100644 --- a/build/shared/lib/theme.txt +++ b/build/shared/lib/theme.txt @@ -6,7 +6,11 @@ status.error.fgcolor = #ffffff status.error.bgcolor = #9E0A0A status.warning.bgcolor = #EF8115 status.warning.fgcolor = #FFFFFF +status.url.fgcolor = #cccccc status.font = processing.sans,plain,13 +# For the clipboard icon, needs to be a little larger on macOS +status.emoji.font = Dialog,plain,19 +status.emoji.font.macosx = Dialog,plain,22 # HEADER TABS # Settings for the tab area at the top. @@ -167,3 +171,6 @@ manager.tab.update.color = #ed7f15 manager.tab.gradient.top = #132638 manager.tab.gradient.bottom = #122535 manager.tab.background = #132638 + +# tree for Examples and Sketchbook windows +tree.font = processing.sans,plain,12 diff --git a/build/shared/lib/welcome/generic.html b/build/shared/lib/welcome/generic.html index f82e090083..798a129f51 100644 --- a/build/shared/lib/welcome/generic.html +++ b/build/shared/lib/welcome/generic.html @@ -1,99 +1,31 @@ Welcome to Processing 3 - + - -
- - - - - - - - -
- - -

Welcome to Processing 3

-
- -

- Read about what’s new in 3.0 → -

- -

- Note that some sketches from Processing 2 may not be compatible. - What has changed? -

- - - - - - - -
- - - Show this welcome
message each time -
- -
- -
+ + + + + + +
+ + +

Welcome to Processing 3

+
+ +

+ Read about what’s new in 3.0 → +

+ +

+ Note that some sketches from Processing 2 may not be compatible. + What has changed? +

- diff --git a/build/shared/lib/welcome/sketchbook.html b/build/shared/lib/welcome/sketchbook.html index 0abd822659..7d27e78380 100644 --- a/build/shared/lib/welcome/sketchbook.html +++ b/build/shared/lib/welcome/sketchbook.html @@ -1,122 +1,50 @@ Welcome to Processing 3 - + - -
- - - - - - - -
- - -

Welcome to Processing 3

-
- + + + + + + +
+ + +

Welcome to Processing 3

+
+ +

+ Read about what’s new in 3.0 → +

+ +

+ Note that some sketches from Processing 2 may not be compatible. + What has changed? +

+ +

- Read about what’s new in 3.0 → + Since older sketches may not be compatible, we recommend creating a new sketchbook folder, so Processing 2 and 3 can happily coexist. This is a one-time process. Read more about it.

-

- Note that some sketches from Processing 2 may not be compatible. - What has changed? -

- -
-

- Since older sketches may not be compatible, we recommend creating a new sketchbook folder, so Processing 2 and 3 can happily coexist. This is a one-time process. Read more about it. -

- - - - - - - - - - -
- - - Create a new sketchbook folder for use with Processing 3 sketches (recommended!) -
- - - Use the existing sketchbook folder for both old and new sketches (may cause conflicts with installed libraries) -
- -
- - +
- + +
- - - Show this welcome
message each time + Click here to create a new sketchbook folder for Processing 3 (recommended!)
- + Otherwise, your existing sketchbook folder will be used for both old and new sketches (may cause conflicts with installed libraries)
- - - +
+ diff --git a/build/shared/lib/welcome/style.css b/build/shared/lib/welcome/style.css new file mode 100644 index 0000000000..231f277437 --- /dev/null +++ b/build/shared/lib/welcome/style.css @@ -0,0 +1,43 @@ +* { + margin: 0; + padding: 0; +} + +body { + padding-left: 20px; + padding-right: 20px; + font-family: "Processing Sans Pro", sans-serif; +} + +h1 { + margin-bottom: 0; + /* can't get the Semibold to work properly */ + font-family: "Processing Sans Pro", sans-serif; + font-size: 18px; + font-weight: normal; +} + +p, td { + margin-bottom: 0; + font-size: 11px; + line-height: 12px; +} + +table { + margin-top: 10px; + margin-bottom: 0; +} + +p.inset, table.inset { + padding: 10px; + background-color: rgb(224, 253, 251); +} + +a { + color: #2c7bb5; + text-decoration: none; +} + +#startButton { + margin-left: 50px; +} \ No newline at end of file diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 758accc7fb..5ed6ba5914 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,3 +1,1428 @@ +PROCESSING 3.5.4 (REV 0270) - 17 January 2020 + +This release has several bug fixes to improve the Contribution Manager, +get Tweak Mode working again, and so on. + + +[ changes ] + ++ Don't remove entries from Recent menu on Save As + https://github.com/processing/processing/issues/5902 + ++ Use ctrl-page up/down for changing tabs on Windows + https://github.com/processing/processing/issues/5794 + ++ Show error when .properties file is missing from a Library/Mode/Tool. + + +[ fixes ] + ++ Tweak Mode working again (fix from Gal Sasson) + https://github.com/processing/processing/issues/5805 + https://github.com/processing/processing/pull/5909 + ++ Fix potential highlighting issue that wasn't selecting portions of text + ++ Names in the contribution listing are no longer case sensitive + (It was placing lowercase names at the bottom of the list.) + ++ Clean up a lot of bad temp file handling in the contrib manager + https://github.com/processing/processing/issues/5845 + https://github.com/processing/processing/issues/5960 + ++ Fix NullPointerException in installPreviouslyFailed() on startup + https://github.com/processing/processing/issues/5482 + https://github.com/processing/processing/issues/5916 + + +[ internal ] + ++ Ignore subfolders in the "libraries" directory. This was causing some + nasty startup issues for folks, and other hard-to-track bugs. Hopefully + there aren't any installs that relied on this behavior. + ++ Update AppBundler to use newer SDK, recompile + ++ Edit build.xml files and appbundler to preserve more attributes + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.5.3 (REV 0269) - 3 February 2019 + +This fixes a typo that left the "Redo" command with the wrong +key shortcut on Windows in the last release, adds updated reference, +and includes a handful of other smaller fixes. + + +[ fixes ] + ++ "Redo" key shortcut for Windows screwed up + https://github.com/processing/processing/issues/5773 + ++ Fix an editor problem with plain text (css, etc) files + https://github.com/processing/processing/issues/5628 + ++ Default to using java.awt.Desktop methods for URLs/files when available + on Linux. Also cover a few weird cases that were failing silently. + ++ Ignore .class files found in the META-INF folder for imported JARs + https://github.com/processing/processing/issues/5778 + ++ Get rid of errant 'Could not parse -1 for display' message. + ++ Fix up and clean a few file i/o issues that were causing resource + leaks with loadXxxx() commands, and intermediate folders not being + created for temporary files used by the saveXxxx() commands. + + +[ additions ] + ++ Added reference for circle(), square(), push(), pop() + + +[ contributions ] + ++ Updated translation of the word "sketch" for Russian speakers + https://github.com/processing/processing/pull/5673 + ++ Update missing @Deprecated tags in PApplet.java + https://github.com/processing/processing/pull/5686 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.5.2 (REV 0268) - 22 January 2019 + +Fixed a pair of nasty regressions, and adding a couple key shortcuts +to the preferences file. + +Also: please help us localize the menu shortcuts that have been causing +trouble on non-US keyboards. See the Localization wiki for more details: +https://github.com/processing/processing/wiki/Localization#shortcuts-and-key-bindings + + +[ more regressions! ] + ++ Some Linux/Windows menu shortcuts were mapped to META instead of CTRL + https://github.com/processing/processing/issues/5763 + ++ Ctrl-click on Mac OS X result in all subsequent clicks reported as right-click + https://github.com/processing/processing/issues/5765 + https://github.com/processing/processing/pull/5766 + + +[ and a new feature! ] + ++ The nine menu shortcuts that can be localized can now also be overridden + by users in preferences.txt. Information is on the Localization page. + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.5.1 (REV 0267) - 21 January 2019 + +Should have known better than to try to fix a bug connnected to +something as fundamental as the size() command. This release just +fixes one major regression in 3.5. + +Please see the release notes for 3.5 for the major changes since 3.4: +https://github.com/processing/processing/releases/tag/processing-0266-3.5 + + +[ oops, sorry ] + ++ size() command not working properly + https://github.com/processing/processing/issues/5759 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.5 (REV 0266) - 20 January 2019 + +Hello from the flight back from Processing Community Day 2019 in LA! +How about a new release? Lots of bug fixes and updates for you. + +We're rolling the minor version from 3.4 to 3.5 because of the additions +to the API and a minor (breaking) change to remove() in the Dict classes. + + +[ api changes and additions ] + ++ Added circle() and square() methods. + ++ Added push() and pop() for parity with p5.js + ++ Non-US keyboards have trouble with a couple of shortcuts, + so their implementation has been moved to the language files. + Please help us update the defaults for your language. More here: + https://github.com/processing/processing/wiki/Localization#shortcuts-and-key-bindings + https://github.com/processing/processing/issues/2199 + https://github.com/processing/processing/issues/3538 + ++ Make JSONObject.quote() (both versions) public + ++ Change behavior of the remove() method in IntDict, FloatDict, etc. + It now returns the value removed, for consistency with the other + remove functions (and most usefulness). In some cases, was returning + the index, which isn't as useful. If remove() is called on a value that + does not exist, an runtime exception will be thrown because there's no + sensible way to indicate that nothing was removed. This is also more + consistent with removeIndex() throwing and exception when the specified + index is not available. + + +[ contributed fixes ] + ++ Extended SVG support for fonts and text + https://github.com/processing/processing/pull/4168 + ++ Updated Russian translation, now can choose Russian in preferences + https://github.com/processing/processing/pull/5619 + ++ Turkish translation updates + https://github.com/processing/processing/pull/5636 + ++ Examples dialog was causing high CPU load + https://github.com/processing/processing/issues/5246 + https://github.com/processing/processing/pull/5654 + ++ Show a warning when a font isn't what the user expected + https://github.com/processing/processing/issues/5481 + https://github.com/processing/processing/pull/5605 + ++ Add a button to hide the console + https://github.com/processing/processing/pull/5115 + ++ Fix NullPointerException in Contribution Manager when installing + https://github.com/processing/processing/issues/5524 + https://github.com/processing/processing/pull/5742 + ++ Improvements to appdata.xml for Linux + https://github.com/processing/processing/pull/5604 + ++ Fix javaPlatform variable for newer JDK versions + https://github.com/processing/processing/pull/5626 + ++ Fix blend mode not being set correctly + https://github.com/processing/processing/issues/5645 + https://github.com/processing/processing/pull/5647 + ++ Profile GL3bc is not available on X11GraphicsDevice + https://github.com/processing/processing/issues/5476 + https://github.com/processing/processing/pull/5652 + + +[ jakub fixes ] + ++ Prevent "could not find sketch size" message from freezing the app + https://github.com/processing/processing/issues/4893 + https://github.com/processing/processing/pull/5708 + https://github.com/processing/processing/issues/5030 (duplicate) + ++ Prevent sketch exceptions from being hidden by a warning + https://github.com/processing/processing/pull/5486 + https://github.com/processing/processing/issues/5412 + ++ size(0, 0) just freezes instead of showing an error + https://github.com/processing/processing/issues/5233 (duplicate) + ++ Fix freeze when restarting sketch with variables in size + https://github.com/processing/processing/pull/5708 + ++ Make sure Ctrl+Left Mouse on MacOS is consistent + https://github.com/processing/processing/issues/5672 + https://github.com/processing/processing/pull/5674 + ++ Stop frame rate counter from exaggerating + https://github.com/processing/processing/pull/5697 + ++ Fix vertex buffer initialized with wrong number of components + https://github.com/processing/processing/pull/5698 + ++ Recreate FBOs when offscreen PGraphicsOpenGL is resized + https://github.com/processing/processing/pull/5699 + + +[ andres with the updates ] + ++ Silence TIS/TSM warning message with P2D/P3D/OPENGL since macOS 10.13.4 + https://github.com/processing/processing/issues/5462 + ++ Improve matrix performance in P2D/P3D + https://github.com/processing/processing/issues/5685 + ++ Initializing textures loads the pixels array, even if not needed aferwards + https://github.com/processing/processing/issues/5748 + ++ Improve startup time by skipping the Android SDK folder when listing sketches + https://github.com/processing/processing/issues/5707 + ++ PShape.attrib() and PShape.setAttrib() are not working + https://github.com/processing/processing/issues/5560 + + +[ still more bug fixes and improvements ] + ++ Improve startup time when user-specified fonts are not used. + The default font will be faster, using ttf/otf is fine. + Only load font list when createFont("The Font Name") is used, + or PFont.list() is called. + ++ "Sketch disappeared" infinite pop up dialogs + https://github.com/processing/processing/pull/4808 + https://github.com/processing/processing/issues/4805 + ++ If settings() present but pixelDensity() is in setup(), no error message + https://github.com/processing/processing/issues/4703 + ++ Fix several out of date links in the Help menu + https://github.com/processing/processing/issues/5729 + ++ Update the About screen to 2019 + ++ Update to Java 8u192, then to 8u202 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.4 (REV 0265) - 26 July 2018 + +Kind of a huge batch of bug fixes and updates. + +We've had trouble on Windows when MS Security Essentials or Windows Defender +decides to defend your machine from our software, removing files from the +download and making Processing unusable. A few extra checks have been added +so that more helpful warnings can be conveyed when this happens. + +The other important fix is better handling in the Contributions Manager +for sites that use https. This fixes Python Mode installation, and many +others that have recently started reporting "Could not find a ... in the +downloaded file" when installing a Library, Mode, Tool, or Example set. + +We're also bumping the release to 3.4 because of a lot of additions, +plus some internal changes that have an impact on API. + + +[ the big ones ] + ++ Show alternate error message on Windows when jnidispatch.dll or core.jar + have been removed by Windows Defender or Microsoft Security Essentials. + https://github.com/processing/processing/issues/5537 + https://github.com/processing/processing/issues/4929 + https://github.com/processing/processing/issues/5442 + This has been a huge headache for us. We've repeatedly submitted the + software and asked Microsoft for help, but haven't had any luck. + If you run into this issue and would like to help, please submit the files + to Microsoft here: https://www.microsoft.com/en-us/wdsi/filesubmission + Perhaps if there are enough reports, they'll understand this is affecting + a lot of people. + ++ Contributed libraries/examples/etc that redirect to https URLs now working. + https://github.com/processing/processing/issues/5554 + + +[ new features ] + ++ It's now possible to make your own theme file for Processing. Copy the + theme.txt file from inside the Processing folder to your sketchbook + folder, and then edit away. For instance, to make a dark theme: + https://github.com/processing/processing/wiki/Dark-Theme-for-PDE + ++ It's now possible to copy the text of the status bar. Click the clipboard + icon at the right-hand side to copy the text to the clipboard. To search + immediately, use shift-click. + https://github.com/processing/processing/issues/5271 + https://github.com/processing/processing/pull/5345 + The default search engine is Google, but you can modify that by altering + the 'search.format' line in preferences.txt + ++ Added pyde as a supported extension, so double-clicking + on Python sketches will launch the PDE. + https://github.com/jdf/processing.py/issues/284 + + +[ do you like data? ] + ++ Added Double and Long versions of the data classes. Not sure if we'll + keep these, but we're trying them out. + ++ Also add subset(long) and subset(double) to PApplet + ++ Changed the internal Sort class to use int for comparisons for better + accuracy, especially when working with double and long values. + ++ Consistently implemented write(PrintWriter) in the List and Dict classes + ++ Added save(File) to the List and Dict classes + ++ Prevent Table.sort() from throwing NullPointerException with empty cells + + +[ updates ] + ++ Fixed up the Welcome dialog. When closing the window or hitting ESC, + the "show this" selection is recorded. Also clicking that text will + toggle the checkbox on/off, as users would expect. + https://github.com/processing/processing/issues/3911 + https://github.com/processing/processing/issues/3912 + ++ Redesigned the Rename window to be less ugly. Now closes when ESC is + pressed, and the default action is set so hitting Enter will work properly. + https://github.com/processing/processing/issues/5391 + https://github.com/processing/processing/issues/5400 + ++ Rewrite exec() to do threads, also handle fast/excessive output cases + ++ Rewrite requestImage() to fix errors/slowness/concurrency problems + ++ Refactoring inside the completion code + https://github.com/processing/processing/commit/7e3661e9f7a6df1569c8bebc683e7742f50caa25 + https://github.com/processing/processing/commit/20c6f86c0d600806c991962eb208548ac45e9e2a + https://github.com/processing/processing/commit/8dda8a4d02bc9a1d15e81fee3e6c183e4076a40e + https://github.com/processing/processing/commit/ff7dc4d5094ccf1cc35189c9412adda93153b436 + ++ Now using Java 8u181. + https://github.com/processing/processing/pull/5586 + ++ Change lack of blendMode() to a warning rather than an error in PDF + ++ Updated the copyright and year in the launch and About screen. + + +[ give gohai a hand, because he's all arm ] + ++ A large number of changes and fixes for ARM submitted by Gottfried, + who also posted 3.3.7.1 and 3.3.7.2 interim releases with some of these + changes already present. Now we're back on track with 3.4. + ++ Additional I/O improvements + https://github.com/processing/processing/pull/5581 + ++ Fix regressions in 3.3.7.1 + https://github.com/processing/processing/issues/5582 + ++ OpenGL ES: Fix GLSL version number for 1.00 + https://github.com/processing/processing/pull/5583 + ++ Add ADS1X15 Analog-to-Digital converter example + https://github.com/processing/processing/pull/5590 + ++ IO: pinMode() can now set pull-up and pull-down resistors on Raspbian + thanks to @xranby for 64-bit help + ++ Several new examples + https://github.com/processing/processing/pull/5566 + ++ IO: New example sketch showing how to use a MPR121 capacitive touch sensor + fun tutorial by @msurguy forthcoming + ++ IO: New example sketch showing how to use a BME280 environmental sensor + IO: New example sketch showing how to use a TSL2561 light sensor + IO: New example sketch showing how to use a PCA9685 Servo & PWM controller + ...all contributed by @OlivierLD + ++ IO: pinMode() got faster + https://github.com/processing/processing/pull/5557 + ++ IO: I2C now supports talking to slower devices, such as Arduino boards + https://github.com/processing/processing/pull/5567 + ++ Support for ARM Mali graphics was added to P2D/P3D + Thanks to seongwook from the forums for his help during bringup + https://github.com/processing/processing/pull/5485 + ++ P3D now supports up to 4 lights on Pi using their OpenGL driver + ++ Serial library now supports Raspbian's port naming (such as "/dev/serial0") + ++ Enable exporting of Windows applications on ARM + https://github.com/processing/processing/pull/5488 + https://github.com/processing/processing/issues/5287 + ++ Clarify SimpleInput example + https://github.com/processing/processing/pull/5558 + ++ Various ARM-related updates + https://github.com/processing/processing/pull/5440 + ++ Make P3D work on Linux SBCs using ARM Mali graphics and their ES 3.1 driver + https://github.com/processing/processing/pull/5475 + + +[ contributed by the community ] + ++ Updates to Japanese translation + https://github.com/processing/processing/pull/5263 + ++ Added Russian translation + https://github.com/processing/processing/pull/5451 + ++ Make "loadXML(String)" handle "file not found" + https://github.com/processing/processing/pull/5144 + ++ Update java.lang.UnsupportedClassVersionError message + https://github.com/processing/processing/pull/5459 + ++ Semi-transparent colors do not display properly in PGraphics + https://github.com/processing/processing/issues/5519 + https://github.com/processing/processing/pull/5522 + ++ Fixed a crash occuring while loading certain SVGs exported from Illustrator + https://github.com/processing/processing/pull/5526 + ++ Support PShape.contains() on GROUP objects + https://github.com/processing/processing/pull/5550 + ++ Improve implementation of PShape.contains() to take the CTM into account + https://github.com/processing/processing/pull/5549 + + +[ bug fixes ] + ++ Make sure the editor is updated after reloading changes (from Jakub) + https://github.com/processing/processing/pull/5487 + https://github.com/processing/processing/issues/5466 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.7 (REV 0264) - 13 March 2018 + +A rollup of several fixes from the last few months. + + +[ changes most likely to be noticed ] + ++ Windows Defender blocks Processing 3.3.6. Not sure why this was happening, + but hopefully a new release should be all that's necessary to fix it. + https://github.com/processing/processing/issues/5329 + ++ Lots of fixes for the Net Library by Jakub + https://github.com/processing/processing/pull/5378 + https://github.com/processing/processing/issues/4419 + https://github.com/processing/processing/issues/5360 + https://github.com/processing/processing/issues/3970 + https://github.com/processing/processing/pull/5389 + ++ Include newlines at end of files (i.e. when saving .pde files) + https://github.com/processing/processing/issues/5327 + Why do this? https://stackoverflow.com/a/729795 + ++ Rename (refactor) dialog is unusable on high density screen + https://github.com/processing/processing/issues/5368 + ++ Detect errors from curved quotation marks (a headache when copying/pasting) + https://github.com/processing/processing/issues/5133 + https://github.com/processing/processing/pull/5152 + ++ NullPointerException on close button with P3D and noLoop + https://github.com/processing/processing/issues/5214 + https://github.com/processing/processing/pull/5384 + ++ Fix exception due to version parsing in Java 9 + https://github.com/processing/processing/issues/5275 + ++ Fix line joins on triangles + https://github.com/processing/processing/issues/5353 + https://github.com/processing/processing/pull/5354 + + +[ somewhere in the middle ] + ++ Fix NullPointerException in ContributionManager.deleteFlagged() + https://github.com/processing/processing/issues/5342 + ++ Fix scrub comments for empty block comment /**/ + https://github.com/processing/processing/pull/5265 + https://github.com/processing/processing/issues/5219 + ++ Fix error checker crash when className contains [ or ] + https://github.com/processing/processing/pull/5304 + ++ Table.insertRow() causes ArrayIndexOutOfBoundsException (with fix) + https://github.com/processing/processing/issues/5406 + ++ blendMode() with PDF isn't showing the warning about it not being available + https://github.com/processing/processing/issues/5105 + ++ textureWrap() not updating when changed during draw() + https://github.com/processing/processing/issues/5322 + ++ Cap frameRate() to 1000 in OpenGL + https://github.com/processing/processing/issues/5404 + ++ ARM tweaks for shaders on the Raspberry Pi + https://github.com/processing/processing/pull/5297 + ++ Fix 3D on contemporary versions of Linux + https://github.com/processing/processing/pull/5428 + https://github.com/processing/processing/issues/5308 + ++ cursor() don't work after void noCursor() in P2D and P3D + https://github.com/processing/processing/issues/5330 + https://github.com/processing/processing/pull/5340 + + +[ changes least likely to be noticed ] + ++ Fix JRE download issues + https://github.com/processing/processing/issues/5284 + ++ Update to Java 8u162 + ++ PdePreprocessor change is breaking current source + https://github.com/processing/processing/issues/5413 + ++ Output .java files in UTF-8 and force compiler to use UTF-8 + https://github.com/processing/processing/pull/5436 + ++ Refactor to use a few Java 8 features + https://github.com/processing/processing/pull/5134 + ++ Remove "Pipe Organ" from exec() docs + https://github.com/processing/processing/pull/5282 + ++ Fix typo in Italian translation + https://github.com/processing/processing/issues/5365 + ++ Remove useless deprecation on PImage.mask(int[]) + ++ Make un/registering methods in PApplet thread-safe + https://github.com/processing/processing/pull/5379 + ++ set colorModeDefault to true by default + ++ Minor bezierPoint() rewrite for performance + https://github.com/processing/processing/pull/5251 + + +[ additions! new features! ] + ++ Added setIndex() method to IntDict, FloatDict, StringDict + ++ Added resize() to IntDict, FloatDict, StringDict + ++ Fix entries() Iterator in IntDict, FloatDict, StringDict + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.6 (REV 0263) - 4 September 2017 + +A collection of mostly minor bug fixes that have accreted +since the last release back in June. + + +[ contributions, we love 'em ] + ++ Add Italian translation + https://github.com/processing/processing/pull/5169 + ++ Wrong tab for missing brace + https://github.com/processing/processing/pull/5180 + https://github.com/processing/processing/issues/5165 + ++ Fix typo in German translation + https://github.com/processing/processing/pull/5195 + https://github.com/processing/processing/issues/5187 + ++ Movie Maker only works once + https://github.com/processing/processing/issues/5168 + https://github.com/processing/processing/pull/5230 + ++ Add more build products to linux/.gitignore + https://github.com/processing/processing/pull/5229 + ++ Add issue template to the repo + https://github.com/processing/processing/issues/5239 + https://github.com/processing/processing/pull/5245 + ++ Add workaround for window size = 0 crash + https://github.com/processing/processing/pull/5234 + https://github.com/processing/processing/issues/5052 + + +[ jakub, we love him ] + ++ Fix comment/uncomment adding slashes at wrong indent + https://github.com/processing/processing/issues/5171 + https://github.com/processing/processing/pull/5185 + ++ Add JavaFX runtime to error checker class path + https://github.com/processing/processing/pull/5186 + + +[ gottfried, with gusto ] + ++ Ironing out the new shell() command + https://github.com/processing/processing/pull/5082 + ++ Workaround issues with August 2017 release of Raspbian + https://github.com/processing/processing/pull/5222 + ++ Fix bugs in line vert shader + https://github.com/processing/processing/pull/5184 + https://github.com/processing/processing/issues/5181 + https://github.com/processing/processing/issues/5182 + https://github.com/processing/processing/issues/5183 + https://github.com/processing/processing/issues/5194 + + +[ behind the scenes ] + ++ Updated to Java 8u144 + ++ Fixed issue with call to remove value instead of key in mode contrib hash + (this was only in the code used by the command line mode loader) + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.5 (REV 0262) - 23 June 2017 + +Fixes for a couple problems introduced in the last release. + + +[ everything that went bad ] + ++ Console window was only remembering two lines of text + because of a name collision in the preferences handling. + https://github.com/processing/processing/issues/5110 + ++ Something went wrong with the 64-bit Linux release: + "libjli.so: cannot open shared object file: No such file or directory" + https://github.com/processing/processing/issues/5111 + ++ "Could not parse -1 for --display" message on some Windows machines + https://github.com/processing/processing/issues/5118 + https://github.com/processing/processing/pull/5141 + + +[ some new things hopefully going good ] + ++ Fix a NullPointerException that showed up with textWidth() and OpenGL + https://github.com/processing/processing/issues/5137 + https://github.com/processing/processing/pull/5138 + ++ Per request, use native file choosers by default on Linux. I'm told + that the default Linux file choosers have grown up in the last decade. + I'm trusting the person who is making that claim and making them default. + https://github.com/processing/processing/issues/5122 + To get the old behavior in the Editor, change preferences.txt to say: + chooser.files.native = false + Or in your code, add this line: + useNativeSelect = false; + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.4 (REV 0261) - 3 June 2017 + +Several useful bug fixes and improvements. Some big, many small. + + +[ fixes you'll notice ] + ++ Exported applications no longer report as "Damaged" on macOS Sierra + https://github.com/processing/processing/issues/4705 + ++ Prevent the console from freezing up when print() and println() + are used to print thousands of lines of output. + https://github.com/processing/processing/pull/4935 + https://github.com/processing/processing/issues/4825 + ++ Apple broke key repeat in macOS Sierra, here's how to fix it: + https://github.com/processing/processing/wiki/Troubleshooting#key-repeat-on-macos-sierra + ++ Fix the keyPressed variable when multiple keys are pressed + https://github.com/processing/processing/pull/5050 + https://github.com/processing/processing/issues/5049 + + +[ some you probably won't ] + ++ Clarify wording of error message regarding sketchbook location + https://github.com/processing/processing/issues/4942 + ++ Remove 'run sketches on display' error text that showed up even + when using Processing for the first time + ++ Implement alternate 'ant app' target for macOS application debugging + ++ Added a null check to sketch loading to prevent some issues such as + https://github.com/processing/processing/issues/4980 + ++ Handle edge case for set() being called with a 2D vector, on a 3D vector + https://github.com/processing/processing/issues/5092 + + +[ incomplete additions ] + ++ Add exec() with StringList options (documentation coming soon) + ++ Begin work on a shell() function to do exec() via a shell + + +[ other contributions - thank you! ] + ++ Add install/uninstall scripts for Linux and correct mime types for the PDE + https://github.com/processing/processing/pull/5106 + ++ IO library updates for ARM + https://github.com/processing/processing/pull/5044 + ++ Check $SUDO_USER on Linux for locating the sketchbook folder + https://github.com/processing/processing/pull/5055 + https://github.com/processing/processing/pull/5054 + ++ Debugging the "files changed" detector in the Editor + https://github.com/processing/processing/issues/4713 + https://github.com/processing/processing/pull/5021 + https://github.com/processing/processing/pull/4849 + ++ Still more updates to the change detector + https://github.com/processing/processing/pull/5075 + ++ Warn user to use L when creating a number constant that won't fit into an int + https://github.com/processing/processing/issues/4878 + https://github.com/processing/processing/pull/5077 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.3 (REV 0260) - 2 May 2017 + +Happy birthday to my Dad and baby brother! + +Let's celebrate with a couple of bug fixes: + ++ keyPressed not returning false once a key is released + https://github.com/processing/processing/issues/5033 + ++ Image tint() was broken in 3.3.x + https://github.com/processing/processing/issues/5040 + https://github.com/processing/processing/pull/5042 + ++ Deal with loadBytes() regressions introduced by their rewrite + (was breaking p5jsMode because of its use of loadBytes(File) + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.2 (REV 0259) - 25 April 2017 + +Broke a few eggs with that last omelette, and left a little eggshell behind. +This version takes care of a handful of revisions. + +[ bug fixes, mostly for regressions in 3.3.1 ] + ++ ArrayIndexOutOfBoundsException when using tint() or loadFont() + https://github.com/processing/processing/issues/5028 + https://github.com/processing/processing/pull/5029 + ++ createInput() wasn't returning null for files that were not found + https://github.com/processing/processing/issues/5026 + ++ Assigning Pixels Vertically Flipped in P2D + https://github.com/processing/processing/issues/5013 + + +[ useful updates, that hopefully aren't regressions ] + ++ Improve loadBytes() performance + https://github.com/processing/processing/pull/5027 + ++ Add (far) more efficient file loading for loadBytes(File) + ++ Add loadBytes(URL) variant that uses content length header for array size + ++ keyPressed is false if one key is released while multiple keys are pressed + https://github.com/processing/processing/issues/4993 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3.1 (REV 0258) - 23 April 2017 + +With Casey and Ben together in Boston for a conference, we managed to +wrap up a few things and prepare a new release. Highlights include: + ++ The UI now supports Arabic with a new translation provided by Omar Hommos + ++ Several bug fixes have been implemented for high-res display support + on Windows and Linux + ++ Several updates from Gottfried for ARM devices like Raspberry Pi and CHIP + ++ Lots of pixelDensity() and sketch scaling work has been developed by + Jakub Valtar and is in the current release, though we've not yet + activated these features entirely. Expect those in the 3.4 release. + +And now on with the countdown: + + +[ bug fixes ] + ++ Fix gap between tab headers and text area at 125% and 150% scaling on Windows + https://github.com/processing/processing/issues/4902 + ++ Some line heights were wrong on hi-dpi displays + https://github.com/processing/processing/issues/4936 + https://github.com/processing/processing/issues/5007 + ++ Fix small tooltip text on high-dpi screens + https://github.com/processing/processing/issues/4914 + ++ Ugly button images at 125% and 150% scaling on Windows + https://github.com/processing/processing/issues/4901 + https://github.com/processing/processing/pull/4906 + ++ Get rid of error message when exporting sketches with the video library + https://github.com/processing/processing/issues/4971 + ++ Fix preprocessing of code with double backslash in string or char literal + https://github.com/processing/processing/issues/4903 + https://github.com/processing/processing/pull/4907 + ++ Fix breakpoints in inner classes + https://github.com/processing/processing/pull/5008 + https://github.com/processing/processing/issues/2946 + ++ Fix preprocessor skipping one char after a block comment + https://github.com/processing/processing/issues/4995 + https://github.com/processing/processing/pull/4999 + ++ Synchronize input event processing + https://github.com/processing/processing/pull/4998 + ++ Scrub comments: skip the second chracter in the escape sequence + https://github.com/processing/processing/pull/5019 + https://github.com/processing/processing/issues/5016 + + +[ additions & changes ] + ++ Added Arabic translation + https://github.com/processing/processing/pull/4970 + ++ Added Jump to Declaration + https://github.com/processing/processing/pull/4707 + https://github.com/processing/processing/issues/4668 + ++ Fix the JRE downloader and upgrade to Java 8 update 131 + ++ Add another warning for yet another a bad NVIDIA driver + https://github.com/processing/processing/issues/4997 + ++ Make the Error Table extend white to the bottom + ++ Use built-in font for any non-Roman or CJK language + + +[ graphics & the core ] + ++ Major work on window placement and pixel density by Jakub + https://github.com/processing/processing/pull/5011 + ++ Improve sum() functions in processing.data + Add sum() to IntDict and FloatDict + Add sumLong() to IntList, IntDict (to handle cases outside integer range) + Add sumDouble() to FloatList, FloatDict (to handle outside float range) + Throw exception when using sum() with numbers that are too large or small + ++ createInput() and createOutput() now both use buffered streams by default + createInputRaw() does not, however + ++ Don't derive the font again if the size is unchanged + https://github.com/processing/processing/issues/4956 + ++ fix temporary file handling for saveBytes(), saveStream(), etc + wasn't handling gzip output properly + also could have problems w/ names under length 3 + + +[ gottfried's arms ] + ++ Add support for 64-bit ARM boards + https://github.com/processing/processing/pull/5002 + ++ Hardware I/O updates for ARM + https://github.com/processing/processing/pull/4931 + ++ Fix MeshTweening vertex shader + https://github.com/processing/processing-docs/issues/523 + https://github.com/processing/processing-docs/pull/524 + ++ ARM: Allow Raspberry Pi's Mesa GL driver to use up to 8 lights + https://github.com/processing/processing/pull/4915 + ...and revert it back again + https://github.com/processing/processing/pull/4922 + ++ Retry with multisampling disabled if creating a framebuffer + fails because of INCOMPLETE_MULTISAMPLE + https://github.com/processing/processing/pull/4921 + ++ Report more error conditions in validateFramebuffer + https://github.com/processing/processing/pull/4920 + ++ Add more Raspberry Pi related fixes to JOGL + https://github.com/processing/processing/pull/4911 + ++ Unblock hardware-accelerated P3D on ARM Mali devices + https://github.com/processing/processing/pull/5014 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.3 (REV 0257) - 12 February 2017 + +This release adds the ability to the scale the UI or high-resolution +(known as HiDPI) screens on Windows and Linux. Sketches don't scale yet, +but this will at least make the Editor and Contribution Manager usable +again on more recent Windows and Linux laptops. + +Note: the scaling feature is only meant to patch up problems on HiDPI +devices, it does not provide an all-purpose means for scaling UI elements +independent of the OS. + +This release also attempts to fix several other Windows bugs, detailed +below. The "unconfirmed" fixes section is a handful of issues that I've +never been able to reproduce, but that should now be fixed. Please +confirm at the links listed to let me know if it's working. + +This is release 3.3 instead of 3.2.5 due to the huge change to the PDE +for scaling, as well as minor API modifications (see below). + + +[ big fixes ] + ++ PDE was too small on high-res Windows and Linux machines. If you're + having trouble with this, change the "Interface scaling" option in + the Preferences window. On Windows, it will attempt to auto-detect. + https://github.com/processing/processing/issues/2411 + https://github.com/processing/processing/issues/4183 + + +[ unconfirmed fixes ] + ++ Visual artifacts on Windows 10 when using menus + https://github.com/processing/processing/issues/4700 + ++ Broken characters in the Welcome Page and the Contribution Manager + https://github.com/processing/processing/issues/4747 + ++ Add a dialog box to warn Windows users about NVIDIA driver problems + https://github.com/processing/processing/issues/4853 + ++ Blank window on startup where the "Welcome" screen should be + https://github.com/processing/processing/issues/3933 + + +[ minor fixes ] + ++ Prevent unnecessary 'file not found' errors in the console during Export + + +[ fixed earlier ] + ++ Contribution Manager does not show all libraries until filter cleared + https://github.com/processing/processing/issues/4840 + + +[ changes to core ] + ++ StringDict(TableRow) constructor to create a dictionary from a table row + ++ Allow lone double quotes in the midst of CSV strings. This improves + compatibility with spreadsheets exported from Google Sheets. + ++ Return null (rather than NullPointerException) for PApplet.trim(null) + ++ Make trim() work on column titles as well + ++ Make Table.trim() also remove unused rows and columns. This will remove + extra rows or columns at the beginning as well, since that's what trim() + does to whitespace on strings. + ++ Consume Unicode BOM (0xFEFF) in createReader() and Table parser + ++ Return null for getString(), getJSONObject(), and getJSONArray() + when key is not present, more in line w/ other API + ++ Several fixes for memory leaks from jdf + https://github.com/processing/processing/pull/4862 + https://github.com/jdf/processing.py/issues/233 + https://github.com/processing/processing/pull/4873 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.2.4 (REV 0256) - 29 January 2017 + +Just getting in as many bug fixes as we can before the end of days. + +The majority of these are from Jakub Valtar, plus a handful of other +contributors are noted below. Read all the way to the end for fun +new features. + + +[ the pde & the editor ] + ++ Detect changes to 'hosts' file in case users modify/remove localhost. + No sketch window would open after hitting Run if someone had monkeyed + with their /etc/hosts file. + https://github.com/processing/processing/issues/4738 + https://github.com/processing/processing/issues/1868 + https://github.com/processing/processing/issues/3123 + https://github.com/processing/processing/issues/4735 + ++ Ctrl-J (for debugger) is inserting newline + https://github.com/processing/processing/issues/3830 + https://github.com/processing/processing/pull/4806 + https://github.com/processing/processing/issues/4804 + ++ Spaces not handled correctly in when installing "processing-java" on macOS + https://github.com/processing/processing/issues/4779 + ++ println(int(byte(245))) throwing error + https://github.com/processing/processing/issues/4652 + https://github.com/processing/processing/pull/4744 + ++ 'web colors' next to each other fail to parse in certain situations + https://github.com/processing/processing/issues/4752 + https://github.com/processing/processing/pull/4753 + ++ Pasting code from editor to empty editor produces Exception + https://github.com/processing/processing/issues/4522 + https://github.com/processing/processing/pull/4761 + ++ possible infinite loop on modified externally + https://github.com/processing/processing/issues/3965 + https://github.com/processing/processing/pull/4762 + ++ Report missing brace in correct tab, suppress other errors until fixed + https://github.com/processing/processing/pull/4777 + ++ Improvements to sketch launching and stopping + https://github.com/processing/processing/pull/4848 + ++ Syntax highlighting issues (fixed with #4761) + https://github.com/processing/processing/issues/4286 + ++ Sketchbook window wasn't updating when sketches added, renamed, etc + https://github.com/processing/processing/issues/2944 + https://github.com/processing/processing/pull/4842 + + +[ contribution manager ] + ++ Set text style properly for Contribution Manager error message + ++ Added the remove filter feature (Akarshit) + https://github.com/processing/processing/pull/3890 + ++ Several Contribution Manager fixes + https://github.com/processing/processing/pull/4844 + ++ Add missing equals() and hashCode() to Contribution + https://github.com/processing/processing/pull/4843 + ++ Contribution Manager does not show all libraries until filter cleared + https://github.com/processing/processing/pull/4843 + https://github.com/processing/processing/issues/4840 + ++ Mode, requiring update, appears in Updates tab but not in Modes tab + https://github.com/processing/processing/issues/4822 + also fixed w/ https://github.com/processing/processing/pull/4843 + + +[ internal changes ] + ++ Only require reference.zip to be present for build + ++ Move the DEBUG flag into an external file or preferences.txt. + Replace java.util.logging code with built-in logging. + ++ Split GUI and non-GUI portions of console for earlier startup. + (Otherwise System.err/out not going to a file unless we have a GUI, + which means we couldn't debug before the GUI shows up) + ++ Fix JRE download failure during ant build due to Oracle change + https://github.com/processing/processing/issues/4823 + + +[ the core ] + ++ Write exec() documentation + https://github.com/processing/processing/issues/4740 + ++ XML fixes for getChild() producing valid XML. Add xmlns to + elements procured from getChild(), and making sure newline + is added after XML header when formatting. + ++ Adding missing docs and keywords for TableRow + https://github.com/processing/processing/pull/4333 + ++ PShape in Java2D wasn't respecting 'kind' + https://github.com/processing/processing/issues/4826 + https://github.com/processing/processing/pull/4834 + ++ Sketches still running in the background after closing + https://github.com/processing/processing/issues/4831 + (needed to allow JAVA2D to terminate when animation thread dies) + https://github.com/processing/processing/pull/4839 + + +[ closing bugs in opengl ] + ++ PShape array index out of bounds when using P3D + https://github.com/processing/processing/issues/4773 + ++ Disable modelX/Y/Z() in P2D because they don't exist in 2D + https://github.com/processing/processing/issues/4813 + ++ Fix typo in GLSL preprocessor + https://github.com/processing/processing/issues/4810 + https://github.com/processing/processing/pull/4816 + ++ Keep Windows timer resolution high for OpenGL sketches. + Prevents frame rate in OpenGL hovering around 30 instead of 60. + https://github.com/processing/processing/pull/4847 + https://github.com/processing/processing/issues/4846 + + +[ the jakubfx renderer ] + ++ FX: Prevent matrix stack overflow + https://github.com/processing/processing/pull/4799 + https://github.com/processing/processing/issues/4206 + ++ FX: Reset transform to identity before drawing background + https://github.com/processing/processing/pull/4795 + ++ FX: Implement mouse wheel event + https://github.com/processing/processing/issues/4169 + https://github.com/processing/processing/pull/4796 + ++ FX: Fix curveVertex drawing all curves together as one long curve + https://github.com/processing/processing/pull/4800 + https://github.com/processing/processing/issues/4382 + ++ FX: Add exception handler which reports exceptions from user code + https://github.com/processing/processing/pull/4798 + https://github.com/processing/processing/issues/4339 + ++ Unify mouse pressed/released events across renderers + https://github.com/processing/processing/issues/4361 + https://github.com/processing/processing/pull/4797 + + +[ new features ] + ++ Add listPaths(), listFiles() + https://github.com/processing/processing/issues/4622 + ++ Add increment() method that takes IntDict to merge another dictionary. + Calling this increment() since it doesn't make sense in practice for + the other dictionary types, even though it's technically an add(). + ++ Added Entry class for iterating StringDict, IntDict, FloatDict + ++ Added XML.print() method (prints with indent of 2) + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.2.3 (REV 0255) - 7 November 2016 + +Lots of fixes to the Contribution Manager and a couple OpenGL tweaks. + + +[ contributions manager ] + ++ If prettyVersion isn't present, just use version number + ++ Ensure that update.id is set before checking for contrib updates + ++ Clicking "Update" button in contrib manager shows non-retina version of icon + https://github.com/processing/processing/issues/4715 + Other instances of the double-size icon found, should be fixed now + ++ Fix the library reporting scripts on the server + ++ Missing version number putting 'null' in the UI + https://github.com/processing/processing-docs/issues/478 + https://github.com/processing/processing/issues/4696 + https://github.com/processing/processing/pull/4712 + ++ Major clean-ups to the Contribution Manager code + + +[ contributions to the manager ] + ++ Up-to-date status disappears after filter is removed (contributed) + https://github.com/processing/processing/issues/4084 + ++ Updates tab blank after adding, removing, updating a contribution + https://github.com/processing/processing/issues/4082 + https://github.com/processing/processing/issues/4704 + ++ Fixes the removal of redundant contribution and update related issues + https://github.com/processing/processing/pull/4086 + + +[ another fix ] + ++ Warn user to restart browser when it hangs on macOS + https://github.com/fathominfo/processing-p5js-mode/issues/4 + + +[ opengl improvements ] + ++ Automatic detection of POINT and LINE shaders fails + https://github.com/processing/processing/issues/4725 + ++ Show warning when frameRate() less than 1 is called with P2D and P3D + https://github.com/processing/processing/issues/4716 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + +PROCESSING 3.2.2 (REV 0254) - 30 October 2016 + +Lots of bug fixes. + + +[ fixes ] + ++ Find in reference for size() opens StringList.size() + https://github.com/processing/processing/issues/4224 + https://github.com/processing/processing/issues/4655 + ++ Limit rollovers on EditorStatus to the text portion. Clicking the status + area when a URL was showing was problematic because it's also the separator + used to adjust the relative size of the two panels. + ++ Switch to Java 8u111. Not using 8u112 because the build numbers are + different depending on the platform, and no 112 fixes are known useful. + ++ Errant "Could not open the URL" when clicking on error messages + https://github.com/processing/processing/issues/4695 + ++ Fix extensions handling in CFBundleDocument code from appbundler + https://github.com/processing/processing/issues/4615 + ++ Update launch4j to 3.9, fixing a problem with exported applications + on Windows reporting "This application requires a Java Runtime Environment + 1.8.0_74", when 1.8.0_101 or later were installed. + https://github.com/processing/processing/issues/4682 + ++ Minor String comparison fix for Tweak mode + https://github.com/processing/processing/issues/4670 + ++ Fix quoting problem in IntDict.toJSON() + ++ Add getRenderer() to SurfaceInfo for Andres + https://github.com/processing/processing/issues/4441 + ++ Exceptions thrown in OpenGL apps when hitting the window's close box + https://github.com/processing/processing/issues/4690 + ++ Add getRowMap() function to Table + ++ Go back to textMode(MODEL) is native font not available for textMode(SHAPE) + https://github.com/processing/processing/issues/4680 + ++ NPE thrown when using textMode(SHAPE) with a .vlw font + https://github.com/processing/processing/issues/4680 + ++ Add toJSON() method to the data classes (IntDict, FloatDict, StringDict, + IntList, FloatList, and StringList). Returns an object of one of those + six types as a JSON-formatted String. For something more like the old + toString() behavior, use print(). + + +[ gottfried's goodness ] + ++ Simplify font situation to make it possible to use vanilla JRE trees + https://github.com/processing/processing/pull/4639 + https://github.com/processing/processing/pull/4641 + ++ Updates for ARM + https://github.com/processing/processing/pull/4640 + + +[ andres can do anything ] + ++ Automatic handling of screen FBOs breaks readPixels() for user-provided FBO + https://github.com/processing/processing/issues/4643 + ++ PGraphicsOpenGL: camera info not updated + https://github.com/processing/processing/issues/4609 + ++ Fix PShape, updateTessellation, matrix transformations + https://github.com/processing/processing/issues/4662 + ++ QUAD_STRIP as child shape draws extra lines + https://github.com/processing/processing/issues/4656 + ++ Remove extra glClear() calls + https://github.com/processing/processing/issues/4694 + ++ PShapes do not show up in PDF with P2D renderer + https://github.com/processing/processing/issues/4647 + ++ Some semi-transparent edges of sphere() meshes rendered in higher density + https://github.com/processing/processing/issues/4720 + ++ P2D and P3D not stopping with empty draw() blocks + https://github.com/processing/processing/issues/4722 + + +[ other contributed fixes ] + ++ Chinese translation updates + https://github.com/processing/processing/pull/4661 + ++ Spanish translation updates + https://github.com/processing/processing/pull/4697 + ++ Spanish "open sketch folder" fix + https://github.com/processing/processing/pull/4710 + ++ Contribution Manager showing 'null' for PeasyCam version + https://github.com/processing/processing/pull/4712 + https://github.com/processing/processing/issues/4696 + ++ Call glGetProgramiv to retrieve program log length + https://github.com/processing/processing/issues/4659 + https://github.com/processing/processing/pull/4660 + ++ JSONObject get() method is private + https://github.com/processing/processing/issues/4334 + https://github.com/processing/processing/pull/4336 + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + PROCESSING 3.2.1 (REV 0253) - 19 August 2016 Fixes for a couple major bugs that showed up in the last release. @@ -5,7 +1430,7 @@ Fixes for a couple major bugs that showed up in the last release. [ fixes ] -+ "Could not replace preferences.old" error message on startup ++ "Could not replace preferences.old" error message on startup when using Processing for the first time. https://github.com/processing/processing/issues/4626 @@ -26,14 +1451,14 @@ Fixes for a couple major bugs that showed up in the last release. PROCESSING 3.2 (REV 0252) - 16 August 2016 -This release includes a handful of fixes to deal with startup bugs, +This release includes a handful of fixes to deal with startup bugs, plus several internal changes for how Modes are implemented. For those semantic versioning enthusiasts keeping track at home, the version has been bumped from 3.1.x to 3.2.x to denote the internal API changes. -[ bug fixes ] +[ bug fixes ] + Processing .jar files in CLASSPATH can cause startup crash https://github.com/processing/processing/issues/4128 @@ -69,7 +1494,7 @@ has been bumped from 3.1.x to 3.2.x to denote the internal API changes. https://github.com/processing/processing/issues/4555 https://github.com/processing/processing/pull/4547 https://github.com/processing/processing/pull/4596 - + + Error checker now adds 'public' to all default access methods https://github.com/processing/processing/pull/4597 https://github.com/processing/processing/issues/4583 @@ -106,35 +1531,35 @@ has been bumped from 3.1.x to 3.2.x to denote the internal API changes. + Move general PDE code out of JavaMode and into general base classes https://github.com/processing/processing/issues/4606 - + + Change default PdeInputHandler constructor slightly (added another copy so that older Modes will still work properly) - -+ Change PdeKeywords to PdeTokenMarker (please notify us if this + ++ Change PdeKeywords to PdeTokenMarker (please notify us if this breaks anything). + Added Mode.requireExampleCompatibility() so that Modes can specify whether example packages should specifically mention their Mode in order to be visible when that Mode is in use. -+ Mode.getTokenMarker(SketchCode code) passes through to ++ Mode.getTokenMarker(SketchCode code) passes through to no arg version if not overridden. [ input method work from Tsuyoshi Fukuda (tyfkda) ] - + + Enable input method support by default on Japanese/Korean/Chinese systems https://github.com/processing/processing/pull/4598 - + + Set text color for InputMethod https://github.com/processing/processing/pull/4593 - + + Set sketch as modified when any character committed using input method https://github.com/processing/processing/pull/4599 - + + Insert characters by InputMethod at one time https://github.com/processing/processing/pull/4594 - + + Insert string when it is committed https://github.com/processing/processing/pull/4602 @@ -147,12 +1572,12 @@ has been bumped from 3.1.x to 3.2.x to denote the internal API changes. PROCESSING 3.1.2 (REV 0251) - 29 July 2016 -Happy Fathom Fiesta Day! We'll be taking the afternoon off to enjoy -the summer, maybe you should take the afternoon off and dive into +Happy Fathom Fiesta Day! We'll be taking the afternoon off to enjoy +the summer, maybe you should take the afternoon off and dive into a new Processing release? -[ pde fixes ] +[ pde fixes ] + NullPointerException in LanguageBundle.read() on startup that prevented Processing from starting up on Windows machines. Network drive issue. @@ -160,7 +1585,7 @@ a new Processing release? https://github.com/processing/processing/pull/4582 https://github.com/processing/processing/issues/4476 -+ Bring back preference to hide the error checking. Error checking will ++ Bring back preference to hide the error checking. Error checking will continue in the background because it's needed for parsing/preprocessing, but some were complaining about the error checker messages. https://github.com/processing/processing/pull/4491 @@ -178,10 +1603,10 @@ a new Processing release? + Update to Java 8u102 build 14 -[ api fixes ] +[ api fixes ] + Rewrite CSV handling to take care of some parsing bugs and improve - performance. Note that the 'newlines' option is no longer necessary + performance. Note that the 'newlines' option is no longer necessary when loading files that contain newline characters mid-field. + Prevent random(low, high) from returning 'high' @@ -194,12 +1619,12 @@ a new Processing release? https://github.com/processing/processing/pull/4520 -[ graphics ] +[ graphics ] + Disable asynchronous saveFrame() by default. This can really improve performance, but can cause weird glitches. Bring it back by using hint(ENABLE_ASYNC_SAVEFRAME) in your code to blissfully and speedily - create image sequences. + create image sequences. https://github.com/processing/processing/issues/4578 + Prevent NPE in loadImage() when called before setup() @@ -226,11 +1651,11 @@ a new Processing release? + Add a temporary workaround for the CHIP to deal with cursor problems https://github.com/processing/processing/pull/4554 -+ Fix GLExceptions on Raspberry Pi when using offscreen PGraphics ++ Fix GLExceptions on Raspberry Pi when using offscreen PGraphics https://github.com/processing/processing/pull/4524 -[ fixed earlier ] +[ fixed earlier ] + Debugger deadlocks when choosing "Step Into" on println() https://github.com/processing/processing/issues/3923 @@ -256,7 +1681,7 @@ Happy Day-after-my-Mother-in-Law's-birthday! (After the last two releases happened on holidays, I'm just gonna keep pushing the festive thing. Hard.) Most importantly, this release fixes a handful of bug fixes for regressions -(a smart-sounding word for making dumb mistakes) in the last release, +(a smart-sounding word for making dumb mistakes) in the last release, plus a handful of other improvements we picked up along the way. @@ -271,9 +1696,9 @@ plus a handful of other improvements we picked up along the way. https://github.com/processing/processing/pull/4465 -[ the editor ] +[ the editor ] -+ Out of date Modes no longer hand Processing 3 on startup, ++ Out of date Modes no longer hand Processing 3 on startup, and will cause less trouble when changing Modes https://github.com/processing/processing/issues/4467 @@ -316,7 +1741,7 @@ plus a handful of other improvements we picked up along the way. https://github.com/processing/processing/pull/4454 -[ the core ] +[ the core ] + Implement support for encoding= option in loadTable() @@ -329,7 +1754,7 @@ plus a handful of other improvements we picked up along the way. https://github.com/processing/processing/commit/9f1d2988dc80ca7d5ee861b944cb59020ff771c5 -[ you'll never notice ] +[ you'll never notice ] + Fix 'ant clean' so that it actually... cleans. @@ -338,7 +1763,7 @@ plus a handful of other improvements we picked up along the way. https://github.com/processing/processing/issues/1492 -[ fixed but forgot to tell you ] +[ fixed but forgot to tell you ] + Complex text input issues (fixed in 3.0.2) https://github.com/processing/processing/issues/3860 @@ -354,18 +1779,18 @@ plus a handful of other improvements we picked up along the way. PROCESSING 3.1 (REV 0249) - 8 May 2016 -Happy Mother's Day! I celebrated by kicking off a Processing release +Happy Mother's Day! I celebrated by kicking off a Processing release while my beautiful wife and daughter took a well-deserved nap. -This release includes several bug fixes, while some of your donation dollars -were fed through Jakub Valtar to produce bug fixes and code improvements, -including some serious reworking of the error checker. Meanwhile, the rest -of the community pitched in with several additional fixes to keep this -caravan rolling, and Gottfried brought up the rear with fistfuls of +This release includes several bug fixes, while some of your donation dollars +were fed through Jakub Valtar to produce bug fixes and code improvements, +including some serious reworking of the error checker. Meanwhile, the rest +of the community pitched in with several additional fixes to keep this +caravan rolling, and Gottfried brought up the rear with fistfuls of improvements for Raspberry Pi and ARM support. -[ contributed pde fixes ] +[ contributed pde fixes ] + Grab bag of smaller, mainly ARM-related updates https://github.com/processing/processing/pull/4300 @@ -414,7 +1839,7 @@ improvements for Raspberry Pi and ARM support. https://github.com/processing/processing/pull/4402 -[ jakub edits the editor ] +[ jakub edits the editor ] + Update app to Java 8 https://github.com/processing/processing/pull/4383 @@ -472,7 +1897,7 @@ improvements for Raspberry Pi and ARM support. https://github.com/processing/processing/pull/4449 -[ gohaiv6 ] +[ gohaiv6 ] + Add automatic mipmap support to GLES2 https://github.com/processing/processing/pull/4416 @@ -542,11 +1967,11 @@ improvements for Raspberry Pi and ARM support. PROCESSING 3.0.2 (REV 0248) - 13 February 2016 Happy Valentine's Day! Nothing says "I LOVE YOU" like a bouquet of bug fixes. -And nothing says, "I LOVE YOU TOO" like the sampler box of contributed fixes +And nothing says, "I LOVE YOU TOO" like the sampler box of contributed fixes and pull requests that the community has put together for me since 3.0.1. -[ editor contributions ] +[ editor contributions ] + Add "full screen" option to the Editor on OS X https://github.com/processing/processing/issues/3993 @@ -555,8 +1980,8 @@ and pull requests that the community has put together for me since 3.0.1. + Add install script for site for ARM https://github.com/processing/processing/pull/4110 -+ Search/replace shouldn't include the string being replaced, - otherwise it can get into an infinite loop. ++ Search/replace shouldn't include the string being replaced, + otherwise it can get into an infinite loop. https://github.com/processing/processing/issues/4270 https://github.com/processing/processing/pull/4271 @@ -581,7 +2006,7 @@ and pull requests that the community has put together for me since 3.0.1. + Add Turkish to the list of languages https://github.com/processing/processing/pull/4073 -+ Make the error message for stack overflows clearer ++ Make the error message for stack overflows clearer https://github.com/processing/processing/pull/4152 + Get rid of dt_socket message, making command line run a little better @@ -619,16 +2044,16 @@ and pull requests that the community has put together for me since 3.0.1. https://github.com/processing/processing/issues/4105 -[ more editor ] +[ more editor ] + Move to Java 8u74, also fixes JavaFX issue. -+ Actually require OS X 10.8.5 (was set to 10.7). The Wiki said 10.8.3 - was required for 3.0 (it is), but has since been updated to 10.8.5. ++ Actually require OS X 10.8.5 (was set to 10.7). The Wiki said 10.8.3 + was required for 3.0 (it is), but has since been updated to 10.8.5. If you're gonna run Mountain Lion, at least make sure he's patched. -[ graphics contributions ] +[ graphics contributions ] + Fill out the Javadoc for PMatrix https://github.com/processing/processing/pull/4155 @@ -640,7 +2065,7 @@ and pull requests that the community has put together for me since 3.0.1. https://github.com/processing/processing/pull/4171 -[ moar graphics ] +[ moar graphics ] + Fix another "Zero length string passed to TextLayout constructor" error @@ -683,13 +2108,13 @@ and pull requests that the community has put together for me since 3.0.1. + exit() is not called in P2D/P3D https://github.com/processing/processing/issues/4156 -+ attrib*() function does not work well with PShape ++ attrib*() function does not work well with PShape https://github.com/processing/processing/issues/4048 [ "Jakub" is just Czech for "cupid" ] -+ Initialize sketch args before calling settings() ++ Initialize sketch args before calling settings() https://github.com/processing/processing/issues/4219 https://github.com/processing/processing/pull/4220 @@ -730,7 +2155,7 @@ Lots and lots of bug fixes. + curveVertex() does not work with FX2D renderer https://github.com/processing/processing/issues/3960 - + + Hide menu bar on OS X when FX2D is running full screen + Add quotes to the necessary parameters in the size() error messages @@ -739,65 +2164,65 @@ Lots and lots of bug fixes. https://github.com/processing/processing/issues/3913 https://github.com/processing/processing/pull/3999 https://github.com/processing/processing/pull/3992 - + + Add a patch for FX2D menubar not hiding, root cause not sorted out + Fix depth sorter ordering when two triangles in a plane share vertices https://github.com/processing/processing/pull/4010 - + + Turn off fixed rate scheduling in OpenGL https://github.com/processing/processing/pull/4004 - + + Fix GLSL preprocessing issues with variable name mangling https://github.com/processing/processing/pull/4052 https://github.com/processing/processing/issues/3961 https://github.com/processing/processing/issues/3968 -+ cursor() fails to work as expected with P2D/P3D ++ cursor() fails to work as expected with P2D/P3D https://github.com/processing/processing/issues/3955 - + + Topics/Shader/Convay broken https://github.com/processing/processing/issues/3947 https://github.com/processing/processing/issues/3973 - + + Regressions wrt GLES2 support between b4 and b7 https://github.com/processing/processing/issues/3976 - + + stroke glitches in P3D https://github.com/processing/processing/issues/4007 https://github.com/processing/processing/issues/4027 https://github.com/processing/processing/issues/4012 - + + Line loops incorrectly closed in P3D https://github.com/processing/processing/issues/4031 - + + pixelDensity() not working with createGraphics() and OpenGL https://github.com/processing/processing/issues/4039 - + + GL related crashes when closing the display window on Ubuntu (Intel) https://github.com/processing/processing/issues/4041 - + + GL related crashes when closing window on MacBook Air (Intel) running 10.9.5 https://github.com/processing/processing/issues/3977 + Update to JogAmp JOGL 2.3.2 https://github.com/processing/processing/issues/3979 - + + Output window cannot be set as non-resizable with the P2D or P3D renderers https://jogamp.org/bugzilla/show_bug.cgi?id=1188 https://github.com/processing/processing/issues/3952 - + + setAlwaysOnTop() does not work in P2D and P3D on Mac https://github.com/processing/processing/issues/3793 - + + P2D and P3D windows behave strangely when larger than the screen size https://github.com/processing/processing/issues/3401 - + + Remove Gluegen & JOGL sources https://github.com/processing/processing/pull/3982 -[ not graphics fixes ] +[ not graphics fixes ] + NullPointerException in ContributionManager.deleteTemp() https://github.com/processing/processing/issues/4026 @@ -805,54 +2230,54 @@ Lots and lots of bug fixes. + Tweak Mode sometimes freezes while running, require a force quit https://github.com/processing/processing/issues/3928 https://github.com/processing/processing/pull/4014 - + + Tweak Mode: Some numbers ignored in second tab https://github.com/processing/processing/issues/4017 https://github.com/processing/processing/pull/4023 - + + Update Japanese translation https://github.com/processing/processing/pull/3956 https://github.com/processing/processing/pull/3971 - + + processing-java stealing focus even with --build flag https://github.com/processing/processing/issues/3996 https://github.com/processing/processing/pull/3998 - + + Documentation updates and other serial fixes https://github.com/processing/processing/pull/4015 + Include Example packs into update count https://github.com/processing/processing/pull/3932 - + + Editor objects are staying in memory https://github.com/processing/processing/issues/3930 https://github.com/processing/processing/pull/3934 https://github.com/processing/processing/issues/3929 - + + Library path for Error Checker and Suggestions https://github.com/processing/processing/pull/3989 https://github.com/processing/processing/issues/3924 - + + A serious error occurred while trying to create a new editor window https://github.com/processing/processing/issues/3974 https://github.com/processing/processing/pull/4001 - + + Export - fix Java not being embedded on 64bit https://github.com/processing/processing/pull/4005 - + + Add error checker document listeners to all tabs https://github.com/processing/processing/pull/4009 - + + Fix memory leak in Recent menu https://github.com/processing/processing/pull/4044 - + + Error checker update (also enables switch on String objects) https://github.com/processing/processing/issues/4034 https://github.com/processing/processing/pull/4042 - + + Fix occasional exception while editing text https://github.com/processing/processing/pull/4043 - + + Prevent preprocessor from crashing when setup() has no body https://github.com/processing/processing/pull/4045 @@ -866,18 +2291,18 @@ Lots and lots of bug fixes. PROCESSING 3.0 (REV 0246) - 30 September 2015, 3pm ET -This one is huge. +This one is huge. -This document covers (in detail) the individual changes between releases. +This document covers (in detail) the individual changes between releases. For an overview abut what's new, different, and exceptional in 3.0, read: https://github.com/processing/processing/wiki/Changes-in-3.0 Most of the changes from the previous beta involve the final beautification of the GUI, and the beatification of the error checker and auto-completion -features. +features. -[ gui updates and fixes ] +[ gui updates and fixes ] + "Saving" messages never clear on "Save As" https://github.com/processing/processing/issues/3861 @@ -938,7 +2363,7 @@ features. https://github.com/processing/processing/pull/3907 -[ contribution manager ] +[ contribution manager ] + Contributions filter ignored after clicking Install https://github.com/processing/processing/issues/3826 @@ -956,7 +2381,7 @@ features. + ArrayIndexOutOfBoundsException freak out when clicking the header line -[ plumbing ] +[ plumbing ] + Fix nasty file counting problem in the change detector https://github.com/processing/processing/pull/3917 @@ -976,19 +2401,19 @@ features. PROCESSING 3.0b7 (REV 0245) - 22 September 2015 It's 8:57pm and Jakub and Ben are still holed up at Fathom's studio in Boston. -Ben is wishing he was Jakub's age, as his wrists, neck, and back all feel -like a bag of broken pretzels after several hours/days/weeks/months of coding. -A bleary-eyed Jakub emerges from deep inside the error checker and completion +Ben is wishing he was Jakub's age, as his wrists, neck, and back all feel +like a bag of broken pretzels after several hours/days/weeks/months of coding. +A bleary-eyed Jakub emerges from deep inside the error checker and completion code, removes his headphones and grunts, "I think it's working." -[ changes and additions ] +[ changes and additions ] + Changed the Tool API to pass Base instead of Editor https://github.com/processing/processing/wiki/Tool-Basics -[ error checking and auto-completion fixes ] +[ error checking and auto-completion fixes ] + Huge rewrite of auto-complete and error checking code https://github.com/processing/processing/issues/3812 @@ -1003,7 +2428,7 @@ code, removes his headphones and grunts, "I think it's working." https://github.com/processing/processing/issues/3759 https://github.com/processing/processing/pull/3848 -+ Using "new color()" instead of "color()" results in "color type detected" ++ Using "new color()" instead of "color()" results in "color type detected" https://github.com/processing/processing/issues/3739 https://github.com/processing/processing/pull/3850 @@ -1011,7 +2436,7 @@ code, removes his headphones and grunts, "I think it's working." https://github.com/processing/processing/issues/3732 -[ watcher bug fixes ] +[ watcher bug fixes ] + "Your sketch has been modified externally" with encrypted OS X volumes https://github.com/processing/processing/issues/3650 @@ -1026,12 +2451,12 @@ code, removes his headphones and grunts, "I think it's working." + Cleaning up the logic in the watcher -[ contribution manager fixes ] +[ contribution manager fixes ] + Contributions Manager UI design https://github.com/processing/processing/issues/3482 -+ CM selected tabs are too tall ++ CM selected tabs are too tall https://github.com/processing/processing/issues/3598 + CM: Clicking item in Libraries list throws exception @@ -1042,7 +2467,7 @@ code, removes his headphones and grunts, "I think it's working." + Clean up the header for the scrolling lists -+ Use real version of bold font, rather than the fake version, ++ Use real version of bold font, rather than the fake version, in several locations. + Remove the "v" from the version numbers in the updates tab @@ -1129,7 +2554,7 @@ code, removes his headphones and grunts, "I think it's working." https://github.com/processing/processing/issues/3825 https://github.com/processing/processing/commit/42c0150da0f400637de916db1f94a687a7bc4288 -+ surface.setLocation() with OpenGL causing a freeze on Windows ++ surface.setLocation() with OpenGL causing a freeze on Windows https://github.com/processing/processing/commit/4c0f9234c0a48f62363233cafc9c9951ee351d3e + selectInput/Output() is behind the drawing window (Windows) @@ -1144,25 +2569,25 @@ code, removes his headphones and grunts, "I think it's working." PROCESSING 3.0b6 (REV 0244) - 11 September 2015 -And I beheld when he had released the sixth beta, and, lo, there was -a great earthquake; and the sun became black as sackcloth of hair, +And I beheld when he had released the sixth beta, and, lo, there was +a great earthquake; and the sun became black as sackcloth of hair, and the moon became as blood. -Aside from bug fixes, the FX2D renderer has received a lot of attention. +Aside from bug fixes, the FX2D renderer has received a lot of attention. On the plus side, it's working really well. On the minus side, we're giving up on making it the default for 3.0. The underlying JavaFX technology it uses is just not ready for our use. It is, however, super fast and makes great looking 2D sketches on retina devices. But it can be a little balky so we don't want it to be the first experience that beginners have with Processing. -Especially if you're doing 2D on a retina Mac, you should definitely try FX2D. -We're at the limit of what we can do performance-wise with the default -(JAVA2D) renderer, so if you're having performance problems, try FX2D. +Especially if you're doing 2D on a retina Mac, you should definitely try FX2D. +We're at the limit of what we can do performance-wise with the default +(JAVA2D) renderer, so if you're having performance problems, try FX2D. -[ bug fixes and improvements ] +[ bug fixes and improvements ] -+ Deal with ConcurrentModificationException in Editor - "Error repainting line range" and ConcurrentModificationException ++ Deal with ConcurrentModificationException in Editor + "Error repainting line range" and ConcurrentModificationException https://github.com/processing/processing/issues/3726 + Major surgery performed to drastically reduce the memory footprint @@ -1195,7 +2620,7 @@ We're at the limit of what we can do performance-wise with the default https://github.com/processing/processing/issues/3554 + Change value of constants PRIMITIVE, PATH, and GEOMETRY constants in PShape - This avoids a collision with entries in PConstants which causes + This avoids a collision with entries in PConstants which causes confusing errors or no errors to be thrown at all https://github.com/processing/processing/issues/3776 @@ -1203,7 +2628,7 @@ We're at the limit of what we can do performance-wise with the default https://github.com/processing/processing/issues/3472 -[ Jakub won't be here forever, but his contributions are eternal ] +[ Jakub won't be here forever, but his contributions are eternal ] + Error/warning location visualisation not updating when editor resizes https://github.com/processing/processing/issues/3619 @@ -1224,7 +2649,7 @@ We're at the limit of what we can do performance-wise with the default + FX - fix rad-deg conversion in rotate() https://github.com/processing/processing/pull/3711 -+ FX - basic pixel operations (get, set, load, update) ++ FX - basic pixel operations (get, set, load, update) https://github.com/processing/processing/pull/3709 + FX - align to pixel grid when drawing 1 px strokes @@ -1282,7 +2707,7 @@ X JOGL - normalize enter key + move createFont() to PGraphics -+ Fix PShape creation in P3D ++ Fix PShape creation in P3D https://github.com/processing/processing/pull/3781 + keyTyped() not firing with P2D and P3D @@ -1294,8 +2719,8 @@ X JOGL - normalize enter key hint(ENABLE_KEY_REPEAT) will turn it back on https://github.com/processing/processing/issues/1622 -+ With the P2D and P3D renderers, a generic set of cursors are - used because the OpenGL renderer doesn't have access to the ++ With the P2D and P3D renderers, a generic set of cursors are + used because the OpenGL renderer doesn't have access to the default cursor images for each platform. https://github.com/processing/processing/issues/3791 @@ -1306,7 +2731,7 @@ X JOGL - normalize enter key https://github.com/processing/processing/issues/3720 -[ Google Summer of Contribution Manager ] +[ Google Summer of Contribution Manager ] + CM: Category dropdown alignment https://github.com/processing/processing/issues/3644 @@ -1317,7 +2742,7 @@ X JOGL - normalize enter key https://github.com/processing/processing/issues/3613 https://github.com/processing/processing/pull/3714 -+ Several of those below were in beta 5... ++ Several of those below were in beta 5... + CM - Focus is shifted out of the filter field when something is searched https://github.com/processing/processing/issues/3682 @@ -1390,9 +2815,9 @@ Fixing a handful of regressions in beta 4, and clearing out some of the nooks and crannies as people report issues with the default download. -[ changes ] +[ changes ] -+ Removed support for fixed-function pipeline in OpenGL. I'm told ++ Removed support for fixed-function pipeline in OpenGL. I'm told this "brings us out of the 90s" and gets things a bit more up-to-date and compatible across many platforms and varying device types. https://github.com/processing/processing/issues/3505 @@ -1409,7 +2834,7 @@ nooks and crannies as people report issues with the default download. https://github.com/processing/processing-docs/pull/289 -[ bug fixes ] +[ bug fixes ] + Line selected for errors is off by one or two https://github.com/processing/processing/issues/3654 @@ -1438,7 +2863,7 @@ nooks and crannies as people report issues with the default download. https://github.com/processing/processing/issues/3704 -[ foundation $$ = bug fixe$ + improvement$ ] +[ foundation $$ = bug fixe$ + improvement$ ] + keyTyped() not firing with P2D and P3D https://github.com/processing/processing/issues/3582 @@ -1469,7 +2894,7 @@ nooks and crannies as people report issues with the default download. https://github.com/processing/processing/issues/3655 -[ contributed fixes ] +[ contributed fixes ] + Undo does not move to the correct location in the editor window https://github.com/processing/processing/issues/707 @@ -1484,7 +2909,7 @@ nooks and crannies as people report issues with the default download. https://github.com/processing/processing/pull/3700 -[ google summer of code ] +[ google summer of code ] + Foundation libraries disapear from CM after restart https://github.com/processing/processing/issues/3659 @@ -1527,10 +2952,10 @@ nooks and crannies as people report issues with the default download. PROCESSING 3.0b4 (REV 0242) - 17 August 2015 -Fixes for several long-standing bugs, plus some internal changes -to make the code slightly more usable by contributors. +Fixes for several long-standing bugs, plus some internal changes +to make the code slightly more usable by contributors. -For Tool and Mode developers, several functions have moved out of +For Tool and Mode developers, several functions have moved out of processing.app.Base and into the Messages and Platform classes. For instance, Base.isWindows() has moved to Platform.isWindows() (seems almost logical, right?) We're not keeping deprecated versions @@ -1545,7 +2970,7 @@ Meanwhile, Jakub Valtar is holed up at Fathom in Boston, fixing all of the bugs. See "your contributions are funding graphics fixes," below. -[ bug fixes ] +[ bug fixes ] + Fix NullPointerException with some sketches that have no size() command https://github.com/processing/processing/issues/3585 @@ -1576,7 +3001,7 @@ the bugs. See "your contributions are funding graphics fixes," below. https://github.com/processing/processing/issues/3623 -[ api/implementation changes ] +[ api/implementation changes ] + Several platform-oriented features have moved to Platform i.e. Platform.isWindows(), Platform.openURL(), Platform.getJavaPath() @@ -1608,10 +3033,10 @@ the bugs. See "your contributions are funding graphics fixes," below. + Contribution Manager GUI updates https://github.com/processing/processing/pull/3596 - + + Sorting CM by the author name inplemented https://github.com/processing/processing/pull/3615 - + + CM needs minimum window size enforced https://github.com/processing/processing/issues/3600 https://github.com/processing/processing/pull/3607 @@ -1652,7 +3077,7 @@ the bugs. See "your contributions are funding graphics fixes," below. + Export unsaved sketch > agree to save prompt > export doesn't finish https://github.com/processing/processing/issues/2724 -+ Add disconnectEvent() to Server ++ Add disconnectEvent() to Server https://github.com/processing/processing/issues/2133 + False positive for mixing active/static mode in Tweak Mode 3.0 alpha 5 @@ -1710,7 +3135,7 @@ PROCESSING 3.0b3 (REV 0241) - 11 August 2015 You get a beta! YOU get a beta! *YOU* get a beta! Everybody gets a beta! -[ bug fixes & changes ] +[ bug fixes & changes ] + Prevent 'examples' from showing as a folder in the sketchbook window (instead only show it in the Examples window) @@ -1730,7 +3155,7 @@ You get a beta! YOU get a beta! *YOU* get a beta! Everybody gets a beta! + Library names not showing up correctly ("pdf" instead of "PDF Export") https://github.com/processing/processing/issues/3574 -+ Contributed Examples were using their folder name, not the 'name' field ++ Contributed Examples were using their folder name, not the 'name' field from their properties file when shown in the Examples window. + Include name of sketch when asking user "Save sketch before closing?" @@ -1777,7 +3202,7 @@ beta release. Please keep the reports & code coming and help us get to 3.0. + Make size(displayWidth, displayHeight) still run in a window. Fixes "fullScreen() cannot be used here" message on startup. https://github.com/processing/processing/issues/3545 - In the past we were auto-detecting if it was the screen size, + In the past we were auto-detecting if it was the screen size, and switching to full screen mode. But that's now removed because fullScreen() is so easy, and full screen may not be wanted. @@ -1789,14 +3214,14 @@ beta release. Please keep the reports & code coming and help us get to 3.0. + Remove "pair is" debug messages from Welcome screen + Save Export to Application settings between uses - + + Fix NullPointerException in setVertex() https://github.com/processing/processing/pull/3553 https://github.com/processing/processing/issues/3550 + Toggling between noLights and PointLight in draw() behaving strangely https://github.com/processing/processing/issues/3546 - + + NullPointerException in Planets demo https://github.com/processing/processing/issues/3551 @@ -1817,7 +3242,7 @@ beta release. Please keep the reports & code coming and help us get to 3.0. it would report "done exporting!" but nothing had actually happened. + Prevent Export with examples and untitled/unsaved sketches - + + Links in error bar are not selectable nor clickable https://github.com/processing/processing/issues/3471 @@ -1830,7 +3255,7 @@ beta release. Please keep the reports & code coming and help us get to 3.0. https://github.com/processing/processing/issues/3433 + Cleaned up the advanced OpenGL wiki page - + + cursor(CROSS) breaks when using surface.setTitle() https://github.com/processing/processing/issues/3472 @@ -1860,11 +3285,11 @@ an author of these, see the notes in the link above. We're also planning some sort of online Q & A / office hours / talk to Ben about what's changed session to help folks along. We want to help, we just need to find the time. -And for those into the nitty gritty, or who enjoy lame jokes about esoteric +And for those into the nitty gritty, or who enjoy lame jokes about esoteric technical details, the detailed changes since 3.0 alpha 11 are below. -[ bug fixes ] +[ bug fixes ] + The new Welcome screen! was... completely broken https://github.com/processing/processing/issues/3474 @@ -1900,7 +3325,7 @@ technical details, the detailed changes since 3.0 alpha 11 are below. https://github.com/processing/processing/pull/3514 -[ changes, because not everything is a bug ] +[ changes, because not everything is a bug ] + Add new console/errors icons to the tabs in the footer @@ -1913,7 +3338,7 @@ technical details, the detailed changes since 3.0 alpha 11 are below. is coming soon that will be better-integrated with the editor. -[ internal changes you'll probably never notice ] +[ internal changes you'll probably never notice ] + Add message that says it's safe to ignore the tools.jar warning @@ -1922,7 +3347,7 @@ technical details, the detailed changes since 3.0 alpha 11 are below. + Update to launch4j 3.8 -[ contributions by our fine community ] +[ contributions by our fine community ] + Fix contribution compatibility check https://github.com/processing/processing/pull/3479 @@ -1952,10 +3377,10 @@ technical details, the detailed changes since 3.0 alpha 11 are below. https://github.com/processing/processing/pull/3522 -[ Jakub joins Andres in a battle of wits and test of wills against OpenGL ] +[ Jakub joins Andres in a battle of wits and test of wills against OpenGL ] + Implement depth sorting! Use hint(ENABLE_DEPTH_SORT) and say goobye - to your 3D transparency woes! + to your 3D transparency woes! https://github.com/processing/processing/issues/90 https://github.com/processing/processing/issues/2235 https://github.com/processing/processing/pull/3507 @@ -2022,7 +3447,7 @@ technical details, the detailed changes since 3.0 alpha 11 are below. PROCESSING 3.0a11 (REV 0238) - 16 July 2015 -Hopefully the last release before we go to beta. +Hopefully the last release before we go to beta. [ new additions ] @@ -2040,11 +3465,11 @@ Hopefully the last release before we go to beta. Our hope is that this will be the last round of changes for the 3.x series, and that it's now safe to update your Modes and Tools to be compatible with the final 3.x release. Changes in this release: - + - Several classes have been moved to a new processing.app.ui package. The processing.app package was much too unwieldy and made it difficult for people to hack on the PDE code. - + - Several functions have moved out of Base and into Util (or Toolkit). Most of these are file-related (removeDir() and others), but the Base class had simply grown to a ridiculous size. It remains enormous @@ -2062,10 +3487,10 @@ Hopefully the last release before we go to beta. + Resize children[] so that getChildren() returns a correctly-sized array https://github.com/processing/processing/issues/3347 - + + clear() was broken (maybe related to #3317) https://github.com/processing/processing/issues/3378 - + + PGraphic ignores PNG transparency (regression from 3.0a5, same as #3378) https://github.com/processing/processing/issues/3317 @@ -2075,16 +3500,16 @@ Hopefully the last release before we go to beta. + Sketches with new fullScreen() method should grab focus by default https://github.com/processing/processing/issues/3380 - + + Sketches not getting focus with Java2D https://github.com/processing/processing/issues/3389 - + + draw() executes twice when noLoop() called in setup() https://github.com/processing/processing/issues/3310 + displayDensity() not functioning properly https://github.com/processing/processing/issues/3436 - + + surface.setXxx() handling https://github.com/processing/processing/issues/3388 Methods for setResizable(), setVisible(), setTitle(), setIconImage() @@ -2093,31 +3518,31 @@ Hopefully the last release before we go to beta. + ArithmeticException: / by zero when using fonts opened with loadFont() https://github.com/processing/processing/issues/3413 - + + SVG briefly broken for Java2D https://github.com/processing/processing/issues/3417 - + + Change how font metrics are pulled to fix text width issues + Check alpha when image extension is "unknown" https://github.com/processing/processing/issues/3442 - + + Add support for more Image types (BGR) with PImage(java.awt.Image) + Move Java2D and JavaFX classes to their own packages -[ multithreading is hard ] +[ multithreading is hard ] + Sketch not always showing with empty draw() https://github.com/processing/processing/issues/3363 - + + Static mode broken with Java2D on Windows and Linux https://github.com/processing/processing/issues/3315 - + + Sketch sometimes doesn't show with noLoop() on Linux https://github.com/processing/processing/issues/3316 - + + Window never shows with exported application on 64-bit Linux https://github.com/processing/processing/issues/3303 @@ -2128,13 +3553,13 @@ Hopefully the last release before we go to beta. + sketch.isReadOnly returns false for examples coming from multiple modes https://github.com/processing/processing/issues/773 - + + Drag and Drop & "Add File" broken for .pde files in 3.0a10 https://github.com/processing/processing/issues/3383 + Show "not compatible" error message in the manager https://github.com/processing/processing/issues/3386 - + + Add more code for handling low-level errors on startup + Update the "Supported Platforms" wiki page with current status @@ -2144,14 +3569,14 @@ Hopefully the last release before we go to beta. + Error message caused by curly bracket in a println string https://github.com/processing/processing/issues/3394 - + + Tweak mode broken (re: new settings() function) https://github.com/processing/processing/issues/3435 + Add build.xml prompt for OS X developers to download the JDK update -[ contribution manager ] +[ contribution manager ] + Change the .properties file syntax a little bit: compatibleModesList -> modes @@ -2160,7 +3585,7 @@ Hopefully the last release before we go to beta. + Send list of installed Libraries, Modes, Tools, and Examples on update https://github.com/processing/processing/issues/3365 - + + Disable contrib manager updates when "check for updates" is turned off in Preferences. Also updated the FAQ to cover the changes. @@ -2169,11 +3594,11 @@ Hopefully the last release before we go to beta. + Use correct localized strings in JavaEditor.java https://github.com/processing/processing/pull/3376 - + + Dim edit menus as appropriate during selection/no selection/etc https://github.com/processing/processing/issues/53 https://github.com/processing/processing/pull/3419 - + + Internationalize MovieMaker.java https://github.com/processing/processing/pull/3424 @@ -2183,24 +3608,24 @@ Hopefully the last release before we go to beta. + Re-enable export to application with command line https://github.com/processing/processing/pull/3451 https://github.com/processing/processing/issues/2760 - + + Change undefined constructor error message for clarity https://github.com/processing/processing/issues/3434 + Mode problems window wasn't doing line breaks https://github.com/processing/processing/issues/3369 https://github.com/processing/processing/pull/3370 - + + Add missing internationalization in app/Sketch.java https://github.com/processing/processing/pull/3392 + Examples window shows contributed examples https://github.com/processing/processing/pull/3421 https://github.com/processing/processing/pull/3421 - + + Reworking the Contribution Manager according to Scott's redesign https://github.com/processing/processing/pull/3423 - + + Finish adding 'examples' contribs https://github.com/processing/processing/issues/2953 @@ -2221,7 +3646,7 @@ Hopefully the last release before we go to beta. https://github.com/processing/processing/pull/3410 -[ retina/hidpi fixes ] +[ retina/hidpi fixes ] + Make g.pixelDensity public inside PApplet (so accessible by sketches) @@ -2232,22 +3657,22 @@ Hopefully the last release before we go to beta. + Text not getting the correct font in Retina2D https://github.com/processing/processing/issues/2617 - + + Text is half size in PGraphicsRetina2D https://github.com/processing/processing/issues/2738 -[ andres loves opengl ] +[ andres loves opengl ] + Add attrib() method https://github.com/processing/processing/issues/2963 + The ortho() function seems broken https://github.com/processing/processing/issues/1278 - + + Errors with loading SVGs in P3D/P2D https://github.com/processing/processing/issues/3379 - + + Sketch window briefly appears on top left corner when using OpenGL https://github.com/processing/processing/issues/3308 @@ -2259,16 +3684,16 @@ Hopefully the last release before we go to beta. + Sketch window is not placed at correct location when running a second time https://github.com/processing/processing/issues/3125 - + + Full screen needs to ignore prev location setting for frame? https://github.com/processing/processing/issues/3305 - + + save() and saveFrame() with 2X renderers fails https://github.com/processing/processing/issues/3255 - + + NPE when using image() created with createGraphics(PGraphicsRetina2D) https://github.com/processing/processing/issues/2510 - + + Closing OpenGL sketch from the PDE doesn't stop java.exe process https://github.com/processing/processing/issues/2335 @@ -2279,13 +3704,13 @@ Hopefully the last release before we go to beta. PROCESSING 3.0a10 (REV 0237) - 9 June 2015 Huge release! Knocking on the door for beta, this includes many changes -and improvements for how displays of all kinds (single, multiple, retina, -high dpi) are handled, plus smoothing, full screen, etc etc. +and improvements for how displays of all kinds (single, multiple, retina, +high dpi) are handled, plus smoothing, full screen, etc etc. -[ breaking things for the future ] +[ breaking things for the future ] -+ Added fullScreen() method to make it far easier to run sketches ++ Added fullScreen() method to make it far easier to run sketches using the full screen. Reference notes and explanation here: https://github.com/processing/processing-docs/issues/250 https://github.com/processing/processing/issues/3296 @@ -2297,14 +3722,14 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + Re-opened the Gates of Hell by adding chaining operations to PVector https://github.com/processing/processing/issues/257 - + + Changed exec() and open() to use varargs. Changed open() to launch() to prevent problems with Python Mode. + Replaced --full-screen command line option with --present to untangle full screen versus the "Present" command that places blanks the rest of the screen around a sketch. - + + ortho() function is being reworked to make it compliant https://github.com/processing/processing/issues/1278 @@ -2335,7 +3760,7 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + Full screen doesn't work on second window w/o present mode https://github.com/processing/processing/issues/3271 - + + Full screen on OS X 10.9 has incorrect placement https://github.com/processing/processing/issues/3305 @@ -2344,19 +3769,19 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + Comments influencing code (preproc issues in parsing) https://github.com/processing/processing/issues/3326 - + + Sketch not appearing depending on arangement of external display on OS X https://github.com/processing/processing/issues/3118 - + + Sketch launching on second display that's not currently in use https://github.com/processing/processing/issues/3082 - + + strokeWeight() in setup() not working for default renderer https://github.com/processing/processing/issues/3331 + Retain original java.awt.Frame when it's available from PSurfaceAWT -+ Set frame icon images for Java2D (dock and cmd-tab) ++ Set frame icon images for Java2D (dock and cmd-tab) https://github.com/processing/processing/issues/257 + Debug message showing up in 3.0a9 when dragging and dropping files @@ -2364,7 +3789,7 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + Rolled back to 3.0a5 version of appbundler due to crash on startup https://github.com/processing/processing/issues/3359 https://github.com/processing/processing/issues/3360 - This re-introduces a few bugs related to the serial library and + This re-introduces a few bugs related to the serial library and scrolling and any other changes later than 16 November 2015 https://github.com/processing/processing/commits/master/build/macosx/appbundler.jar https://github.com/processing/processing/commits/master/build/macosx/appbundler/native/main.m @@ -2374,39 +3799,39 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + set(0, 0, image) does not set alpha channel to opaque in P2D/P3D https://github.com/processing/processing/issues/2125 - + + GROUP shapes are broken in 3.0a9 https://github.com/processing/processing/issues/3336 - + + Only a quarter of the sketch is appearing in 2x mode https://github.com/processing/processing/issues/3332 https://github.com/processing/processing/issues/3327 - + + Single transparent pixel at end of textures in OpenGL https://github.com/processing/processing/issues/115 - + + Implement setImpl() instead of set() inside PGraphicsOpenGL https://github.com/processing/processing/issues/160 https://github.com/processing/processing/issues/3012 - + + Strange extra lines with PShape 3D https://github.com/processing/processing/issues/3006 - + + BACKSPACE key is identified as DELETE in OpenGL renderers https://github.com/processing/processing/issues/3338 -+ More key issues in OpenGL ++ More key issues in OpenGL https://github.com/processing/processing/issues/3352 + Set icon for OpenGL windows https://github.com/processing/processing/issues/3348 - + + save() and saveFrame() with OPENGL renderer fails https://github.com/processing/processing/issues/3334 - + + Errors in glsl code are only caught when set() is used https://github.com/processing/processing/issues/2268 - + + Strips when rendering spheres with lights and anti-aliasing https://github.com/processing/processing/issues/1185 @@ -2421,7 +3846,7 @@ high dpi) are handled, plus smoothing, full screen, etc etc. + Add i18n for Archiver Tool and missing text https://github.com/processing/processing/pull/3349 - + + Fix case-related bugs in Toolkit.setMenuMnemonics() https://github.com/processing/processing/pull/3366 @@ -2433,27 +3858,27 @@ high dpi) are handled, plus smoothing, full screen, etc etc. https://github.com/processing/processing/pull/3319 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a9 (REV 0236) - 19 May 2015 -More work as we head toward beta. Mostly improvements to the GUI +More work as we head toward beta. Mostly improvements to the GUI and fixes for many bugs. So close to beta I can practically smell it. -[ changes ] +[ changes ] + Implement more of the bottom half of the editor window GUI + Show screen dimensions in the Preferences window for display selector -+ Change how the variables/debug window works. Automatically ++ Change how the variables/debug window works. Automatically show the window when debugging, hide when not. https://github.com/processing/processing/issues/3298 https://github.com/processing/processing/issues/3091 -+ Enabling and disabling the debugger toggles the Step/Continue ++ Enabling and disabling the debugger toggles the Step/Continue buttons in the toolbar + Remove techie options from the Debug menu @@ -2464,7 +3889,7 @@ and fixes for many bugs. So close to beta I can practically smell it. + Lots of internal cleaning -[ bug fixes ] +[ bug fixes ] + Implement Cmd-Q handler on Mac OS X to shut down sketches properly https://github.com/processing/processing/issues/3301 @@ -2492,7 +3917,7 @@ and fixes for many bugs. So close to beta I can practically smell it. https://github.com/processing/processing/issues/3293 -[ fixed in 3.0a8, confirmed later ] +[ fixed in 3.0a8, confirmed later ] + "Step" not working properly https://github.com/processing/processing/issues/3266 @@ -2504,7 +3929,7 @@ and fixes for many bugs. So close to beta I can practically smell it. https://github.com/processing/processing/issues/3271 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a8 (REV 0235) - 17 May 2015 @@ -2518,7 +3943,7 @@ section below, for a change in how the size() command works. [ fixes ] -+ size() sometimes erratic (i.e default size used) This was often ++ size() sometimes erratic (i.e default size used) This was often seen with large setup() functions, or on more esoteric platforms. https://github.com/processing/processing/issues/1672 @@ -2528,8 +3953,8 @@ section below, for a change in how the size() command works. + Sketchbook window requires restart of Processing before updating after sketchbook location change. https://github.com/processing/processing/issues/3214 - -+ Replace & Find was reading "Find & Replace" + ++ Replace & Find was reading "Find & Replace" https://github.com/processing/processing/issues/3247 + "One file added to sketch" message when two files added @@ -2553,12 +3978,12 @@ section below, for a change in how the size() command works. setup() and is the only place where size() can be used. If using Processing without the PDE (i.e. with another IDE like Eclipse), remove the size() method from setup() and instead place it like so: - + public void settings() { size(400, 400, P3D); // your size() command here } - - The rest of your code remains unchanged. The PDE does this + + The rest of your code remains unchanged. The PDE does this transparently, so 99% of people won't even notice this change. However, it allows us to fix (and avoid) a lot of really nasty complications that come from how Processing lets you switch @@ -2573,7 +3998,7 @@ section below, for a change in how the size() command works. implementation of the settings() method is a simpler solution. + Added SVG Export library (works like PDF Export). This has not - been tested heavily yet. + been tested heavily yet. + Replace Tweak Mode ColorSelector with JComponent version https://github.com/processing/processing/issues/3209 @@ -2597,8 +4022,8 @@ section below, for a change in how the size() command works. thiList.append(value); } -+ Inside main(), don't set 'args' to a zero-length array if no args - were passed in, instead leave 'args' null. ++ Inside main(), don't set 'args' to a zero-length array if no args + were passed in, instead leave 'args' null. [ debugger ] @@ -2608,10 +4033,10 @@ section below, for a change in how the size() command works. + Change "method" to "function" in a few error messages https://github.com/processing/processing/issues/3225 - + + Error message for incorrect function arguments is wonky https://github.com/processing/processing/issues/3268 - + + String concatenation mistakes produce odd error messages https://github.com/processing/processing/issues/3253 @@ -2621,7 +4046,7 @@ section below, for a change in how the size() command works. + Window size not passing into Tweak Mode https://github.com/processing/processing/issues/3208 https://github.com/processing/processing/pull/3227 - + + Keep the tab menu at the right-hand side https://github.com/processing/processing/pull/3236 @@ -2630,7 +4055,7 @@ section below, for a change in how the size() command works. + Prevent breakpoints from causing a reload prompt https://github.com/processing/processing/pull/3263 - + + Added buffer to file detection time https://github.com/processing/processing/pull/3262 @@ -2640,15 +4065,15 @@ section below, for a change in how the size() command works. + Preferences window fixes for Linux https://github.com/processing/processing/pull/3232 https://github.com/processing/processing/issues/3231 - + + Clear error message in Contribution Manager after retrying https://github.com/processing/processing/pull/3240 https://github.com/processing/processing/issues/3239 - + + Add SOCKS proxy support to the PDE https://github.com/processing/processing/issues/2643 https://github.com/processing/processing/pull/3260 - + + Use system proxy by default https://github.com/processing/processing/issues/1476 https://github.com/processing/processing/pull/3251 @@ -2661,18 +4086,18 @@ section below, for a change in how the size() command works. + OpenGL sketches work only after running a sketch with default renderer https://github.com/processing/processing/issues/3218 - + + static mode - no setup() / draw() - broken in OpenGL https://github.com/processing/processing/issues/3163 - + + Deal with some performance issues https://github.com/processing/processing/issues/3210 - + + Can't run sketches with offscreen PGraphics https://github.com/processing/processing/issues/3259 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a7 (REV 0234) - 26 April 2015 @@ -2681,7 +4106,7 @@ Read the notes in 3.0a6 for major changes! This is only a minor bug fix release to take care of a few things that were broken in 3.0a6. -[ fixes ] +[ fixes ] + Fix bug that prevented the Preferences window from opening https://github.com/processing/processing/issues/3215 @@ -2701,9 +4126,9 @@ release to take care of a few things that were broken in 3.0a6. + Avoid minor memory leak in StringList.pop() -[ known issues ] +[ known issues ] -+ OpenGL sketches work on Windows (32- and 64-bit) only after running ++ OpenGL sketches work on Windows (32- and 64-bit) only after running a sketch that uses the default renderer https://github.com/processing/processing/issues/3218 @@ -2714,14 +4139,14 @@ release to take care of a few things that were broken in 3.0a6. https://github.com/processing/processing/issues?q=is%3Aopen+label%3Ahigh+-label%3Aenhancement -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a6 (REV 0233) - 25 April 2015 This is the big one! We've jettisoned PApplet as the base class so that we can improve performance, reduce flicker, and have a better base from -which to build better, more modern graphics rendering. More of the +which to build better, more modern graphics rendering. More of the gory details for the PApplet/PGraphics changes can be found here: https://github.com/processing/processing/tree/master/core @@ -2730,26 +4155,26 @@ https://github.com/processing/processing/issues/3072 and that means all Modes and some Tools will need to be updated: https://github.com/processing/processing/issues/3080 -We've also made major changes to better integrate PDE X, Tweak Mode, +We've also made major changes to better integrate PDE X, Tweak Mode, and other nice features for the default "Java" Mode. These will be the -center of the changes for 3.x, which is focused on improving the editing -and debugging experience in general. +center of the changes for 3.x, which is focused on improving the editing +and debugging experience in general. Suffice to say, this is truly an ALPHA quality release. We're pushing it out so that we can get more people testing it. If you want something more -stable, we recommend 3.0a5 (not 2.2.1, that thing is old!) +stable, we recommend 3.0a5 (not 2.2.1, that thing is old!) Library/Mode/Tool authors: Please help us get 3.0 ready by getting your code ready for 3.0! Because 2.x and 3.x contributions are separate, you -can maintain separate versions if you like (or only support 3.x). You -can also specify the earliest and latest revisions of Processing that -your code supports, so that it's only installed with the correct version. +can maintain separate versions if you like (or only support 3.x). You +can also specify the earliest and latest revisions of Processing that +your code supports, so that it's only installed with the correct version. If anything is unclear, please file an issue. I've not had time to write up all the changes yet (and some are still in progress), but what you see in this release is representative of where we're headed for 3.0. -[ known issues ] +[ known issues ] The full list is here: https://github.com/processing/processing/issues/ but a few that you might be likely to run across: @@ -2764,11 +4189,11 @@ but a few that you might be likely to run across: https://github.com/processing/processing/issues/3125 -[ general fixes and changes ] +[ general fixes and changes ] + Merge experimental into the main Java mode, move Java Mode to its own area -+ Deal with ctrl-alt-n regression ++ Deal with ctrl-alt-n regression https://github.com/processing/processing/issues/2979 + Don't add a ^M to files when writing @@ -2832,7 +4257,7 @@ but a few that you might be likely to run across: https://github.com/processing/processing/pull/2922 -[ who loves pull requests? I do. ] +[ who loves pull requests? I do. ] + Splash screen for Linux https://github.com/processing/processing/pull/3005 @@ -2914,7 +4339,7 @@ but a few that you might be likely to run across: + Fix ColorChooser cursor https://github.com/processing/processing/pull/3186 -+ Improve Spanish localization ++ Improve Spanish localization https://github.com/processing/processing/pull/3185 + Internationalization of editor error messages and Greek translations @@ -3008,13 +4433,13 @@ but a few that you might be likely to run across: https://github.com/processing/processing/pull/3102 -[ processing.core ] +[ processing.core ] -+ Remove Applet as the base class. ++ Remove Applet as the base class. https://github.com/processing/processing/tree/master/core + Replaced JOGL with LWJGL. Ongoing JOGL support is unclear and LWJGL - seems to be more consistently maintained. Unfortunately, it trades + seems to be more consistently maintained. Unfortunately, it trades one set of quirks for another. + Renamed 2x (hidpi/retina) versions of renderers to JAVA2D_2X, P3D_2X, etc. @@ -3040,7 +4465,7 @@ but a few that you might be likely to run across: https://github.com/processing/processing/issues/2925 -[ more contributions! ] +[ more contributions! ] + saveFrame() doesn't save opaque PNG files https://github.com/processing/processing/issues/3031 @@ -3065,7 +4490,7 @@ but a few that you might be likely to run across: https://github.com/processing/processing/issues/3114 -[ processing.data ] +[ processing.data ] + Ensure # of columns and titles lines up with Table(iterator) constructor @@ -3084,11 +4509,11 @@ but a few that you might be likely to run across: [ sketch ] -+ Added E2D, an experimental/enhanced renderer that draws directly - to the Graphics context without an intermediate image. This greatly - speeds up performance (especially on retina/hidpi displays), but - prevents pixel access (no save(), saveFrame(), loadPixels(), etc). - It also causes some rendering hiccups (frame rate is not as smooth), ++ Added E2D, an experimental/enhanced renderer that draws directly + to the Graphics context without an intermediate image. This greatly + speeds up performance (especially on retina/hidpi displays), but + prevents pixel access (no save(), saveFrame(), loadPixels(), etc). + It also causes some rendering hiccups (frame rate is not as smooth), but that's why it's experimental. + Remove isGL(), is2D(), is3D(), displayable() from PApplet @@ -3121,27 +4546,27 @@ but a few that you might be likely to run across: https://github.com/processing/processing/issues/2641 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a5 (REV 0232) - 16 November 2014 -Hello from the University of Denver! I'm here with Casey, Dan, Andres, -and Manindra working on 3.0. Chris Coleman and Laleh Mehran have been +Hello from the University of Denver! I'm here with Casey, Dan, Andres, +and Manindra working on 3.0. Chris Coleman and Laleh Mehran have been hosting us on behalf of the EDP program. It all looks a bit like this: https://twitter.com/digitalcoleman/status/533784122179596288 [ changes ] -+ Removed the sound library. It's now available as its own library ++ Removed the sound library. It's now available as its own library from the Library Manager. + Change how languages are loaded, adding a local override. + Update to use JRE/JDK 7u72 -+ Implement the active() method for Serial and Server ++ Implement the active() method for Serial and Server https://github.com/processing/processing/issues/2364 https://github.com/processing/processing/pull/2588 @@ -3172,7 +4597,7 @@ https://twitter.com/digitalcoleman/status/533784122179596288 [ bug fixes ] -+ Remove debug message printed to the console when the control key ++ Remove debug message printed to the console when the control key is pressed, when using the new editor. + size(640,360 , P3D) doesn't work properly (strange spacing) @@ -3193,7 +4618,7 @@ https://twitter.com/digitalcoleman/status/533784122179596288 https://github.com/processing/processing/issues/2930 -[ contributed fixes ] +[ contributed fixes ] + Cmd + H runs sketch instead of hiding the PDE (OS X) https://github.com/processing/processing/issues/2881 @@ -3292,7 +4717,7 @@ https://twitter.com/digitalcoleman/status/533784122179596288 https://github.com/processing/processing/pull/2958 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a4 (REV 0231) - 12 September 2014 @@ -3302,17 +4727,17 @@ The next alpha release will contain major changes and break a few libraries and tools, so this is an attempt at a final "stable" alpha that can be used until all those issues are sorted out. -[ changes ] +[ changes ] + Contributions (Libraries, Modes, Tools) are now read from their own listing that's specific to Processing 3. https://github.com/processing/processing/issues/2850 https://github.com/processing/processing/issues/2849 -+ Made the new editor the default. ++ Made the new editor the default. + The OS X default File menu (shown when no windows are open) now has the - order/naming changes found in the sketch window File menu. + order/naming changes found in the sketch window File menu. + Turning off file watching because of errant "this sketch has changed" messages. Hopefully this will return soon. @@ -3321,7 +4746,7 @@ until all those issues are sorted out. + Turned off code completion by default and reset its preference name. -[ bug fixes ] +[ bug fixes ] + TGAs from saveFrame() create transparent/black movies with Movie Maker https://github.com/processing/processing/issues/2851 @@ -3338,7 +4763,7 @@ until all those issues are sorted out. https://github.com/processing/processing/issues/2831 -[ internal tweaks ] +[ internal tweaks ] + Optimize creation of boxed primitives https://github.com/processing/processing/pull/2826 @@ -3350,14 +4775,14 @@ until all those issues are sorted out. https://github.com/processing/processing/pull/2844 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a3 (REV 0230) - 26 August 2014 -The 3.0 process continues as we've wrapped up a very successful +The 3.0 process continues as we've wrapped up a very successful Google Summer of Code, and have also been integrating contributions -(internationalization!) from some helpful community members. +(internationalization!) from some helpful community members. In particular, Jakub Valtar, Darius M, and Frederico Bond are my heroes: https://github.com/processing/processing/commits/master?author=jakubvaltar @@ -3375,7 +4800,7 @@ https://github.com/processing/processing/commits/master?author=voidplus [ fixes and updates ] -+ The sound library is now available for 64-bit Windows and Linux. ++ The sound library is now available for 64-bit Windows and Linux. 32-bit versions are still in the works. + Don't write sketch.properties unless it's a non-default mode @@ -3520,7 +4945,7 @@ https://github.com/processing/processing/commits/master?author=voidplus + Call applet.exit() instead of System.exit() from Present Mode's 'stop' https://github.com/processing/processing/pull/2680 - + + Drawing RECT PShape with rounded corners crashes the sketch https://github.com/processing/processing/issues/2648 @@ -3540,7 +4965,7 @@ https://github.com/processing/processing/commits/master?author=voidplus https://github.com/processing/processing/issues/2679 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a2 (REV 0229) - 31 July 2014 @@ -3548,25 +4973,25 @@ PROCESSING 3.0a2 (REV 0229) - 31 July 2014 The 3.0 train gains steam and continues to hurtle down the track. -[ changes ] +[ changes ] + Added a new sketchbook location, so that you can have separate sketchbooks - with 2.0 and 3.0 releases. The downside is that they won't stay in sync, + with 2.0 and 3.0 releases. The downside is that they won't stay in sync, but the upside is that sketches that haven't been updated, or conflicting - Libraries, Modes, or Tools won't cause trouble with the other version. + Libraries, Modes, or Tools won't cause trouble with the other version. The new preference is called sketchbook.location.three (the old preference was sketchbook.location). If you already have a 2.0 sketchbook, that will be used by default with 3.0 until you change it in the Preferences window. + Neglected to mention with the previous release that the video library has been removed from the default download. This decreases the size of the - Processing download by about 20%. In addition, it was only the video + Processing download by about 20%. In addition, it was only the video library for the platform being downloaded, and with the return of cross- platform application export, that could cause sadness. To use the video library, use the "Add Library..." menu and select it from the list. + Added a new preference for the 3.0 sketchbook location, so that a separate - sketchbook (and with it, different Modes, Tools, and Libraries) can be + sketchbook (and with it, different Modes, Tools, and Libraries) can be used with Processing 3.0 versus older versions of 2.x. + Remove default menu bar hack for OS X @@ -3574,11 +4999,11 @@ The 3.0 train gains steam and continues to hurtle down the track. + Move to native OS X full screen (supported in 10.7 and later) https://github.com/processing/processing/issues/2641 - This allows us to remove native code for hiding the menu bar. + This allows us to remove native code for hiding the menu bar. But it may introduce more quirks, we'll have to test it out. -[ fixes ] +[ fixes ] + The Examples weren't included in 3.0a1. Oops. https://github.com/processing/processing/issues/2652 @@ -3607,7 +5032,7 @@ The 3.0 train gains steam and continues to hurtle down the track. https://github.com/processing/processing/issues/2208 -[ the data classes ] +[ the data classes ] + Add copy() method to Table @@ -3652,12 +5077,12 @@ X Fixed issue where the browser wasn't opening the reference properly https://github.com/processing/processing/pull/2657 -[ you request, we pull ] +[ you request, we pull ] + Insert tabs properly when prefs set for tabs mode https://github.com/processing/processing/pull/2607 -+ Improve the appearance when using the Nimbus LAF ++ Improve the appearance when using the Nimbus LAF https://github.com/processing/processing/pull/2671 + Implement A and a (elliptical arcs) @@ -3674,7 +5099,7 @@ X Fixed issue where the browser wasn't opening the reference properly https://github.com/processing/processing/pull/2324 -[ fixed in earlier releases ] +[ fixed in earlier releases ] + maxHeapSize typo in the build scripts https://github.com/processing/processing/issues/2603 @@ -3696,7 +5121,7 @@ X Fixed issue where the browser wasn't opening the reference properly https://github.com/processing/processing/issues/5 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 3.0a1 (REV 0228) - 26 July 2014 @@ -3705,14 +5130,14 @@ Kicking off the 3.0 release process. The focus for Processing 3 is improving the editor and the coding process, so we'll be integrating what was formerly PDE X as the main editor. -This release also includes a number of bug fixes and changes, based on +This release also includes a number of bug fixes and changes, based on in-progress Google Summer of Code projects and a few helpful souls on Github. Please contribute to the Processing 3 release by testing and reporting bugs. Or better yet, helping us fix them and submitting pull requests. -[ contributed fixes! ] +[ contributed fixes! ] + Fix blendMode() problems in the default renderer (thanks Jakub Valtar!) https://github.com/processing/processing/issues/2012 @@ -3743,7 +5168,7 @@ Or better yet, helping us fix them and submitting pull requests. https://github.com/processing/processing/issues/2630 -[ summer of code ] +[ summer of code ] + Line coloring incorrect for filtered contribution listings https://github.com/processing/processing/issues/2583 @@ -3767,7 +5192,7 @@ Or better yet, helping us fix them and submitting pull requests. + Add preference to set the present color https://github.com/processing/processing/pull/2568 -+ Fix a problem where mode menu selection would change even if ++ Fix a problem where mode menu selection would change even if the change was canceled due to the sketch being modified https://github.com/processing/processing/issues/2615 @@ -3775,12 +5200,12 @@ Or better yet, helping us fix them and submitting pull requests. https://github.com/processing/processing/pull/2651 -[ more bug fixes ] +[ more bug fixes ] + Prevent the current Mode from being de-selected https://github.com/processing/processing/issues/2545 -+ Prevent ArrayIndexOutOfBoundsException when calling min/maxValue() ++ Prevent ArrayIndexOutOfBoundsException when calling min/maxValue() on a FloatDict that only contains NaN values + Last row was being skipped on tables with the 'newlines' option set @@ -3797,10 +5222,10 @@ Or better yet, helping us fix them and submitting pull requests. Formerly, this was throwing a NullPointerException. -[ changes ] +[ changes ] + A new sound library has been added, and Minim has been removed. Minim - will now available via the Contributions Manager. + will now available via the Contributions Manager. + Add copy() method to PVector @@ -3809,13 +5234,13 @@ Or better yet, helping us fix them and submitting pull requests. + add getColumnTitle(int) and getColumnTitles() to TableRow interface -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.2.1 (REV 0227) - 19 May 2014 A handful of bug fixes, the most prominent rolls back a change that broke -PDE X and other Modes and Tools. +PDE X and other Modes and Tools. + Bring back setIcon(Frame) for PDE X and others https://github.com/processing/processing-experimental/issues/64 @@ -3823,7 +5248,7 @@ PDE X and other Modes and Tools. + Add additional code for crashing when the Mode is changed or new editor windows opened. -+ Use mouseReleased() instead of mousePressed() in the color selector, ++ Use mouseReleased() instead of mousePressed() in the color selector, otherwise it registers the release as a click in the color window https://github.com/processing/processing/issues/2514 @@ -3853,7 +5278,7 @@ PDE X and other Modes and Tools. + Updated reference files included in the download. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.2 (REV 0226) - 12 May 2014 @@ -3862,7 +5287,7 @@ Major changes to, and improvements upon, how "Export to Application" works. Plus dozens of bug fixes for all manner of atrocities. -[ bug fixes and additions ] +[ bug fixes and additions ] + Sketches only starting once, or half-starting and hanging on Mac OS X. A major problem on OS X, thanks to David Fokkema for tracking down a fix. @@ -3908,7 +5333,7 @@ Plus dozens of bug fixes for all manner of atrocities. [ export to application ] + The return of multi-platform export! Create applications for Windows - and Linux while using OS X. Create a Linux application from Windows. + and Linux while using OS X. Create a Linux application from Windows. Against my better judgement, we're supporting it again. It's extremely difficult, but was disappointing to remove it earlier. @@ -3916,7 +5341,7 @@ Plus dozens of bug fixes for all manner of atrocities. https://github.com/processing/processing/issues/2349 + Change Windows export to use launch4j instead of our custom launcher. - This will fix many, many problems, but may introduce some new ones. + This will fix many, many problems, but may introduce some new ones. + Windows (64-bit) now creates a proper .exe instead of a .bat file https://github.com/processing/processing/issues/923 @@ -3957,7 +5382,7 @@ Plus dozens of bug fixes for all manner of atrocities. + Bug in relative moveto commands for SVG https://github.com/processing/processing/issues/2377 -+ Add a constructor to bind Server to a specific address ++ Add a constructor to bind Server to a specific address https://github.com/processing/processing/issues/2356 + Fonts from loadFont() show up as blocks in P3D (regression) @@ -3967,16 +5392,16 @@ Plus dozens of bug fixes for all manner of atrocities. https://github.com/processing/processing/issues/2493 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.1.2 (REV 0225) - 15 April 2014 -Lots of small bug fixes plus some additional changes to support +Lots of small bug fixes plus some additional changes to support the new Python Mode, coming soon: https://github.com/jdf/processing.py -[ the pde ] +[ the pde ] + The PDE was using 15% of CPU while just sitting idle. Thanks to David Fokkema for the fix (and pull request). @@ -4003,7 +5428,7 @@ the new Python Mode, coming soon: https://github.com/jdf/processing.py https://github.com/processing/processing/issues/2453 -[ the core ] +[ the core ] + sketchPath() was returning user.home in exported apps on OS X https://github.com/processing/processing/issues/2181 @@ -4018,15 +5443,15 @@ the new Python Mode, coming soon: https://github.com/jdf/processing.py + PGraphics.colorCalcARGB(int, float) wasn't properly capping alpha values https://github.com/processing/processing/issues/2439 -+ Make sure that the window background color isn't the same as the default - sketch background color (otherwise the sketch area isn't clear). ++ Make sure that the window background color isn't the same as the default + sketch background color (otherwise the sketch area isn't clear). https://github.com/processing/processing/issues/2297 + Fix for occasional NullPointerException in paint() https://github.com/processing/processing/issues/2354 -[ andres vs opengl, episode 225 ] +[ andres vs opengl, episode 225 ] + copy() under OPENGL uses upside-down coordinates for cropping https://github.com/processing/processing/issues/2345 @@ -4060,7 +5485,7 @@ the new Python Mode, coming soon: https://github.com/jdf/processing.py https://github.com/processing/processing/issues/2424 -[ fixed in earlier releases ] +[ fixed in earlier releases ] + draw() called again before finishing on OS X (retina issue) https://github.com/processing/processing/issues/1709 @@ -4072,7 +5497,7 @@ the new Python Mode, coming soon: https://github.com/jdf/processing.py https://github.com/processing/processing/issues/2252 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.1.1 (REV 0224) - 21 January 2014 @@ -4096,7 +5521,7 @@ Still a number of known issues, but this cleans up several of the biggies. https://github.com/processing/processing/issues/2202 -[ windows ] +[ windows ] + Export to Application was broken on Windows https://github.com/processing/processing/issues/2219 @@ -4142,7 +5567,7 @@ Still a number of known issues, but this cleans up several of the biggies. https://github.com/processing/processing/pull/2266 -[ core fixes ] +[ core fixes ] + PImage resize() causes PImage not to be rendered in JAVA2D https://github.com/processing/processing/issues/2179 @@ -4189,24 +5614,24 @@ Still a number of known issues, but this cleans up several of the biggies. https://github.com/processing/processing/issues/2233 -[ missing in the 2.1 release notes ] +[ missing in the 2.1 release notes ] -+ init() not called on tools until later ++ init() not called on tools until later https://github.com/processing/processing/issues/1859 + Finish changes so the PDE can use an unmodified JRE https://github.com/processing/processing/issues/1840 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.1 (REV 0223) - 27 October 2013 -There have been major changes since 2.0.3, most of them are outlined in +There have been major changes since 2.0.3, most of them are outlined in the release notes for 2.1 beta 1 (look down a few dozen lines). -This release includes a few updates to fix problems introduced in the beta +This release includes a few updates to fix problems introduced in the beta release, as well as additional general bug fixes, especially for OpenGL. + Added an option to not embed the Java runtime into an exported application. @@ -4214,8 +5639,8 @@ release, as well as additional general bug fixes, especially for OpenGL. Java 7u45 or later. Details on the same page that nobody read last time: http://wiki.processing.org/w/Export_Info_and_Tips -+ The new println() (see the beta 1 notes) makes some old code behave a - little differently. In the past, println() with an array would write ++ The new println() (see the beta 1 notes) makes some old code behave a + little differently. In the past, println() with an array would write out the array, one element per line, with the index in the front. i.e.: PFont.list()) would write something like this to the console: @@ -4232,18 +5657,18 @@ release, as well as additional general bug fixes, especially for OpenGL. Serif SansSerif Monospaced Dialog DialogInput ACaslonPro-Bold... - To get the old behavior, use printArray(). It's the price of progress, + To get the old behavior, use printArray(). It's the price of progress, and shouldn't really "break" anyone's code since it's just writing to the - console. We think the new syntax outweighs the downside of the change. + console. We think the new syntax outweighs the downside of the change. With arrays of primitive types (int[], float[], anything that's not an object), we've added code so that println() works as before. But we - can't do the same for arrays of objects, such as String. + can't do the same for arrays of objects, such as String. + The preference for font smoothing (anti-aliasing) in the editor has been - reset in this release. Fonts are unusably gross on OS X (and Linux) + reset in this release. Fonts are unusably gross on OS X (and Linux) without smoothing and Oracle's version of Java (now in use with 2.1), - and many longtime users have anti-aliasing turned off. You can still + and many longtime users have anti-aliasing turned off. You can still turn off smoothing in the Preferences window, but the results may be poor. https://github.com/processing/processing/issues/2164 https://github.com/processing/processing/issues/2160 @@ -4266,7 +5691,7 @@ release, as well as additional general bug fixes, especially for OpenGL. https://github.com/processing/processing/issues/2135 -[ OpenGL updates ] +[ OpenGL updates ] + Using sketchQuality() does not work properly with P3D, OPENGL, P2D https://github.com/processing/processing/pull/2157 @@ -4299,21 +5724,21 @@ release, as well as additional general bug fixes, especially for OpenGL. https://github.com/processing/processing/commit/cca2f08a24ef892c494f5a75aa0e4b01de7e5d8a -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.1 beta 1 (REV 0222) - 20 October 2013 This release contains major changes. The big ones: -+ Java 7 is now used across all platforms. On Mac OS X, ++ Java 7 is now used across all platforms. On Mac OS X, we're now embedding Java 7u45. More info here: http://wiki.processing.org/w/Supported_Platforms#Java_Versions -+ Major changes have been made to Export to Application. ++ Major changes have been made to Export to Application. Read here: http://wiki.processing.org/w/Export_Info_and_Tips -+ print() and println() now make debugging fun! They can now take any ++ print() and println() now make debugging fun! They can now take any number of parameters, which means that code like: println(x, y, mouseX, mouseY); will print out @@ -4324,13 +5749,13 @@ This release contains major changes. The big ones: + A new serial library has been added! The results of Gottfried Haider's Google Summer of Code project now replaces the old serial library. -And everyone should wish Casey Reas happy birthday today! +And everyone should wish Casey Reas happy birthday today! This release is my birthday present for him. What did you get him? Here's a more detailed rundown of what else is in this release: -[ new features and additions ] +[ new features and additions ] + For people using Eclipse, the new print() and println() methods add some quirks because of how println() works for arrays in previous @@ -4341,9 +5766,9 @@ Here's a more detailed rundown of what else is in this release: https://github.com/processing/processing/issues/2056 + Update the JavaDoc, remove java.* package prefix ugliness. Also link - out to the online version of the Oracle documentation. + out to the online version of the Oracle documentation. -+ Major work on the source and the build scripts as we completed the ++ Major work on the source and the build scripts as we completed the transition to Java 7, and away from Apple's deprecated Java 6. http://wiki.processing.org/w/Supported_Platforms#Mac_OS_X @@ -4356,7 +5781,7 @@ Here's a more detailed rundown of what else is in this release: + Remove unused/outdated 'Mangler' Tool example -+ Remove video library for other platforms in download. This saves ++ Remove video library for other platforms in download. This saves significant space because we're not doing cross-platform export anymore. + Update apple.jar file with new version @@ -4376,7 +5801,7 @@ Here's a more detailed rundown of what else is in this release: Java 7 on OS X only supports 64-bit, so 32-bit is no longer available. -[ editor fixes ] +[ editor fixes ] + Deal with null/missing folders for Tools and Modes https://github.com/processing/processing/issues/2068 @@ -4416,8 +5841,8 @@ Here's a more detailed rundown of what else is in this release: + Java2D images crash after being resized https://github.com/processing/processing/issues/2113 -+ Constrain lerpColor() between 0 and 1. Unlike lerp(), where it might - make mathematical sense, going outside the boundary colors produces ++ Constrain lerpColor() between 0 and 1. Unlike lerp(), where it might + make mathematical sense, going outside the boundary colors produces really messy results. + JSONObject/Array.format(-1) not working on embedded JSONObjects @@ -4463,7 +5888,7 @@ Here's a more detailed rundown of what else is in this release: https://github.com/processing/processing/issues/2151 -[ new serial library ] +[ new serial library ] + Incorporate the new serial library. Woohoo! https://github.com/processing/processing/pull/2093 @@ -4481,9 +5906,9 @@ Here's a more detailed rundown of what else is in this release: https://github.com/processing/processing/issues/1374 -[ font fixes and changes ] +[ font fixes and changes ] -+ Add ability to change the editor (and console) font from a menu ++ Add ability to change the editor (and console) font from a menu in the Preferences window. https://github.com/processing/processing/issues/2078 @@ -4493,9 +5918,9 @@ Here's a more detailed rundown of what else is in this release: + Allow editor and console font changes without restart. -+ Anti-aliasing fix for the editor line status. ++ Anti-aliasing fix for the editor line status. -+ Change to bold instead of semibold version of Source Code Pro. ++ Change to bold instead of semibold version of Source Code Pro. The semibold wasn't mapping properly as the same family. + Use the same font in the console as the editor. @@ -4516,12 +5941,12 @@ Here's a more detailed rundown of what else is in this release: + Add support for many other image file types to Movie Maker -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0.3 (REV 0221) - 5 September 2013 -Lots of bug fixes, primarily a ton of work by Andres to improve +Lots of bug fixes, primarily a ton of work by Andres to improve OpenGL rendering with P2D and P3D. @@ -4530,7 +5955,7 @@ OpenGL rendering with P2D and P3D. + blendMode() change causes OpenGL renderer to be very slow https://github.com/processing/processing/issues/2021 -+ Serious OpenGL performance issues on OS X, this was fixed ++ Serious OpenGL performance issues on OS X, this was fixed with the JOGL update in 2.0.2, but we neglected to note it. https://github.com/processing/processing/issues/1714 @@ -4585,7 +6010,7 @@ OpenGL rendering with P2D and P3D. https://github.com/processing/processing/issues/2061 -[ other bug fixes ] +[ other bug fixes ] + Fix options parsing on loadTable() to handle spaces. @@ -4594,18 +6019,18 @@ OpenGL rendering with P2D and P3D. https://github.com/processing/processing/pull/2046 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0.2 (REV 0220) - 14 August 2013 -Many small bug fixes and lots of work on the Library/Tool/Mode Manager. +Many small bug fixes and lots of work on the Library/Tool/Mode Manager. Full screen is back for Windows, and lots more. -[ bug fixes ] +[ bug fixes ] -+ Fix Windows issues with associating .pde files ++ Fix Windows issues with associating .pde files https://github.com/processing/processing/issues/286 http://code.google.com/p/processing/issues/detail?id=247 @@ -4621,7 +6046,7 @@ Full screen is back for Windows, and lots more. + Setting an INT4 uniform in PShader causes an out of bounds exception https://github.com/processing/processing/issues/1994 -+ Fix "less less" typo ++ Fix "less less" typo https://github.com/processing/processing/issues/1928 + Slash breaks syntax highlighting when spaces are involved @@ -4648,7 +6073,7 @@ Full screen is back for Windows, and lots more. https://github.com/processing/processing/issues/1962 -[ contribution managers ] +[ contribution managers ] + Support multiple categories for libraries https://github.com/processing/processing/issues/1970 @@ -4663,7 +6088,7 @@ Full screen is back for Windows, and lots more. + Restrict library categories to the ones in the document. If it's not correct, shows up as 'other'. -+ Catch Errors (not just Exceptions) when loading libraries, modes, ++ Catch Errors (not just Exceptions) when loading libraries, modes, and tools. Handles UnsupportedClassVersionError and other quirks. + Redo handling of "old" versions of contributions. @@ -4673,7 +6098,7 @@ Full screen is back for Windows, and lots more. https://github.com/processing/processing/pull/1925 -[ data, data, data ] +[ data, data, data ] + Error in IntList and FloatList insert() https://github.com/processing/processing/issues/1929 @@ -4692,7 +6117,7 @@ Full screen is back for Windows, and lots more. https://github.com/processing/processing/issues/1893 + When using increment() on IntList, make sure the index exists and - automatically resize the list if necessary. This is more in keeping + automatically resize the list if necessary. This is more in keeping with increment() in the Dict classes. + getSubset() broken in IntList, StringList, and missing from FloatList @@ -4709,7 +6134,7 @@ Full screen is back for Windows, and lots more. https://github.com/processing/processing/issues/2007 -[ internal changes you'll never notice... unless I broke something ] +[ internal changes you'll never notice... unless I broke something ] + Add an exception wrapper for startup, hopefully we can catch/debug more "Processing can't start!" issues with this. @@ -4737,17 +6162,17 @@ Full screen is back for Windows, and lots more. https://github.com/processing/processing/issues/2010 -[ changes ] +[ changes ] -+ Experimental Mode has been removed from the default download, - so that it can be updated more frequently. Install it and help us ++ Experimental Mode has been removed from the default download, + so that it can be updated more frequently. Install it and help us test what will become the 3.0 release of Processing! + Add "Processing Foundation" to the Help menu. https://github.com/processing/processing/issues/1908 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0.1 (REV 0219) - 21 June 2013 @@ -4755,7 +6180,7 @@ PROCESSING 2.0.1 (REV 0219) - 21 June 2013 Bug fixes for some of what ailed the Processing 2.0 release, including two contributed from Josh Giesbrecht. Thanks Josh! -[ bug fixes ] +[ bug fixes ] + Modes, Tools, Libraries not moving properly on Windows https://github.com/processing/processing/issues/1781 @@ -4764,7 +6189,7 @@ two contributed from Josh Giesbrecht. Thanks Josh! https://github.com/processing/processing/issues/707 http://code.google.com/p/processing/issues/detail?id=668 -+ Fix a problem with exporting Windows applications from OS X and Linux. ++ Fix a problem with exporting Windows applications from OS X and Linux. https://github.com/processing/processing/issues/1890 + getVertex() trying to get three values when no Z-coord is available @@ -4774,7 +6199,7 @@ two contributed from Josh Giesbrecht. Thanks Josh! + Fix typo in default printProjection() method https://github.com/processing/processing/issues/1863 -[ additions ] +[ additions ] + Add error message for that reports what line was bad while parsing a table. (Otherwise confusing ArrayIndexOutOfBoundsException while parsing bad CSV.) @@ -4782,19 +6207,19 @@ two contributed from Josh Giesbrecht. Thanks Josh! + Added option to remove the background image at the top of the window. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0 (REV 0218) - 3 June 2013 -And just like that, here we are at 2.0. +And just like that, here we are at 2.0. -[ bug fixes ] +[ bug fixes ] + Example window has the Java application icon https://github.com/processing/processing/issues/1800 -+ The update checker sometimes insisted there were updates, ++ The update checker sometimes insisted there were updates, even though there were not, due to a build problem. https://github.com/processing/processing/issues/1792 @@ -4825,33 +6250,33 @@ And just like that, here we are at 2.0. + P2D/P3D sketches don't get focus until clicked https://github.com/processing/processing/issues/1700 -[ changes ] +[ changes ] -+ A handful of tweaks to smooth out the 2.0 user interface. - Incorporates some of the feedback suggested here: ++ A handful of tweaks to smooth out the 2.0 user interface. + Incorporates some of the feedback suggested here: https://github.com/processing/processing/pull/1822 while trying to preserve the look & feel of our PDE design. + Added built-in fonts (Source Sans and Source Code from Adobe) - as the default font for the UI and editor. As usual, the editor - font can be changed in preferences.txt. And if you already have + as the default font for the UI and editor. As usual, the editor + font can be changed in preferences.txt. And if you already have a preferences.txt file, the new font won't override it. Fonts for GUI elements can be modified in lib/theme.txt, but be careful with those, and don't complain if/when they break. -+ Added several additional functions for data classes. More details ++ Added several additional functions for data classes. More details in the reference and coming soon. + Changed how null values were handled with binary tables. If anyone - was using the (undocument) .bin format for Table, you'll need to + was using the (undocument) .bin format for Table, you'll need to re-save your data. -+ Changed XML.toString() (what's called when you print() or println() - an XML object) to just send a single line of text instead of a full ++ Changed XML.toString() (what's called when you print() or println() + an XML object) to just send a single line of text instead of a full XML document with a header. Use format(numSpaces) if you want a properly formatted document with declaration at the top. -[ andres on the attack ] +[ andres on the attack ] + PImage not drawn after resize()/get() in P2D/P3D https://github.com/processing/processing/issues/1830 @@ -4896,17 +6321,17 @@ And just like that, here we are at 2.0. https://github.com/processing/processing/issues/1515 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b9 (REV 0217) - 18 May 2013 The 2.0 interface has arrived! Mmm... pretty. -We've removed Android and JavaScript modes from the default download. You +We've removed Android and JavaScript modes from the default download. You can easily install them by selected "Add Mode" from the Mode menu. They've -been removed because the changes have not kept pace with the rest of -Processing, and it was holding up the release of 2.0. As separate projects, +been removed because the changes have not kept pace with the rest of +Processing, and it was holding up the release of 2.0. As separate projects, we hope it'll be easier for volunteers to get involved, rather than our tiny, worn out development team. View the projects here: https://github.com/fjenett/javascript-mode-processing @@ -4919,13 +6344,13 @@ inside Processing. More documentation coming soon! We're hoping this is the last beta before 2.0, but we're still haggling with one or two issues that could require a beta 10. That's a lot of beta. -[ fixes ] +[ fixes ] + Major OutOfMemoryError problem with images fixed by Andres! http://code.google.com/p/processing/issues/detail?id=1353 https://github.com/processing/processing/issues/1391 -+ Lots of fixes for the library/mode/tool manager. ++ Lots of fixes for the library/mode/tool manager. Repairing colors, layout, etc. along with lots of internal fixes. + Fix MovieMaker, it was completely broken @@ -4934,7 +6359,7 @@ with one or two issues that could require a beta 10. That's a lot of beta. + processing-java dialog window was huge https://github.com/processing/processing/issues/1748 -+ Library with bad version number in version causes stack trace to print. ++ Library with bad version number in version causes stack trace to print. Added warning message about it with a pointer to the remedy. + "New version available" mesage is showing HTML tags around it @@ -4968,7 +6393,7 @@ with one or two issues that could require a beta 10. That's a lot of beta. + New images for modes. New design! -+ Added loadJSONArray(), loadJSONObject. ++ Added loadJSONArray(), loadJSONObject. + Hundreds of changes to the new data classes, sorting out their API, etc. @@ -4981,11 +6406,11 @@ with one or two issues that could require a beta 10. That's a lot of beta. + Change error message for libraries (especially serial) for 32- vs 64-bit to clarify that the 32- or 64-bit version of Processing can be used instead. -+ Rebuilt the internal Runner to use SocketAttach... This may bring up ++ Rebuilt the internal Runner to use SocketAttach... This may bring up a firewall message on some machines. Don't worry, it's safe (as long as the message is showing up when you hit Run, that's expected). -+ Add set(x, y) to PVector. ++ Add set(x, y) to PVector. + Removed div() and mult() from PVector, since not a legit math operation. https://code.google.com/p/processing/issues/detail?id=1506 @@ -5009,16 +6434,16 @@ with one or two issues that could require a beta 10. That's a lot of beta. only requires a JRE (and is therefore much smaller!) -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b8 (REV 0216) - 24 February 2013 -Dead bugs on the windscreen as we head down the road to 2.0. +Dead bugs on the windscreen as we head down the road to 2.0. (The fact that we're still in bad metaphor territory suggests we're still a little ways off from 2.0 final.) -[ bugs fixed ] +[ bugs fixed ] + "Find in Reference" broken in 2.0b7 http://code.google.com/p/processing/issues/detail?id=1456 @@ -5040,7 +6465,7 @@ we're still a little ways off from 2.0 final.) + Color coding for if/else in Processing IDE doesn't match http://code.google.com/p/processing/issues/detail?id=1457 -+ Ignore ArrayIndexOutOfBoundsException in JEditTextArea.xToOffset() ++ Ignore ArrayIndexOutOfBoundsException in JEditTextArea.xToOffset() + Fix IllegalStateException on Windows/Linux in Save prompt happened when hitting ESC or otherwise closing the window @@ -5057,7 +6482,7 @@ we're still a little ways off from 2.0 final.) http://code.google.com/p/processing/issues/detail?id=1533 + Fix "Bounds out of range" when outdenting a block of text - Exception in thread "AWT-EventQueue-0" + Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Bounds out of range: 5374,5376 [5375] at processing.app.syntax.JEditTextArea.select(JEditTextArea.java:1214) at processing.app.Editor.handleIndentOutdent(Editor.java:1819) @@ -5072,7 +6497,7 @@ we're still a little ways off from 2.0 final.) + Fix table loading quirk with extensions -+ PImage.resize() greater than image size hangs ++ PImage.resize() greater than image size hangs http://code.google.com/p/processing/issues/detail?id=1463 + loadBytes() does not close input stream @@ -5089,11 +6514,11 @@ we're still a little ways off from 2.0 final.) [ improvements, updates, and changes ] -+ Add basic retina support (text/labels, buttons not yet updated) ++ Add basic retina support (text/labels, buttons not yet updated) to the Mac OS X version. + Clean up the code and interface for the Movie Maker tool - http://code.google.com/p/processing/issues/detail?id=836 + http://code.google.com/p/processing/issues/detail?id=836 + Suggest possible import statements for common Java classes http://code.google.com/p/processing/issues/detail?id=1550 @@ -5120,7 +6545,7 @@ we're still a little ways off from 2.0 final.) + Add clear() to replace background(0, 0, 0, 0) http://code.google.com/p/processing/issues/detail?id=1446 -+ Change heading2D() to just heading() ++ Change heading2D() to just heading() http://code.google.com/p/processing/issues/detail?id=987 + Remove hint(ENABLE_NATIVE_FONTS) @@ -5139,7 +6564,7 @@ we're still a little ways off from 2.0 final.) + Miscellaneous XML fixes and cleanups -[ tool/mode/library manager ] +[ tool/mode/library manager ] + General cleanup of the visuals/layout @@ -5162,7 +6587,7 @@ we're still a little ways off from 2.0 final.) https://github.com/processing/processing/issues/1425 http://code.google.com/p/processing/issues/detail?id=1387 -[ android ] +[ android ] + Update documentation and tools for Android SDK Tools revision 21 http://code.google.com/p/processing/issues/detail?id=1398 @@ -5177,7 +6602,7 @@ we're still a little ways off from 2.0 final.) + Remove mouseEvent and keyEvent variables (deprecated on desktop) -[ table ] +[ table ] + Added lastRowIndex() @@ -5198,7 +6623,7 @@ we're still a little ways off from 2.0 final.) + Added getColumnCount() to TableRow -[ andres assault ] +[ andres assault ] + P3D sketches failing to run http://code.google.com/p/processing/issues/detail?id=1500 @@ -5273,7 +6698,7 @@ we're still a little ways off from 2.0 final.) + P2D, P3D drawing errors in static mode, gray screen https://github.com/processing/processing/issues/1648 - Still seeing a few of these in some cases, but hopefully + Still seeing a few of these in some cases, but hopefully this is fixed for the most part. [ manindra magic ] @@ -5291,24 +6716,24 @@ we're still a little ways off from 2.0 final.) http://code.google.com/p/processing/issues/detail?id=1504 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b7 (REV 0215) - 7 December 2012 -475,382 bug fixes in this release as we work on finalizing 2.0. +475,382 bug fixes in this release as we work on finalizing 2.0. -[ changes ] +[ changes ] -+ Removed all imports that aren't covered in the Processing reference. ++ Removed all imports that aren't covered in the Processing reference. If you use java.awt, java.util, or other classes in your sketch, you will need to add an import line to the beginning of your sketch. - Only the classes that are covered in the reference (HashMap, ArrayList, + Only the classes that are covered in the reference (HashMap, ArrayList, and some others) are now imported by default. This has been done to improve - overall cross-platform parity and to avoid users unknowingly adding + overall cross-platform parity and to avoid users unknowingly adding Java classes, and then the sadness that comes when switching to Android - or JavaScript modes. + or JavaScript modes. The list of imports is now hard-coded (no longer read from preferences.txt) and includes the following: @@ -5320,11 +6745,11 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 import java.io.OutputStream; import java.io.IOException; - If we're missing anything that's covered in the reference, please let us + If we're missing anything that's covered in the reference, please let us know via the bugs database. + A new "experimental" mode has been added. It's the start of combining two - of our Google Summer of Code projects (DebugMode and XQMode) to enable + of our Google Summer of Code projects (DebugMode and XQMode) to enable a debugger and on-the-fly error checking. We're including it in the release so that folks can test it out and let us know how it's doing. The interface still needs work and its innards may be a bit buggy, but it represents @@ -5346,16 +6771,16 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 http://code.google.com/p/processing/issues/detail?id=1354 http://guides.macrumors.com/Keyboard_shortcuts§ion=10#Text_Shortcuts -+ Set quality level higher when exporting JPEG images. This will result - in larger JPEG files with save() and saveFrame(), but the default quality - setting in the past was unacceptable for many/most projects. ++ Set quality level higher when exporting JPEG images. This will result + in larger JPEG files with save() and saveFrame(), but the default quality + setting in the past was unacceptable for many/most projects. http://code.google.com/p/processing/issues/detail?id=58 - See the bug report link for how to implement in case you want to set + See the bug report link for how to implement in case you want to set the quality lower (or even higher) than the new default. + Table row iterating syntax has changed. This code: for (TableRow row : table) { ... } - has now changed to + has now changed to for (TableRow row : table.getRows()) { ... } (This may change to rows() on the next round, pending other API tweaks) @@ -5396,10 +6821,10 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 + Change output from processing-java to be UTF-8 encoded. http://code.google.com/p/processing/issues/detail?id=1418 -+ Disable Quartz renderer to fix line blending problem on OS X. ++ Disable Quartz renderer to fix line blending problem on OS X. This older renderer was faster but had some bugs, like one that - caused lines to composite incorrectly when alpha was used. - Add "PApplet.useQuartz = true;" into your PApplet.main() + caused lines to composite incorrectly when alpha was used. + Add "PApplet.useQuartz = true;" into your PApplet.main() function to switch back to the old method: http://processing.googlecode.com/svn/trunk/processing/build/javadoc/core/processing/core/PApplet.html#useQuartz @@ -5407,7 +6832,7 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 http://code.google.com/p/processing/issues/detail?id=613 -[ bug fixes ] +[ bug fixes ] + mouseButton not being set properly in mouseClicked. http://code.google.com/p/processing/issues/detail?id=1350 @@ -5418,17 +6843,17 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 + mousePressed() coloring now different from mousePressed http://code.google.com/p/processing/issues/detail?id=41 Still not necessarily perfect, but it's a big improvement. - Note for people implementing their own Modes: FUNCTION1 and + Note for people implementing their own Modes: FUNCTION1 and FUNCTION2 have now been added for functions with parens. + 32-bit mode / 64-bit mode preference was ignored on OS X. http://code.google.com/p/processing/issues/detail?id=1426 -+ Prevent errors on first line of a new tab from highlighting the last - line of the previous tab. In particular, a single letter on a new tab ++ Prevent errors on first line of a new tab from highlighting the last + line of the previous tab. In particular, a single letter on a new tab was highlighting the last line of the tab to its left. -+ Android debug information wasn't being passed through to the console. ++ Android debug information wasn't being passed through to the console. In addition, on Windows, error reporting wasn't working properly (couldn't find the right line or report the error correctly). http://code.google.com/p/processing/issues/detail?id=1440 @@ -5441,7 +6866,7 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 + P2D/P3D PGraphics buffer failing to draw if larger than main surface. http://code.google.com/p/processing/issues/detail?id=1255 -+ Fix double error report when textMode(SCREEN) was used: ++ Fix double error report when textMode(SCREEN) was used: textMode(SCREEN) has been removed from Processing 2.0. textMode(256) is not supported by this renderer. @@ -5534,7 +6959,7 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 + Using a PGraphics as a texture produces visual artifacts. http://code.google.com/p/processing/issues/detail?id=1420 -[ android ] +[ android ] + Like the desktop release, removed default imports. This includes: android.view.MotionEvent, android.view.KeyEvent,android.graphics.Bitmap @@ -5542,17 +6967,17 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 cross-platform compatibility between Java, JavaScript, and Android modes. + Changed event handling to hopefully clean up some inconsistencies. - Removed motionX/Y/Pressure... these need to be handled separately. + Removed motionX/Y/Pressure... these need to be handled separately. More here: http://wiki.processing.org/w/Android -+ mouseX/Y no longer include history with moves, which reduces fidelity ++ mouseX/Y no longer include history with moves, which reduces fidelity a bit, but will hopefully prevent us overdoing it for future releases. + Fix how pmouseX/Y are set. http://code.google.com/p/processing/issues/detail?id=238 http://code.google.com/p/processing/issues/detail?id=1018 -[ fixed earlier / cleaning ] +[ fixed earlier / cleaning ] + When turning smoothing on, internal lines of shapes are visible. http://code.google.com/p/processing/issues/detail?id=53 @@ -5621,15 +7046,15 @@ PROCESSING 2.0b7 (REV 0215) - 7 December 2012 http://code.google.com/p/processing/issues/detail?id=929 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b6 (REV 0214) - 2 November 2012 -Patching up command line issues that went backwards in the last release, -a number of OpenGL fixes, and more internal changes and updates. +Patching up command line issues that went backwards in the last release, +a number of OpenGL fixes, and more internal changes and updates. -[ bug fixes ] +[ bug fixes ] + Command line support was broken in 2.0b5, with an error about processing-java ClassNotFoundException: BatchCompiler @@ -5643,31 +7068,31 @@ a number of OpenGL fixes, and more internal changes and updates. http://code.google.com/p/processing/issues/detail?id=911 + Editor not responding properly if the "External Editor" preference - had been enabled with a previous release. + had been enabled with a previous release. http://code.google.com/p/processing/issues/detail?id=1355 + A number of OpenGL fixes to better handle older chipsets, like the - GMA 950 (found on lots of older Mac Minis and similar hardware). + GMA 950 (found on lots of older Mac Minis and similar hardware). + Reverted back to an older version of the JOGL library to prevent - issues with sketches locking up. In particular, this should fix - sketches that use the video library: + issues with sketches locking up. In particular, this should fix + sketches that use the video library: http://code.google.com/p/processing/issues/detail?id=1338 http://code.google.com/p/processing/issues/detail?id=1364 + Icon loading was causing an error if you used a package for your code. http://code.google.com/p/processing/issues/detail?id=1346 -+ No longer using --request on OS X 10.6, since it's not available. ++ No longer using --request on OS X 10.6, since it's not available. Avoids a harmless warning message on the console when running a sketch. -[ changes/additions ] +[ changes/additions ] + Added an option to Preferences to enable/disable advanced input method support to handle complex scripts like Japanese, Korean, or Chinese. http://code.google.com/p/processing/issues/detail?id=526 -+ Add option for blinking and/or block caret in the editor. To disable ++ Add option for blinking and/or block caret in the editor. To disable caret blinking in the text editor, add this line to preferences.txt: editor.caret.blink = true Or to just a block caret, use this: @@ -5676,7 +7101,7 @@ a number of OpenGL fixes, and more internal changes and updates. [ internal ] -+ Removed applet-related preferences, and the 'applet' subfolder in the ++ Removed applet-related preferences, and the 'applet' subfolder in the source/distribution. + Removed the old 'cmd' folder from the source/distribution @@ -5684,11 +7109,11 @@ a number of OpenGL fixes, and more internal changes and updates. + Preferences are now written in sorted order to make it easier to handle comparisons or other debugging. -+ Major change to handle how the 'lib' folder is found, hopefully does a ++ Major change to handle how the 'lib' folder is found, hopefully does a better job with command line support. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b5 (REV 0213) - 22 October 2012 @@ -5696,7 +7121,7 @@ PROCESSING 2.0b5 (REV 0213) - 22 October 2012 Fixes for a few regressions that showed up in 2.0b4, plus some internal changes to simplify how modes are handled. -[ bug fixes ] +[ bug fixes ] + Libraries not installed through IDE had blank names. http://code.google.com/p/processing/issues/detail?id=1331 @@ -5707,17 +7132,17 @@ changes to simplify how modes are handled. + Console disappearing with increased editor font size. http://code.google.com/p/processing/issues/detail?id=1275 -[ changes/internal ] +[ changes/internal ] + Change how modes are set up so that XQMode, our Google Summer of Code project can work properly. -+ Implement multiple sizes of icons for PDE and core. This improves ++ Implement multiple sizes of icons for PDE and core. This improves the quality of the icon seen on Windows and Linux attached to frames. http://code.google.com/p/processing/issues/detail?id=632 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b4 (REV 0212) - 21 October 2012 @@ -5725,11 +7150,11 @@ PROCESSING 2.0b4 (REV 0212) - 21 October 2012 Command line support is back! Find and Replace works over multiple tabs! The Mac OS X version should work again in spite of Apple's best efforts! -[ additions & removals ] +[ additions & removals ] -+ Command line support is now available for Java mode. On Windows and Linux, - use the processing-java program. On Mac OS X, there's an option in the - Tools menu to install the command line tool. ++ Command line support is now available for Java mode. On Windows and Linux, + use the processing-java program. On Mac OS X, there's an option in the + Tools menu to install the command line tool. http://code.google.com/p/processing/issues/detail?id=142 Build and export options should even work in headless mode when enabled @@ -5739,21 +7164,21 @@ The Mac OS X version should work again in spite of Apple's best efforts! Android and JavaScript mode are not supported, contributions are welcome: http://code.google.com/p/processing/issues/detail?id=1323 -+ Added a Tool for Mac OS X to help set up serial port. Using serial on ++ Added a Tool for Mac OS X to help set up serial port. Using serial on OS X requires some incantations on the command line, and this prompts for an administrator password and takes care of them for you. The commands - involve creating a folder and setting a few permissions. If everything + involve creating a folder and setting a few permissions. If everything is already set properly, the Tool will not be present in the Tools menu. + With the arrival of command line support, the misunderstood and sometimes - maligned "Use External Editor" option has been removed. + maligned "Use External Editor" option has been removed. http://code.google.com/p/processing/issues/detail?id=515 + Fix several problems introduced by Apple's recent Java "update". Apple's most recent Java update may render older versions of Processing - completely unusable, it's not quite clear yet. + completely unusable, it's not quite clear yet. -[ bug fixes ] +[ bug fixes ] + Fix the exceptionally slow startup (a 5 second delay) in recent releases. @@ -5775,30 +7200,30 @@ The Mac OS X version should work again in spite of Apple's best efforts! + mouseButton wasn't getting set on mouseReleased() http://code.google.com/p/processing/issues/detail?id=1294 -[ technical updates ] +[ technical updates ] + JOGL has been updated, which may help iron out some GL quirks. + Change all build.xml files to use Java 6 as both source and target (avoids Java 7 warnings during build). -+ Updated ecj.jar to use jdt-core.jar... This is a larger file but were ++ Updated ecj.jar to use jdt-core.jar... This is a larger file but were hoping that this would get our GSoC project "XQMode" working without the need for patches. Sadly that's not the case, but stay tuned. -[ known issues ] +[ known issues ] + Fewer exclamation points will be used to introduce future releases. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b3 (REV 0211) - 10 September 2012 Shaking out the beta bugs. -[ major fixes ] +[ major fixes ] + registerMethod("keyEvent", ...) not calling key event methods. http://code.google.com/p/processing/issues/detail?id=1225 @@ -5808,13 +7233,13 @@ Shaking out the beta bugs. http://code.google.com/p/processing/issues/detail?id=1226 + Restore deprecated versions of getFont() and getImage() to address - library compatibility issues. The similar getBitmap() and getTypeface() + library compatibility issues. The similar getBitmap() and getTypeface() methods on Android will not be restored. http://code.google.com/p/processing/issues/detail?id=1223 -[ minor fixes ] +[ minor fixes ] -+ Changing the default display in Preferences does not reset editor ++ Changing the default display in Preferences does not reset editor location, so it appears to have no effect. http://code.google.com/p/processing/issues/detail?id=1162 @@ -5823,7 +7248,7 @@ Shaking out the beta bugs. + Make Mode menu into a radio button, so it cannot be de-selected http://code.google.com/p/processing/issues/detail?id=1227 -[ changes and additions ] +[ changes and additions ] + Show error message when using createGraphics() with P2D, P3D, or OPENGL and the main drawing surface is not an OpenGL renderer. @@ -5840,19 +7265,19 @@ Shaking out the beta bugs. Fingers crossed that these don't give us last-minute regressions. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b2 (REV 0210) - 7 September 2012 -One major fix for libraries that use key events, and a number of minor -fixes that we've found along the way. +One major fix for libraries that use key events, and a number of minor +fixes that we've found along the way. -[ fixes and updates ] +[ fixes and updates ] + Libraries with using key events were reporting: "java.lang.IllegalArgumentException: argument type mismatch" - in beta 1, this is now fixed. + in beta 1, this is now fixed. + Added hint(ENABLE_STROKE_PURE) to deal with Java 2D regression. http://code.google.com/p/processing/issues/detail?id=1137 @@ -5860,13 +7285,13 @@ fixes that we've found along the way. + Fix for stroke with beginShape(TRIANGLE_FAN) http://code.google.com/p/processing/issues/detail?id=1137 -+ hint() documentation now updated (except for the hint above). ++ hint() documentation now updated (except for the hint above). http://code.google.com/p/processing/issues/detail?id=1144 + Using ortho() breaks stroke rendering http://code.google.com/p/processing/issues/detail?id=1207 -[ fixed earlier ] +[ fixed earlier ] + POINTS mode vertices are huge http://code.google.com/p/processing/issues/detail?id=1037 @@ -5874,7 +7299,7 @@ fixes that we've found along the way. + Potentially insufficient ellipse detail with P3D/OPENGL when scaled http://code.google.com/p/processing/issues/detail?id=87 -+ Implement support for complex shapes when using the OpenGL renderer ++ Implement support for complex shapes when using the OpenGL renderer http://code.google.com/p/processing/issues/detail?id=122 + modelX/Y/Z broken when aiming a camera @@ -5889,18 +7314,18 @@ fixes that we've found along the way. + Memory improvements for updatePixels() with OpenGL (P2D and P3D) http://code.google.com/p/processing/issues/detail?id=77 -+ Text characters showing up as opaque rectangles ++ Text characters showing up as opaque rectangles http://code.google.com/p/processing/issues/detail?id=80 + Changing framerate causes program to crash with P2D in 2.0a6 http://code.google.com/p/processing/issues/detail?id=1116 -[ android ] +[ android ] + Updated examples from Andres and categories in the examples browser. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0b1 (REV 0209) - 3 September 2012 @@ -5908,16 +7333,16 @@ PROCESSING 2.0b1 (REV 0209) - 3 September 2012 Bug fixes, new registered methods for libraries, updated keywords, and we're beta! -[ changes ] +[ changes ] -+ Require 10.6.8 as minimum Mac OS X system version. ++ Require 10.6.8 as minimum Mac OS X system version. + Change name from "Standard" to "Java" mode. + Save opened/closed state of entries in the examples browser http://code.google.com/p/processing/issues/detail?id=827 -+ Lots of internal changes to loadShape() and PShape. ++ Lots of internal changes to loadShape() and PShape. + Work on making API more generic and consistent for cross-platform use. Font PFont.getFont() -> Object PFont.getNative() @@ -5925,15 +7350,15 @@ and we're beta! Image PImage.getImage() -> Object PImage.getNative() Bitmap PImage.getBitmap() -> Object PImage.getNative() -+ beginGL() and endGL() are gone, and beginPGL() and endPGL() exist - in their place. The PGL class is a layer that lets us talk to ++ beginGL() and endGL() are gone, and beginPGL() and endPGL() exist + in their place. The PGL class is a layer that lets us talk to OpenGL in a way that's cross-platform and consistent. It also has many GL calls for people who want to access GL directly. -+ New syntax introduced for libraries and registered methods. ++ New syntax introduced for libraries and registered methods. Documentation coming soon. -[ bug fixes ] +[ bug fixes ] + Handle dimming the Find/Replace buttons. http://code.google.com/p/processing/issues/detail?id=1056 @@ -5954,33 +7379,33 @@ and we're beta! + GL Android sketches halting after rotation. http://code.google.com/p/processing/issues/detail?id=1146 -[ known issues ] +[ known issues ] + createShape() is not implemented with the default 2D renderer. -+ See the Changes page on the Wiki for more. ++ See the Changes page on the Wiki for more. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a9 (REV 0208) - 1 September 2012 -As we inch closer to beta, a quick release for testing. +As we inch closer to beta, a quick release for testing. Plenty of video and OpenGL graphics fixes from Andres, and some functions -disappearing due to cleanups by Ben. (Andres giveth, Ben taketh away). +disappearing due to cleanups by Ben. (Andres giveth, Ben taketh away). -Consider this one to be 'nightly build' quality. +Consider this one to be 'nightly build' quality. -[ general ] +[ general ] + Help menu broken when Processing has spaces in its path name in 2.0a8 http://code.google.com/p/processing/issues/detail?id=1164 + We now have repeating textures. Use textureWrap(CLAMP) (the usual version) or textureWrap(REPEAT). If this feature is used for evil - and cheesiness, it will be removed in future releases. + and cheesiness, it will be removed in future releases. http://code.google.com/p/processing/issues/detail?id=94 + Fix lights in GL renderers on low-end android devices. @@ -5989,7 +7414,7 @@ Consider this one to be 'nightly build' quality. + Pixels for createGraphics() now transparent for P2D, P3D. http://code.google.com/p/processing/issues/detail?id=1156 -[ video ] +[ video ] + GettingStartedCapture in 2.0a8 launches X11 in Mountain Lion http://code.google.com/p/processing/issues/detail?id=1191 @@ -6012,7 +7437,7 @@ Consider this one to be 'nightly build' quality. + Wrong resolutions reported by Capture.list() http://code.google.com/p/processing/issues/detail?id=1192 -[ advanced ] +[ advanced ] + Several constants moved out of PConstants and into PGraphics. @@ -6023,16 +7448,16 @@ Consider this one to be 'nightly build' quality. + Removed several video functions that weren't approved. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a8 (REV 0207) - 5 August 2012 -A handful of bug fixes. Not as large a release as 2.0a7, but I decided +A handful of bug fixes. Not as large a release as 2.0a7, but I decided it best to get the updates out there and in use rather than waiting for -beta 1 since I'm not sure when we'll be able to get that out. +beta 1 since I'm not sure when we'll be able to get that out. -[ miscellaneous ] +[ miscellaneous ] + Make sure smooth() is the default with both renderers http://code.google.com/p/processing/issues/detail?id=1157 @@ -6054,10 +7479,10 @@ beta 1 since I'm not sure when we'll be able to get that out. + Added 'empty sketchbook' indicator when the sketchbook menus are empty -+ Prevent users from deleting the last tab on the only sketch that is - currently open on Windows and Linux. ++ Prevent users from deleting the last tab on the only sketch that is + currently open on Windows and Linux. -[ serial ] +[ serial ] + Added 64-bit RXTX for Mac OS X serial from this page: http://blog.iharder.net/2009/08/18/rxtx-java-6-and-librxtxserial-jnilib-on-intel-mac-os-x/ @@ -6069,7 +7494,7 @@ beta 1 since I'm not sure when we'll be able to get that out. + bufferUntil() with values above 127 do not work properly http://code.google.com/p/processing/issues/detail?id=1079 -[ plumbing ] +[ plumbing ] + Switch to using java.awt.Desktop classes for opening folders, links, etc. @@ -6084,31 +7509,31 @@ beta 1 since I'm not sure when we'll be able to get that out. + Added notes about "color(0, 0, 0, 0) produces black" to the Wiki. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a7 (REV 0206) - 29 July 2012 -Hopefully the last alpha before we hit 2.0 beta. +Hopefully the last alpha before we hit 2.0 beta. The big change is that we're dropping support for applets in 2.0, and in this release. See the Changes section of the Wiki for details. We've not updated all of the documentation to reflect this yet. -OS X 10.8 Mountain Lion support has also been added, by virtue of our +OS X 10.8 Mountain Lion support has also been added, by virtue of our paying $99/year for the privilege of releasing our free and open source application on OS X. When run on 10.8, versions prior to 2.0a7 would report -that they were corrupt, invalid, or not trusted. Which is definitely us. +that they were corrupt, invalid, or not trusted. Which is definitely us. -[ editor ] +[ editor ] -+ Implemented a "Recent Sketches" menu. This replaces re-opening - sketches on startup, which behaved inconsistently anyway. ++ Implemented a "Recent Sketches" menu. This replaces re-opening + sketches on startup, which behaved inconsistently anyway. http://code.google.com/p/processing/issues/detail?id=188 + Use Swing file choosers by default on Linux. The default open/save - dialogs provided by Java are pretty gruesome, so we're switching to - the Swing JFileChooser instead. To swap the behavior, set + dialogs provided by Java are pretty gruesome, so we're switching to + the Swing JFileChooser instead. To swap the behavior, set 'chooser.files.native' in your preferences.txt file. + Suppress "invalid context 0x0" and "invalid drawable" because they're @@ -6124,13 +7549,13 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. updates for 32/64-bit support in general. http://code.google.com/p/processing/issues/detail?id=955 -+ Replace processing.exe with a more standard version from launch4j, ++ Replace processing.exe with a more standard version from launch4j, which should hopefully clean up some launcher issues. http://code.google.com/p/processing/issues/detail?id=943 http://code.google.com/p/processing/issues/detail?id=176 + Change how sketches open so that there's no longer differences between - the File menu 'Open' and the way it worked from the toolbar. Simplifies + the File menu 'Open' and the way it worked from the toolbar. Simplifies additional code that was quirky. http://code.google.com/p/processing/issues/detail?id=1034 @@ -6142,18 +7567,18 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. + Instead of prompting for sketchbook location on Linux, just default to a folder named 'sketchbook' in the user's home directory. This can easily - be changed later but simplifies things internally a bit. + be changed later but simplifies things internally a bit. -+ No longer allow underscore at beginning of sketch name (causes problems ++ No longer allow underscore at beginning of sketch name (causes problems with Android, and also with applets, though we care less about those...) http://code.google.com/p/processing/issues/detail?id=1047 -+ Fixed a problem where sanitized names (underscores replacing unusable ++ Fixed a problem where sanitized names (underscores replacing unusable characters) could potentially overwrite existing folders. -[ core ] +[ core ] -+ Major changes to selectInput(), selectOutput(), and selectFolder(). ++ Major changes to selectInput(), selectOutput(), and selectFolder(). See the Wiki: http://wiki.processing.org/w/Changes#Change_and_Removed The changes are there to prevent a threading bug: http://code.google.com/p/processing/issues/detail?id=173 @@ -6162,9 +7587,9 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. http://code.google.com/p/processing/issues/detail?id=233 + Change 'appletViewer' back to 'online'. Still deprecated, especially - because applets are going away. + because applets are going away. -+ Add begin/endGL added to PGraphics/PApplet. ++ Add begin/endGL added to PGraphics/PApplet. + Add hasChildren() to XML library. http://code.google.com/p/processing/issues/detail?id=1045 @@ -6172,8 +7597,8 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. + Fix where displayWidth/Height not being set properly before setup() http://code.google.com/p/processing/issues/detail?id=1120 -+ XML now throws exceptions in its constructor (for advanced users). - Use loadXML() instead of "new XML(this, ....)" ++ XML now throws exceptions in its constructor (for advanced users). + Use loadXML() instead of "new XML(this, ....)" http://code.google.com/p/processing/issues/detail?id=1138 + loadXML() returns null when the file did not open properly @@ -6183,11 +7608,11 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. http://code.google.com/p/processing/issues/detail?id=1143 + Add some extra options for PApplet.main() for advanced users: - PApplet.main("SketchName") and PApplet.main("SketchName", args) + PApplet.main("SketchName") and PApplet.main("SketchName", args) -[ android ] +[ android ] -+ Add full PAppletMethods implementation to Android, so that PGraphics ++ Add full PAppletMethods implementation to Android, so that PGraphics and PImage methods are brought into PApplet. + Swap Run on Device and Run on Emulator @@ -6200,7 +7625,7 @@ that they were corrupt, invalid, or not trusted. Which is definitely us. http://code.google.com/p/processing/issues/detail?id=1054 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a6 (REV 0205) - 1 June 2012 @@ -6217,9 +7642,9 @@ http://wiki.processing.org/w/Changes + Added an option for selecting the default display inside Preferences. -+ P2D and P3D are now variations of the OpenGL renderer. ++ P2D and P3D are now variations of the OpenGL renderer. -+ XML and Table are now part of the processing.data.* package. ++ XML and Table are now part of the processing.data.* package. There's also new loadTable() and loadXML() methods in PApplet. [ bug fixes ] @@ -6245,7 +7670,7 @@ http://wiki.processing.org/w/Changes + When internal tools crash, don't add them to the menu (prevents the PDE from locking up on startup). -[ fixed earlier ] +[ fixed earlier ] + Export reports "Could not copy source file" (even though it works) http://code.google.com/p/processing/issues/detail?id=638 @@ -6278,19 +7703,19 @@ http://wiki.processing.org/w/Changes + Make displayWidth/Height work properly with multiple screen. (In the past, screen.width and screen.height just returned the default - display size, not necessarily the display being used.) + display size, not necessarily the display being used.) + Built in Hansi's full screen API for OS X, so that sketches can use full screen without exclusive mode. See the Wiki for details. http://wiki.processing.org/w/Window_Size_and_Full_Screen -+ Now attempts detect when a sketch's size is the full screen, ++ Now attempts detect when a sketch's size is the full screen, and if so removes the frame border, etc. + --display option now works properly (on OS X and elsewhere) http://code.google.com/p/processing/issues/detail?id=71 -[ OpenGL by Andres ] +[ OpenGL by Andres ] + polygon shapes without fill slowdown render progressively http://code.google.com/p/processing/issues/detail?id=1028 @@ -6325,11 +7750,11 @@ http://wiki.processing.org/w/Changes + OpenGL noSmooth() does not work http://code.google.com/p/processing/issues/detail?id=328 -[ android ] +[ android ] + Android SDK Tools revision 19 (later may work too) are required. -+ Android mode no longer broken on Windows. Google has fixed the bug, ++ Android mode no longer broken on Windows. Google has fixed the bug, but you'll need to use the latest SDK. http://code.google.com/p/processing/issues/detail?id=1022 @@ -6346,32 +7771,32 @@ http://wiki.processing.org/w/Changes http://code.google.com/p/processing/issues/detail?id=751 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a5 (REV 0204) - 23 March 2012 Major updates in this release include a huge revamp of the OpenGL library -by Andres, fixes to get Android Mode working again, and a number of bug +by Andres, fixes to get Android Mode working again, and a number of bug fixes and additions as we head toward 2.0. Unfortunately, however, Android mode is still broken on Windows. http://code.google.com/p/processing/issues/detail?id=1022 -On the OpenGL front, we're working to have a single library that works -across both desktop and mobile, which is good news because it means we have -a fighting chance of making it work (rather than maintaining two entire sets -of a very complicated set of code), but the downside is that it requires -newer versions of OpenGL on both the desktop and mobile, so it may cause -problems with old OSes, mediocre graphics drivers, etc that worked with +On the OpenGL front, we're working to have a single library that works +across both desktop and mobile, which is good news because it means we have +a fighting chance of making it work (rather than maintaining two entire sets +of a very complicated set of code), but the downside is that it requires +newer versions of OpenGL on both the desktop and mobile, so it may cause +problems with old OSes, mediocre graphics drivers, etc that worked with earlier releases. -[ bug fixes ] +[ bug fixes ] + OpenGL applets are working again. http://code.google.com/p/processing/issues/detail?id=845 -+ Abnormal high Java CPU usage at empty sketch with draw() ++ Abnormal high Java CPU usage at empty sketch with draw() http://code.google.com/p/processing/issues/detail?id=729 + "Framingham" example has BufferOverflowException @@ -6383,7 +7808,7 @@ earlier releases. + Doc comments not being properly terminated in export of applet http://code.google.com/p/processing/issues/detail?id=877 -+ Tweaks to the code to prevent multiple copies of Processing from ++ Tweaks to the code to prevent multiple copies of Processing from running at once. + Fix bug with 'base' not getting set in the Mac OS X platform class. @@ -6402,7 +7827,7 @@ earlier releases. + Several bug fixes inside Table as they relate to inserting/adding columns. -[ changes/additions ] +[ changes/additions ] + Enable smooth() by default. @@ -6413,7 +7838,7 @@ earlier releases. + Update to Java 6u29 for Linux and Windows (OS X now updated). -+ Don't show library conflict warning until someone tries to build ++ Don't show library conflict warning until someone tries to build with code that actually calls on one of those packages. + urlEncode() and urlDecode() added (docs coming later). @@ -6421,9 +7846,9 @@ earlier releases. + delay() is back again. F*king delay(). + Added anti-alias methods so that FSAA can set up properly. The API for - these is not set yet. + these is not set yet. -[ in earlier releases ] +[ in earlier releases ] + Commenting via menu or shortcut does not set sketch to "need save". http://code.google.com/p/processing/issues/detail?id=860 @@ -6441,7 +7866,7 @@ earlier releases. + Closing applet window in Processing 1.5 causes serial crash. http://code.google.com/p/processing/issues/detail?id=635 -[ javascript ] +[ javascript ] + Finalize JavaScript mode export folder name. http://code.google.com/p/processing/issues/detail?id=848 @@ -6450,7 +7875,7 @@ earlier releases. http://code.google.com/p/processing/issues/detail?id=936 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a4 (REV 0203) - 10 November 2011 @@ -6458,7 +7883,7 @@ PROCESSING 2.0a4 (REV 0203) - 10 November 2011 This is just a quick release so that I can procrastinate on packing for Chicago a little longer. A handful of bug fixes here: -+ Video capture was broken in 2.0a3 on OS X due to an issue with the build ++ Video capture was broken in 2.0a3 on OS X due to an issue with the build process. Should be all set now. + Fixed incessant "inefficient font rendering" debug message on Android. @@ -6471,7 +7896,7 @@ Chicago a little longer. A handful of bug fixes here: messages when natives aren't available for the platform--just an UnsatisfiedLinkError when you try to run. Will fix.) -[ andres' bug victims ] +[ andres' bug victims ] + Multiple calls to curve() connect subsequent curves with lines in P3D/OPENGL http://code.google.com/p/processing/issues/detail?id=865 @@ -6480,18 +7905,18 @@ Chicago a little longer. A handful of bug fixes here: http://code.google.com/p/processing/issues/detail?id=890 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a3 (REV 0202) - 5 November 2011 Some weekend bug fixing and regression repair for the recent alpha releases. -Also several Android fixes to get things working again with more recent -updates from Google. You'll need to upgrade to this version of Processing +Also several Android fixes to get things working again with more recent +updates from Google. You'll need to upgrade to this version of Processing in order to continue using Android mode. -[ environment ] +[ environment ] + Fix problem with serial not loading on Mac OS X. @@ -6509,14 +7934,14 @@ in order to continue using Android mode. + IDE Export Application button exports applet (fixed in 2.0a2) http://code.google.com/p/processing/issues/detail?id=863 -[ core ] +[ core ] + Fix for video frames not showing up in 3D. + Rounded rect() does not have a maximum length for corner radius http://code.google.com/p/processing/issues/detail?id=813 -[ android ] +[ android ] + Fix libraries when used with Android. Libraries can also specify an Android version by including an 'android' subfolder. @@ -6540,7 +7965,7 @@ in order to continue using Android mode. http://code.google.com/p/processing/issues/detail?id=864 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a2 (REV 0201) - 31 October 2011 @@ -6548,12 +7973,12 @@ PROCESSING 2.0a2 (REV 0201) - 31 October 2011 Happy Halloween! I'll be dressing up as an ArrayIndexOutOfBoundsException. This release is primarily focused on the new video library and making it -usable across platforms. It also has some changes for how applications +usable across platforms. It also has some changes for how applications are exported, and a number of other bug fixes and tweaks. -[ platforms ] +[ platforms ] -+ With this release, Java 1.6 is now required. We will no longer be ++ With this release, Java 1.6 is now required. We will no longer be supporting Java 1.5. + In perhaps related news, we are no longer supporting Mac OS X 10.5. @@ -6566,21 +7991,21 @@ are exported, and a number of other bug fixes and tweaks. 64-bit. Library support has changed significantly to get things working, more on this coming soon. -+ Serial on Mac OS X and Windows is currently only available for 32-bit. - Hoping someone can help us support a 64-bit version sometime soon. ++ Serial on Mac OS X and Windows is currently only available for 32-bit. + Hoping someone can help us support a 64-bit version sometime soon. + When exporting a 64-bit application for Windows, a .bat file is created, because our .exe doesn't yet support 64-bit. Assuming you have a 64-bit JVM installed, the .bat file should load things properly. -+ Because serial only supports 32-bit on OS X, exporting an application - that uses serial will only create a application.macosx32 folder, which - is a 32-bit app for Mac OS X. No application.macosx64 will be created, - nor will a universal application.macosx folder. This is also the case ++ Because serial only supports 32-bit on OS X, exporting an application + that uses serial will only create a application.macosx32 folder, which + is a 32-bit app for Mac OS X. No application.macosx64 will be created, + nor will a universal application.macosx folder. This is also the case for other libraries that have only 32- or 64-bit support. See earlier note that 32- and 64-bit support is an f*ing nightmare. -[ video ] +[ video ] + The most significant change in this release is that the new video library from Andres (based on his old gsvideo library) is nearing fully fucntional. @@ -6591,10 +8016,10 @@ are exported, and a number of other bug fixes and tweaks. [ other changes ] -+ Application is now the default export (instead of Applet). ++ Application is now the default export (instead of Applet). + Change to how dataPath() and dataFile() work. This is an undocumented - function, but for those using it, here's the skinny: + function, but for those using it, here's the skinny: dataPath() is only available with applications, not applets or Android. On Windows and Linux, this is simply the data folder, which is located @@ -6609,26 +8034,26 @@ are exported, and a number of other bug fixes and tweaks. works with an applet, you should use other methods such as createInput(), createReader(), or loadStrings(). -+ Additional library files included with application exports are now placed ++ Additional library files included with application exports are now placed in the 'lib' folder on Linux and Windows, or buried inside the OS X app. This helps prevent the unsightly mess of DLLs that were crowding the root folder of exported applications on Windows and Linux. -+ If noLoop() has been called but a sketch is resized, redraw() will be ++ If noLoop() has been called but a sketch is resized, redraw() will be called to update the screen. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 2.0a1 (REV 0200) - 2 September 2011 -First alpha release as we head toward 2.0. Please read the changes page +First alpha release as we head toward 2.0. Please read the changes page to learn about what's different: http://wiki.processing.org/w/Changes -[ since we last spoke ] +[ since we last spoke ] -+ Lots of video work from Andres. ++ Lots of video work from Andres. + Updated to Java 6u26 on Windows and Linux. @@ -6647,16 +8072,16 @@ to learn about what's different: http://wiki.processing.org/w/Changes + PImage.save() with full path raises exception http://code.google.com/p/processing/issues/detail?id=808 -+ Fix problem where loading data from an http:// stream would - run out of memory on Android. ++ Fix problem where loading data from an http:// stream would + run out of memory on Android. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0199 - 27 June 2011 -Handful of bug fixes, primarly to deal with issues introduced in 0198. +Handful of bug fixes, primarly to deal with issues introduced in 0198. + Remove error messages for UpdateCheck w/o internet connection. @@ -6672,15 +8097,15 @@ Handful of bug fixes, primarly to deal with issues introduced in 0198. + Fix broken loadNode() and XML usage in general. + Fix problem with save() writing multiple image files with an extra .tif - at the end. + at the end. + Added no-op orientation() method to the desktop version so that code will work unchanged between Android and desktop. -+ Add warning for missing glyphs in PFont. ++ Add warning for missing glyphs in PFont. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0198 - 23 June 2011 @@ -6691,15 +8116,15 @@ covered on the changes page in the Wiki: http://wiki.processing.org/w/Changes This is an interim release so that Andres can do a workshop. Not recommended for casual use. Hostile or belligerent whiners need not apply. -Android mode has received zero testing, so XML, SVG, 3D, and other major +Android mode has received zero testing, so XML, SVG, 3D, and other major features may be broken. See statement directly above. -[ bugs fixed ] +[ bugs fixed ] + Examples window placed off-screen when PDE window is maximized http://code.google.com/p/processing/issues/detail?id=669 -+ Make examples window respond to ESC, and double-click events to ++ Make examples window respond to ESC, and double-click events to expand/collapse nodes. + Launch script for Linux fails to open a sketches with relative paths @@ -6717,7 +8142,7 @@ features may be broken. See statement directly above. + Make sketch.properties usable elsewhere by loading/reloading http://code.google.com/p/processing/issues/detail?id=722 -+ Export to Application reports "Could not copy source file:" ++ Export to Application reports "Could not copy source file:" http://code.google.com/p/processing/issues/detail?id=638 + Automatically insert the 'import processing.opengl' when P3D used. @@ -6741,10 +8166,10 @@ features may be broken. See statement directly above. + Removed the delay() method. It was awful. -+ Addded thread() method that takes a function name as a parameter, ++ Addded thread() method that takes a function name as a parameter, and runs it on its own thread. No more classes! -+ PImage.save() returns a success boolean (rather than throwing an ++ PImage.save() returns a success boolean (rather than throwing an exception when it fails). [ core bugs fixed ] @@ -6755,7 +8180,7 @@ features may be broken. See statement directly above. + problem with destroy() calling System.exit() http://code.google.com/p/processing/issues/detail?id=698 -+ post() is called after setup() ++ post() is called after setup() http://code.google.com/p/processing/issues/detail?id=455 + Remove auto-sizing from binary() (was inconsistent with hex() method). @@ -6812,19 +8237,19 @@ features may be broken. See statement directly above. + removed A2D and A3D constants -+ colorMode() error ++ colorMode() error http://code.google.com/p/processing/issues/detail?id=223 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.5.1 (REV 0197) - 15 May 2011 This release fixes a handful of regressions and quirks that were found in -the Processing 1.5 release last month. +the Processing 1.5 release last month. -[ editor ] +[ editor ] + Windows splash screen for version 1.5 says "1.2" http://code.google.com/p/processing/issues/detail?id=631 @@ -6843,13 +8268,13 @@ the Processing 1.5 release last month. + File > New and Command-N stop working on OS X after running a sketch http://code.google.com/p/processing/issues/detail?id=664 -[ core ] +[ core ] + Reverted to the old createFont() behavior, where native fonts will be used with createFont() in more situations. http://code.google.com/p/processing/issues/detail?id=662 -[ svg ] +[ svg ] + Improve handling of transformations in SVG files. http://code.google.com/p/processing/issues/detail?id=388 @@ -6862,7 +8287,7 @@ the Processing 1.5 release last month. + Fix misshapen quadratic bezier curves when drawing SVG files. -[ examples ] +[ examples ] + HsvSpace example sketch in 1.5 download requires additional import http://code.google.com/p/processing/issues/detail?id=661 @@ -6871,7 +8296,7 @@ the Processing 1.5 release last month. http://code.google.com/p/processing/issues/detail?id=655 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.5 (REV 0196) - 17 April 2011 @@ -6881,7 +8306,7 @@ being the introduction of "modes" for the editor, allowing you to switch between Android development or the classic desktop/web mode. More modes are coming in future releases. -Another significant change is a fix for applets that were stuttering or +Another significant change is a fix for applets that were stuttering or appearing to run very, very slowly in Firefox 4 and Chrome. That's the major reason that we're releasing this version in advance on 2.0 later this summer. @@ -6895,7 +8320,7 @@ eventually replacing the built-in OpenGL library for 2.0. Meanwhile, here are the changes since revision 0195, the last pre-release: -[ pde ] +[ pde ] + A new version of the reference and examples have been posted online. @@ -6908,7 +8333,7 @@ Meanwhile, here are the changes since revision 0195, the last pre-release: http://dev.processing.org/bugs/show_bug.cgi?id=810 http://code.google.com/p/processing/issues/detail?id=100 -+ Fixed a bug in the LoadFile2 example ++ Fixed a bug in the LoadFile2 example http://code.google.com/p/processing/issues/detail?id=522 + Shift-indent without selection increases indention @@ -6958,9 +8383,9 @@ Mac software developer hero of my youth, Peter N Lewis. + Fix minor native fonts issue. -[ android ] +[ android ] -+ Workaround for loadImage(url) bug in Google's Android source. ++ Workaround for loadImage(url) bug in Google's Android source. Issue tracked down by psoden. (Thanks!) http://code.google.com/p/processing/issues/detail?id=629 @@ -6974,21 +8399,21 @@ Mac software developer hero of my youth, Peter N Lewis. http://code.google.com/p/processing/issues/detail?id=518 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0195 - 10 April 2011 -Bug fixes and several Android updates. Working to close in on a proper +Bug fixes and several Android updates. Working to close in on a proper Processing 1.5 release. -This release has several changes to renaming sketches, using Save As, +This release has several changes to renaming sketches, using Save As, and how untitled sketches are handled. Please help test! Note that on the Android side, this release once again requires installation of the Google APIs. See the Android Wiki page for details. -[ general ] +[ general ] + Sketch restarts automatically after pressing stop button on PDE http://code.google.com/p/processing/issues/detail?id=561 @@ -7036,11 +8461,11 @@ of the Google APIs. See the Android Wiki page for details. + Remove version number from splash image http://code.google.com/p/processing/issues/detail?id=324 -+ Subfolders in /libraries folder not supported in 0194, ++ Subfolders in /libraries folder not supported in 0194, bring them back for toxi and the toxiclibs folks. http://code.google.com/p/processing/issues/detail?id=578 -[ core ] +[ core ] + Deal with bad screen updates for sketches running < 60 fps in JAVA2D @@ -7053,7 +8478,7 @@ of the Google APIs. See the Android Wiki page for details. + save() and other pixel operations no longer working with JAVA2D in 0194 http://code.google.com/p/processing/issues/detail?id=594 -[ android ] +[ android ] + point() doesn't render in A3D http://code.google.com/p/processing/issues/detail?id=592 @@ -7074,21 +8499,21 @@ of the Google APIs. See the Android Wiki page for details. + Better error handling when certain SDK components are not installed. -+ Canceling an attempt to find the Android SDK leaves no window open, ++ Canceling an attempt to find the Android SDK leaves no window open, or crash when trying to change to Android mode w/ no Android SDK http://code.google.com/p/processing/issues/detail?id=605 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0194 - 9 March 2011 Lots of fixes for late-breaking problems in release 0193. -[ fixes ] +[ fixes ] -+ The Auto Format command went missing in 0193. It's back for 0194, but is ++ The Auto Format command went missing in 0193. It's back for 0194, but is now located in the Edit menu, where it will stay for the rest of its long and happy life. @@ -7103,7 +8528,7 @@ Lots of fixes for late-breaking problems in release 0193. + Fix for flicker problem in the default renderer. http://code.google.com/p/processing/issues/detail?id=558 -+ The examples menu wasn't completely removed in 0193. ++ The examples menu wasn't completely removed in 0193. + Remove "temporarily skipping deletion of" debugging message on export. @@ -7114,7 +8539,7 @@ Lots of fixes for late-breaking problems in release 0193. + Fix problem with Sketch Permissions for Android. http://code.google.com/p/processing/issues/detail?id=559 -[ notes ] +[ notes ] + Because both OpenGL and OpenGL2 are present, there may be conflicts if you implement any OpenGL-specific code outside the Processing API. If your sketch @@ -7124,7 +8549,7 @@ Lots of fixes for late-breaking problems in release 0193. import javax.media.opengl.glu.*; then you should remove one of the OpenGL libraries, depending on which you - would like to use. + would like to use. + OpenGL is built-in on Android. You don't need to add it as a library, the way you do with the desktop. A "import processing.opengl.*" line won't @@ -7137,48 +8562,48 @@ Lots of fixes for late-breaking problems in release 0193. [ additions ] -+ Added a new icon for "Export to Application", along the lines of the - icons used on the Android side. ++ Added a new icon for "Export to Application", along the lines of the + icons used on the Android side. + Remove warning about the broken build. http://code.google.com/p/processing/issues/detail?id=519 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0193 - 8 March 2011 -The PDE is receiving a major overhaul. The most obvious change is that +The PDE is receiving a major overhaul. The most obvious change is that there's now a menu that allows you to switch between "modes". "Standard" -is the Java-based mode that we're all used to, and "Android" compiles -things for Android devices. +is the Java-based mode that we're all used to, and "Android" compiles +things for Android devices. -Basically it's all pre-releases from here until 2.0. +Basically it's all pre-releases from here until 2.0. -With the mode support, it will soon be possible to embed other projects, -like the Python version, or the JS exporter, directly inside the PDE. +With the mode support, it will soon be possible to embed other projects, +like the Python version, or the JS exporter, directly inside the PDE. More on this later. This release also fixes a handful of Android problems, like the use of libraries, the code folder, and so on. -[ core ] +[ core ] + Fix problem that made applets suck in Google Chrome and Firefox 4. + Fix java.lang.OutOfMemoryError using get() and image() inside a tight loop. http://code.google.com/p/processing/issues/detail?id=42 -+ Changed default font to Lucida Sans, available on all platforms. ++ Changed default font to Lucida Sans, available on all platforms. This means that your text may be a slightly different size if you haven't - used textFont(), but hey, you probably don't use the default font, right? + used textFont(), but hey, you probably don't use the default font, right? A fella (or gal) like you? + textAlign() incorrect with default font on Mac OS X 10.6 http://code.google.com/p/processing/issues/detail?id=362 -+ Clean up how PDF fonts are handled. Default to writing fonts as shapes, ++ Clean up how PDF fonts are handled. Default to writing fonts as shapes, which makes PDF files larger, but is likely to work in more cases. If you want editable/real text, you can call textMode(MODEL) right after creating the PDF renderer (directly below size() or beginRecord()). @@ -7189,7 +8614,7 @@ libraries, the code folder, and so on. + Fix bizarre window placement when using Present mode on OS X. -[ pde changes/fixes ] +[ pde changes/fixes ] + Added support for separate 32 and 64 bit versions of libraries. @@ -7203,7 +8628,7 @@ libraries, the code folder, and so on. library into a newer, faster, more amazinger OpenGL that will eventually be the default. -+ Added a *lot* of examples. This has also had the effect of making the ++ Added a *lot* of examples. This has also had the effect of making the download enormous. It's currently obese. We'll sort that out later. + Code folder oddity on application export (in SVN) @@ -7224,7 +8649,7 @@ libraries, the code folder, and so on. http://code.google.com/p/processing/issues/detail?id=529 + Console, preferences cleanup: removed build.path, as well as - console.output.file, and console.error.file. Also removed 'console' + console.output.file, and console.error.file. Also removed 'console' true/false from preferences. + Change console to write to the 'console/' folder in settings. @@ -7234,7 +8659,7 @@ libraries, the code folder, and so on. + Add splash image on OS X. + Added window for examples. It's a bit ugly, but the menu was too much - and we should be able to clean this feller up later. Also makes the + and we should be able to clean this feller up later. Also makes the examples a bit more obvious. + Updated the serial library for Mac OS X @@ -7249,7 +8674,7 @@ libraries, the code folder, and so on. http://dev.processing.org/bugs/show_bug.cgi?id=54 http://code.google.com/p/processing/issues/detail?id=17 -[ fixed in 0192 ] +[ fixed in 0192 ] + Auto-format screws up if/else/else if blocks http://code.google.com/p/processing/issues/detail?id=325 @@ -7259,7 +8684,7 @@ libraries, the code folder, and so on. [ android edits ] -+ Add better icons from Casey for exported applications. ++ Add better icons from Casey for exported applications. + Remove the need to download the android core.jar separately http://code.google.com/p/processing/issues/detail?id=421 @@ -7284,10 +8709,10 @@ libraries, the code folder, and so on. http://dev.processing.org/bugs/show_bug.cgi?id=1379 http://code.google.com/p/processing/issues/detail?id=201 -+ With mode support, "Run on Device" and "Run in Emulator" instead of ++ With mode support, "Run on Device" and "Run in Emulator" instead of "Run" and "Present". -[ internal changes ] +[ internal changes ] + Removed build.path from preferences.txt. Not really used anywhere, just trying to clean things up. @@ -7295,8 +8720,8 @@ libraries, the code folder, and so on. + Removed 'console.output.file' and 'console.error.file'. These weren't respected as paths, no reason for them. -+ Change console to write to the 'console/' folder in settings. - This may eventually create a problem with logs that need to be cleaned, ++ Change console to write to the 'console/' folder in settings. + This may eventually create a problem with logs that need to be cleaned, but we'll keep an eye on it for now. + Removed 'console' true/false from preferences. @@ -7305,19 +8730,19 @@ libraries, the code folder, and so on. http://code.google.com/p/processing/issues/detail?id=197 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0192 - 18 December 2010 This release contains a roll-up of lots of bug fixes. However, it's being released before it's ready, so it should only be used by people who are having -trouble with the new Android SDK release (revision 8) from Google, which +trouble with the new Android SDK release (revision 8) from Google, which broke Android support last week. -This version of Processing for Android *requires* Android SDK Tools Release 8. -If you're not using release 8, and don't have the necessary components -installed, you'll get (confusing) error messages saying that the SDK location +This version of Processing for Android *requires* Android SDK Tools Release 8. +If you're not using release 8, and don't have the necessary components +installed, you'll get (confusing) error messages saying that the SDK location is not set, and that it could not find an SDK in the location that you specify. As for this being an early release, the problem is that major changes were @@ -7327,11 +8752,11 @@ support is somewhat broken. So with that caveat, no whining, please. On a happier note, the changes: -[ android fixes ] +[ android fixes ] + Compile android-core with Java 5 as the target so that it works on OS X 10.5. -[ additions from andres ] +[ additions from andres ] + A3D should use lower color depth on older devices. http://code.google.com/p/processing/issues/detail?id=391 @@ -7377,7 +8802,7 @@ On a happier note, the changes: + AutoFormat unecessarily adds spaces to function with multiple args http://code.google.com/p/processing/issues/detail?id=462 -[ edits from Lonnen ] +[ edits from Lonnen ] + Fix for disappearing horizontal scroll bar regression http://code.google.com/p/processing/issues/detail?id=316 @@ -7430,19 +8855,19 @@ On a happier note, the changes: + shearX and shearY not properly implemented with P2D and JAVA2D http://code.google.com/p/processing/issues/detail?id=452 -+ frame.setResizable(true) does not enable maximize button. ++ frame.setResizable(true) does not enable maximize button. Thanks to Christian Thiemann for a workaround. http://code.google.com/p/processing/issues/detail?id=467 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0191 - 30 September 2010 Bug fix release. Contains major fixes to 3D for Android. -[ changes ] +[ changes ] + Added option to preferences panel to enable/disable smoothing of text inside the editor. @@ -7450,7 +8875,7 @@ Bug fix release. Contains major fixes to 3D for Android. + Added more anti-aliasing to the Linux interface. Things were downright ugly in places where defaults different from Windows and Mac OS X. -[ bug fixes ] +[ bug fixes ] + Fix a problem with Linux permissions in the download. http://code.google.com/p/processing/issues/detail?id=343 @@ -7463,7 +8888,7 @@ Bug fix release. Contains major fixes to 3D for Android. + Remove extraneous console messages on export. -+ When exporting, don't include a library multiple times. ++ When exporting, don't include a library multiple times. + Fixed a problem where no spaces in the size() command caused an error. http://code.google.com/p/processing/issues/detail?id=390 @@ -7497,34 +8922,34 @@ Bug fix release. Contains major fixes to 3D for Android. + Finish screen pixels/texture operations in A3D http://code.google.com/p/processing/issues/detail?id=298 -+ Fixed a bug in the camera handling. This was a quite urgent issue, ++ Fixed a bug in the camera handling. This was a quite urgent issue, since affected pretty much everything. It went unnoticed until now because the math error canceled out with the default camera settings. http://forum.processing.org/topic/possible-3d-bug -+ Also finished the implementation of the getImpl() method in PImage, - so it initializes the texture of the new image in A3D mode. ++ Also finished the implementation of the getImpl() method in PImage, + so it initializes the texture of the new image in A3D mode. This makes the CubicVR example to work fine. -[ core ] +[ core ] + Fix background(PImage) for OpenGL http://code.google.com/p/processing/issues/detail?id=336 -+ Skip null entries with trim(String[]) ++ Skip null entries with trim(String[]) + Fix NaN with PVector.angleBetween http://code.google.com/p/processing/issues/detail?id=340 + Fix missing getFloat() method in XML library -+ Make sure that paths are created with saveStream(). ++ Make sure that paths are created with saveStream(). (saveStream() wasn't working when intermediate directories didn't exist) -+ Make createWriter() use an 8k buffer by default. ++ Make createWriter() use an 8k buffer by default. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0190 - 18 August 2010 @@ -7534,18 +8959,18 @@ are some problems with fonts. If you're using text, especially with PDFs, you may want to wait until the next release. Android users should read the Wiki (http://wiki.processing.org/w/Android) -which has a lot of new information. +which has a lot of new information. -[ android ] +[ android ] -+ Added a new menu to cover enabling/disabling Android mode. ++ Added a new menu to cover enabling/disabling Android mode. -+ Added a Permissions dialog, so that you can set permissions for your ++ Added a Permissions dialog, so that you can set permissions for your applications, e.g. so you can read from the internet or save files. -+ Added support for icons. Put files named icon-32.png, icon-48.png, ++ Added support for icons. Put files named icon-32.png, icon-48.png, and icon-72.png in your sketch folder, and they'll be added to your - project when it's created. Otherwise you'll get an ugly blue dot + project when it's created. Otherwise you'll get an ugly blue dot default icon. You've been warned. + Finish implementing the size() command on Android. See the Wiki for notes. @@ -7562,7 +8987,7 @@ which has a lot of new information. + Fix text ascent/descent problem, text("blah\nblah") wasn't working. -+ Fixed how the manifest file is read/written. ++ Fixed how the manifest file is read/written. http://dev.processing.org/bugs/show_bug.cgi?id=1429 http://code.google.com/p/processing/issues/detail?id=221 @@ -7581,18 +9006,18 @@ which has a lot of new information. + Fix errors showing up that .java files were duplicates. http://code.google.com/p/processing/issues/detail?id=232 -[ core ] +[ core ] + Changed skewX/Y to shearX/Y. -+ ENABLE_NATIVE_FONTS was being ignored, native fonts were always used ++ ENABLE_NATIVE_FONTS was being ignored, native fonts were always used in some cases. However, this broke some other things. But that's why this is a pre-release, not a final. -[ xml fixes and changes ] +[ xml fixes and changes ] + Changed the XML constructor to take a String for a node name, instead of - parsing a document from a String. Instead, use XMLElement.parse(String) + parsing a document from a String. Instead, use XMLElement.parse(String) if you want to read a file. + Added getBoolean() methods. @@ -7621,9 +9046,9 @@ which has a lot of new information. + Update XMLElement constructor problem. http://code.google.com/p/processing/issues/detail?id=342 -[ environment ] +[ environment ] -+ Added more specific language to Lnux/Sun/Java error messages on Linux. ++ Added more specific language to Lnux/Sun/Java error messages on Linux. Also added support for "Oracle" in the name. + Fix the New/Open buttons on the toolbar @@ -7641,7 +9066,7 @@ which has a lot of new information. http://code.google.com/p/processing/issues/detail?id=15 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.2.1 (REV 0189) - 14 July 2010 @@ -7650,43 +9075,43 @@ Fix for a problem with some static-mode programs. See below for the other changes since 1.1. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.2 (REV 0188) - 13 July 2010 -Changes too numerous to mention, see the notes below for all the +Changes too numerous to mention, see the notes below for all the revisions that followed the 1.1 release in March. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0187 - 12 July 2010 -More bug fixes, and one new treat for OS X users. Hopefully we're about +More bug fixes, and one new treat for OS X users. Hopefully we're about set to call this one 1.2. Please test and report any issues you find: http://code.google.com/p/processing/issues/list -[ additions ] +[ additions ] -+ On Mac OS X, you're no longer required to have a sketch window open at ++ On Mac OS X, you're no longer required to have a sketch window open at all times. This will make the application feel more Mac-like--a little more elegant and trendy and smug with superiority. -+ Added a warning to the Linux version to tell users that they should be ++ Added a warning to the Linux version to tell users that they should be using the official version of Java from Sun if they're not. http://wiki.processing.org/w/Supported_Platforms#Linux - There isn't a perfect way to detect whether Sun Java is in use, - so please let us know how it works or if you have a better idea. + There isn't a perfect way to detect whether Sun Java is in use, + so please let us know how it works or if you have a better idea. -[ fixes ] +[ fixes ] + "Unexpected token" error when creating classes with recent pre-releases. http://code.google.com/p/processing/issues/detail?id=292 -+ Prevent horizontal scroll offset from disappearing. - Thanks to Christian Thiemann for the fix. ++ Prevent horizontal scroll offset from disappearing. + Thanks to Christian Thiemann for the fix. http://code.google.com/p/processing/issues/detail?id=280 http://code.google.com/p/processing/issues/detail?id=10 @@ -7698,26 +9123,26 @@ http://code.google.com/p/processing/issues/list http://code.google.com/p/processing/issues/detail?id=303 + Added requestFocusInWindow() call to replace Apple's broken requestFocus(), - which should return the previous behavior of sketches getting focus + which should return the previous behavior of sketches getting focus immediately when loaded in a web browser. http://code.google.com/p/processing/issues/detail?id=279 -+ Add getDocumentBase() version of createInput() for Internet Explorer. ++ Add getDocumentBase() version of createInput() for Internet Explorer. Without this, sketches will crash when trying to find files on a web server that are not in the exported .jar file. This fix is only for IE. Yay IE! -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0186 - 26 June 2010 Minor updates following up on 0185. -[ mixed bag ] +[ mixed bag ] + Android SDK requirement is now API 7 (Android 2.1), because Google has - deprecated API 6 (2.0.1). + deprecated API 6 (2.0.1). + More Linux PDF fixes from Matthias Breuer. Thanks! @@ -7730,18 +9155,18 @@ Minor updates following up on 0185. + Updated the included examples with recent changes. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0185 - 20 June 2010 -Primarily a bug fix release. The biggest change are a couple tweaks for +Primarily a bug fix release. The biggest change are a couple tweaks for problems caused by Apple's Update 2 for Java on OS X, so this should make -Processing usable on Macs again. +Processing usable on Macs again. -[ bug fixes ] +[ bug fixes ] -+ Fix for Apple bug that caused an assertion failure when requestFocus() ++ Fix for Apple bug that caused an assertion failure when requestFocus() was called in some situations. This was causing the PDE to become unusable for opening sketches, and focus highlighting was no longer happening. http://code.google.com/p/processing/issues/detail?id=258 @@ -7766,14 +9191,14 @@ Processing usable on Macs again. also added begin/endDraw between frames http://dev.processing.org/bugs/show_bug.cgi?id=1227 -[ additions ] +[ additions ] + Add the changes for "Copy as HTML" to replace the "Copy for Discourse" function, now that we've shut down the old YaBB discourse board. http://code.google.com/p/processing/issues/detail?id=271 -+ Option to disable re-opening sketches when you start Processing. - The default will stay the same, but if you don't like the feature, ++ Option to disable re-opening sketches when you start Processing. + The default will stay the same, but if you don't like the feature, alter your preferences.txt file to change: last.sketch.restore=true to the following: @@ -7788,7 +9213,7 @@ Processing usable on Macs again. http://code.google.com/p/processing/issues/detail?id=179 Those bugs are not yet fixed, but will be addressed in future releases. -+ Option to change the default naming of sketches via preferences.txt. ++ Option to change the default naming of sketches via preferences.txt. First, you can change the prefix, which defaults to: editor.untitled.prefix=sketch_ And the suffix is handled using dates. The current default (since 1.0) is: @@ -7806,13 +9231,13 @@ Processing usable on Macs again. + Added option to launch a sketch directly w/ linux. Thanks to Larry Kyrala. http://dev.processing.org/bugs/show_bug.cgi?id=1549 -+ Pass actual exceptions from InvocationTargetException in registered ++ Pass actual exceptions from InvocationTargetException in registered methods, which improves how exceptions are reported with libraries. -+ Added loading.gif to the js version of the applet loader. Not sure ++ Added loading.gif to the js version of the applet loader. Not sure if this is actually working or not, but it's there. -[ android ] +[ android ] + Added permissions for INTERNET and WRITE_EXTERNAL_STORAGE to the default AndroidManifest.xml file. This will be addressed in greater detail here: @@ -7823,25 +9248,25 @@ Processing usable on Macs again. + Lots of work happening underneath with regards to Android, more updates soon as things start evening out a bit. -+ Defaulting to a WVGA screen for the default Processing AVD. ++ Defaulting to a WVGA screen for the default Processing AVD. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0184 - 14 April 2010 -Pre-release version with more bug fixes. Proper release notes will +Pre-release version with more bug fixes. Proper release notes will accompany an actual release. If you're curious in the meantime, look at todo.txt and done.txt from the source tree. -+ The 'Export' option now works in Android, so that you can get at ++ The 'Export' option now works in Android, so that you can get at the debug APK that's created. -+ Problems finding javac.exe on Windows should now be fixed. ++ Problems finding javac.exe on Windows should now be fixed. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0183 - 31 March 2010 @@ -7850,10 +9275,10 @@ Bug fixes for Android, should remove the API v5 requirement and make things work fine with API v6, the new minimum. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -PROCESSING REV 0182 - 29 March 2010 +PROCESSING REV 0182 - 29 March 2010 Bug fix pre-release. This updates three areas: @@ -7867,7 +9292,7 @@ A more thorough revisions update will be written for the next full release version (1.2? 1.5? 2.0?) that includes all these changes. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0181 - 19 March 2010 @@ -7875,27 +9300,27 @@ PROCESSING REV 0181 - 19 March 2010 Another update for the preprocessor changes (see below). -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0180 - 15 March 2010 -This is a interim release with a reworked preprocessor that adds Java 5 -syntax. We're releasing this interim version because we need help testing +This is a interim release with a reworked preprocessor that adds Java 5 +syntax. We're releasing this interim version because we need help testing it since it has an impact on any sketch created in the Processing environment. Basically, we mighta goofed something up big, and we wanna catch it before -we throw it to the wolves. +we throw it to the wolves. The release also fixes a number of preprocessor bugs. Those changes will -be documented a bit later. +be documented a bit later. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.1 (REV 0179) - 11 March 2010 -This is the first general-purpose release since 1.0.9. The text below merges +This is the first general-purpose release since 1.0.9. The text below merges all of the changes from all the interim revisions, with the exception of the changes for the upcoming Android tools, which are not enabled in this release. @@ -7906,15 +9331,15 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. [ font changes ] -+ It's no longer necessary to use textFont() before text() and other - text-handling functions. The default "SansSerif" font is used, which - varies by platform. ++ It's no longer necessary to use textFont() before text() and other + text-handling functions. The default "SansSerif" font is used, which + varies by platform. -+ Also in this release, the createFont() method will only load characters - as they are used, which should greatly improve the font situation on ++ Also in this release, the createFont() method will only load characters + as they are used, which should greatly improve the font situation on non-Roman systems like Japanese. This will use far less memory, and should - be all around much more efficient. Formerly, createFont() took several - seconds to run, depending on the speed of your system. + be all around much more efficient. Formerly, createFont() took several + seconds to run, depending on the speed of your system. http://dev.processing.org/bugs/show_bug.cgi?id=1111 + Fixed a problem with the Create Font tool ignoring the 'smooth' setting @@ -7923,13 +9348,13 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. + Fixed a separate problem with the createFont() method also ignoring the 'smooth' setting. -+ With the Create Font tool, you can also specify what Unicode character ++ With the Create Font tool, you can also specify what Unicode character blocks you'd like to use, making a much smaller font. + Fonts are no longer power of 2 by default. This should also make them more memory efficient. With future OpenGL updates, this will work even better. -[ other changes ] +[ other changes ] + Lots of edits to the HTML that's used for exported applets. If JavaScript is enabled, Sun's new loading functions are used, which offer the best @@ -7938,14 +9363,14 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. + Changed the OpenGL HTML template to load differently, which should fix a NullPointerException in JOGLAppletLanucher with Java 6 Update 18 on Windows, - and should also be more efficient altogether, because the JOGL libraries can + and should also be more efficient altogether, because the JOGL libraries can be downloaded just once from Sun, rather than for each sketch that uses them. http://dev.processing.org/bugs/show_bug.cgi?id=1452 + Code from Takachin that handles full input method support in the editor for Japanese and other scripts that are more complicated than Roman text. http://dev.processing.org/bugs/show_bug.cgi?id=854 - Thanks Takachin! + Thanks Takachin! + Now using iText 2.1.7. @@ -7955,14 +9380,14 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. + With great help from Hansi, moved the build scripts over to Ant. http://dev.processing.org/bugs/show_bug.cgi?id=151 Also moved the special JRE for Linux and Windows out of SVN. It'll only be - downloaded when 'ant dist' is run. + downloaded when 'ant dist' is run. + Javadoc is slowly improving. More on that later. + Deprecated 'screen', and added screenWidth and screenHeight. Discussion here: http://dev.processing.org/bugs/show_bug.cgi?id=1499 -[ bug fixes ] +[ bug fixes ] + Fix for filter(DILATE/ERODE) from Dave Bollinger http://dev.processing.org/bugs/show_bug.cgi?id=1477 @@ -7982,7 +9407,7 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. + To fix video, and some other libraries on Snow Leopard, exported applications are now explicitly set to run 32-bit on OS X. -+ Fix LITERAL_class so that blah.class syntax can be used in PDE code. ++ Fix LITERAL_class so that blah.class syntax can be used in PDE code. Found and fixed by Christian Thiemann. Thank you! http://dev.processing.org/bugs/show_bug.cgi?id=1466 @@ -8008,37 +9433,37 @@ of release 1.0.10. Which is nice, because release 1.0.10 sounds baffling. + Fixed a problem where imports inside comments were being included. -[ keys ] +[ keys ] -+ Added ctrl-ins, shift-ins, shift-delete for cut/copy/paste on Windows and ++ Added ctrl-ins, shift-ins, shift-delete for cut/copy/paste on Windows and Linux, but disabled by default on Mac OS X. You can change the setting by altering "editor.keys.alternative_cut_copy_paste" in preferences.txt. http://dev.processing.org/bugs/show_bug.cgi?id=162 -+ Added a preference to change shift-backspace to just mean backspace, ++ Added a preference to change shift-backspace to just mean backspace, rather than delete. Set this entry in preferences.txt: editor.keys.shift_backspace_is_delete = true http://dev.processing.org/bugs/show_bug.cgi?id=1463 -+ Added an option for home and end keys traveling to the start/end of the ++ Added an option for home and end keys traveling to the start/end of the current line rather than the beginning/ending of a sketch. The latter is the HIG default for Mac OS X, but drives some people nuts. Change with: editor.keys.home_and_end_travel_far = false -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0178 - 4 March 2010 Tons of Android work in this release. A2D has been tested and runs correctly for all of the examples in "Basics" and "Topics". A3D is not quite finished -yet, and the size() command is still causing crashes. +yet, and the size() command is still causing crashes. This release also contains lots of work on Android Mode for the PDE, which is being worked on by Jonathan Feinberg. -[ core ] +[ core ] + Fix for filter(DILATE/ERODE) from Dave Bollinger http://dev.processing.org/bugs/show_bug.cgi?id=1477 @@ -8048,7 +9473,7 @@ is being worked on by Jonathan Feinberg. + Added implementation for get/set methods inside PImage (w/o pixels[]) -[ fixes to android core ] +[ fixes to android core ] + Fix noLoop() and static-mode sketches. http://dev.processing.org/bugs/show_bug.cgi?id=1467 @@ -8059,7 +9484,7 @@ is being worked on by Jonathan Feinberg. + App not pausing or closing when switching to another activity http://dev.processing.org/bugs/show_bug.cgi?id=1404 -+ Bezier curves were broken in A2D (extra point is drawn connecting the ++ Bezier curves were broken in A2D (extra point is drawn connecting the shape to the corner). + Fixed other minor bugs in shape drawing. @@ -8076,7 +9501,7 @@ is being worked on by Jonathan Feinberg. + Drastically improve the performance of the time functions (minute() et al) -+ Point wasn't detecting different stroke weights. ++ Point wasn't detecting different stroke weights. + Point wasn't working with strokeWeight > 1. @@ -8098,7 +9523,7 @@ is being worked on by Jonathan Feinberg. + Remove legacy PGraphics3D class from processing.core.android http://dev.processing.org/bugs/show_bug.cgi?id=1402 -[ android mode ] +[ android mode ] + Exception handling is much improved. @@ -8112,7 +9537,7 @@ is being worked on by Jonathan Feinberg. PROCESSING REV 0177 - 21 February 2010 -Fix for the Android tools complaining "Open quote is expected for +Fix for the Android tools complaining "Open quote is expected for attribute "{1}" associated with an element type android:minSdkVersion." Just posting a new revision because it's easier than writing instructions @@ -8126,17 +9551,17 @@ below that (a tipoff being that there's no PDF library on Android...) [ android ] -+ Minimum platform support is changing to 2.0 instead of 1.6. That means ++ Minimum platform support is changing to 2.0 instead of 1.6. That means "Eclair" or later, and goodbye to my T-Mobile G1, undoubtedly the ugliest - cell phone I have ever owned. Hello to Droid and Nexus One. - Performance is very poor on pre-2.0 devices anyway. + cell phone I have ever owned. Hello to Droid and Nexus One. + Performance is very poor on pre-2.0 devices anyway. -+ Known issue: Sketches that use noLoop() are currently broken. ++ Known issue: Sketches that use noLoop() are currently broken. http://dev.processing.org/bugs/show_bug.cgi?id=1467 + Added support for libraries and the code folder. -+ Classes have moved to the processing.core package instead of ++ Classes have moved to the processing.core package instead of processing.android.core. + Slashes in the SDK path are now escaped properly on Windows. @@ -8149,7 +9574,7 @@ below that (a tipoff being that there's no PDF library on Android...) + loadFont() and text() now work properly. createFont() has not been tested. -[ changes ] +[ changes ] + Lots of edits to the HTML that's used for exported applets. If JavaScript is enabled, Sun's new loading functions are used, which offer the best @@ -8158,17 +9583,17 @@ below that (a tipoff being that there's no PDF library on Android...) + Changed the OpenGL HTML template to load differently, which should fix a NullPointerException in JOGLAppletLanucher with Java 6 Update 18 on Windows, - and should also be more efficient altogether, because the JOGL libraries can + and should also be more efficient altogether, because the JOGL libraries can be downloaded just once from Sun, rather than for each sketch that uses them. http://dev.processing.org/bugs/show_bug.cgi?id=1452 + Code from Takachin that handles full input method support in the editor for Japanese and other scripts that are more complicated than Roman text. http://dev.processing.org/bugs/show_bug.cgi?id=854 - Thanks Takachin! + Thanks Takachin! + Downgraded the PDF library to use iText 1.5.4, because later versions seem - to load slower, and don't seem to offer additional benefits. If the PDF + to load slower, and don't seem to offer additional benefits. If the PDF library gets worse, please post a bug and we'll go back to the 2.x release we were using, or upgrade to the more recent 5.x series. @@ -8178,13 +9603,13 @@ below that (a tipoff being that there's no PDF library on Android...) + With great help from Hansi, moved the build scripts over to Ant. http://dev.processing.org/bugs/show_bug.cgi?id=151 Also moved the special JRE for Linux and Windows out of SVN. It'll only be - downloaded when 'ant dist' is run. This makes the build and maintenance - more of a mess for me, but will save me from people whining about the + downloaded when 'ant dist' is run. This makes the build and maintenance + more of a mess for me, but will save me from people whining about the large files. + Javadoc is slowly improving. More on that later. -[ bug fixes ] +[ bug fixes ] + Updated JNA to version 3.2.4 to support Windows 7 64-bit http://dev.processing.org/bugs/show_bug.cgi?id=1424 @@ -8199,7 +9624,7 @@ below that (a tipoff being that there's no PDF library on Android...) + To fix video, and some other libraries on Snow Leopard, exported applications are now explicitly set to run 32-bit on OS X. -+ Fix LITERAL_class so that blah.class syntax can be used in PDE code. ++ Fix LITERAL_class so that blah.class syntax can be used in PDE code. Found and fixed by Christian Thiemann. Thank you! http://dev.processing.org/bugs/show_bug.cgi?id=1466 @@ -8210,9 +9635,9 @@ below that (a tipoff being that there's no PDF library on Android...) + If you overwrite PApplet.main(), you're responsible for what happens. http://dev.processing.org/bugs/show_bug.cgi?id=1446 -[ keys ] +[ keys ] -+ Added ctrl-ins, shift-ins, shift-delete for cut/copy/paste on Windows and ++ Added ctrl-ins, shift-ins, shift-delete for cut/copy/paste on Windows and Linux, but disabled by default on Mac OS X. You can change the setting by altering "editor.keys.alternative_cut_copy_paste" in preferences.txt. http://dev.processing.org/bugs/show_bug.cgi?id=162 @@ -8222,18 +9647,18 @@ below that (a tipoff being that there's no PDF library on Android...) editor.keys.shift_backspace_is_delete = true http://dev.processing.org/bugs/show_bug.cgi?id=1463 -+ Added an option for home and end keys traveling to the start/end of the ++ Added an option for home and end keys traveling to the start/end of the current line rather than the beginning/ending of a sketch. The latter is the HIG default for Mac OS X, but drives some people nuts. Change with: editor.keys.home_and_end_travel_far = false [ fonts ] -+ Starting in this release, the createFont() method will only load characters - as they are used, which should greatly improve the font situation on ++ Starting in this release, the createFont() method will only load characters + as they are used, which should greatly improve the font situation on non-Roman systems like Japanese. This will use far less memory, and should - be all around much more efficient. Formerly, createFont() took several - seconds to run, depending on the speed of your system. + be all around much more efficient. Formerly, createFont() took several + seconds to run, depending on the speed of your system. http://dev.processing.org/bugs/show_bug.cgi?id=1111 + Fixed a problem with the Create Font tool ignoring the 'smooth' setting @@ -8242,14 +9667,14 @@ below that (a tipoff being that there's no PDF library on Android...) + Fixed a separate problem with the createFont() method also ignoring the 'smooth' setting. -+ With the Create Font tool, you can also specify what Unicode character ++ With the Create Font tool, you can also specify what Unicode character blocks you'd like to use, making a much smaller font. + Fonts are no longer power of 2 by default. This should also make them more memory efficient. With future OpenGL updates, this will work even better. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING REV 0172 through 0175 @@ -8257,7 +9682,7 @@ PROCESSING REV 0172 through 0175 These releases are mostly about Android (listed at the top), but also contain any interim fixes that happened in the meantime. -[ android ] +[ android ] + Fix problem with Android HTML dialog box several
items showing up when first loading @@ -8279,11 +9704,11 @@ any interim fixes that happened in the meantime. + Updates for r4 version of the SDK. -[ changes ] +[ changes ] -+ In the editor toolbar, shift-new and shift-open on the toolbar open a - new window. Also, when shift is down, change text of the toolbar item - to represent what it does. ++ In the editor toolbar, shift-new and shift-open on the toolbar open a + new window. Also, when shift is down, change text of the toolbar item + to represent what it does. + Replaced com.apple.eawt.Application invocation to deal with deprecation. This may cause problems with older releases (or on 10.4 or 10.5), not sure. @@ -8291,13 +9716,13 @@ any interim fixes that happened in the meantime. + Use xdg-open as launcher on linux http://dev.processing.org/bugs/show_bug.cgi?id=1358 -+ Default wildcard imports are causing naming conflicts, changed how ++ Default wildcard imports are causing naming conflicts, changed how they're set up in the preferences file. http://dev.processing.org/bugs/show_bug.cgi?id=1103 + Changed createInputRaw() to only bother checking URLs if : present -[ bug fixes ] +[ bug fixes ] + Re-enabled hack for temporary clipping. Clipping still needs to be implemented properly, however. Please help! @@ -8315,7 +9740,7 @@ any interim fixes that happened in the meantime. + Fixed a problem where imports inside comments were being included. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.9 (REV 0171) - 20 October 2009 @@ -8324,7 +9749,7 @@ Happy birthday to Casey! [ bug fixes ] -+ Removed NPOT texture support until further testing, because it was ++ Removed NPOT texture support until further testing, because it was resulting in blurring images in OPENGL sketches. http://dev.processing.org/bugs/show_bug.cgi?id=1352 @@ -8332,12 +9757,12 @@ Happy birthday to Casey! http://dev.processing.org/bugs/show_bug.cgi?id=786 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.8 (REV 0170) - 18 October 2009 -A bonfire of bug fixes. +A bonfire of bug fixes. [ environment ] @@ -8371,26 +9796,26 @@ A bonfire of bug fixes. http://dev.processing.org/bugs/show_bug.cgi?id=1332 http://dev.processing.org/bugs/show_bug.cgi?id=1092 -+ Saving the project with the same name (but different case) ++ Saving the project with the same name (but different case) as an existing tab was deleting code on Windows and OS X. http://dev.processing.org/bugs/show_bug.cgi?id=1102 -[ core ] +[ core ] -+ filter(RGB) supposed to be filter(OPAQUE) ++ filter(RGB) supposed to be filter(OPAQUE) http://dev.processing.org/bugs/show_bug.cgi?id=1346 -+ Implement non-power-of-2 textures for OpenGL (on cards where available). ++ Implement non-power-of-2 textures for OpenGL (on cards where available). This is a partial fix for texture edge problems: http://dev.processing.org/bugs/show_bug.cgi?id=602 + Fix get() when used with save() in OpenGL mode -+ Immediately update projection with OpenGL. In the past, projection - updates required a new frame. This also prevents camera/project from ++ Immediately update projection with OpenGL. In the past, projection + updates required a new frame. This also prevents camera/project from being reset when the drawing size is changed. -+ Removed an error that caused the cameraNear value to be set to -8. ++ Removed an error that caused the cameraNear value to be set to -8. This may cause other problems with drawing/clipping however. + Removed methods from PApplet that use doubles. These were only temporarily @@ -8408,18 +9833,18 @@ A bonfire of bug fixes. + Updated Quaqua to 6.2 on Mac OS X. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.7 (REV 0169) - 4 September 2009 -Bug fixes and updates, also some tweaks for Mac OS X Snow Leopard. +Bug fixes and updates, also some tweaks for Mac OS X Snow Leopard. -[ changes ] +[ changes ] + Tweaks for Mac OS X Snow Leopard, to force it to run in 32-bit mode. This should bring back the video library (if temporarily), and hopefully - fix serial as well, though I didn't have a serial device handy to test. + fix serial as well, though I didn't have a serial device handy to test. + Fix problem where line highlighting was off in 'static' mode. http://dev.processing.org/bugs/show_bug.cgi?id=1263 @@ -8430,11 +9855,11 @@ Bug fixes and updates, also some tweaks for Mac OS X Snow Leopard. + PVector.angleDistance() returning NaN due to precision errors http://dev.processing.org/bugs/show_bug.cgi?id=1316 -+ Removed a major try/catch block from PApplet.main(), hopefully ++ Removed a major try/catch block from PApplet.main(), hopefully this will allow some exception stuff to come through properly. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.6 (REV 0168) - 12 August 2009 @@ -8442,7 +9867,7 @@ PROCESSING 1.0.6 (REV 0168) - 12 August 2009 Bug fixes and minor changes. Most important are replacement JOGL libraries so that OpenGL applets won't present an "expired certificate" error. -[ bug fixes ] +[ bug fixes ] + Replaced the faulty JOGL library that had expired certificates (Sun bug). http://dev.processing.org/bugs/show_bug.cgi?id=1271 @@ -8476,29 +9901,29 @@ so that OpenGL applets won't present an "expired certificate" error. + PDF member functions set protected instead of private http://dev.processing.org/bugs/show_bug.cgi?id=1276 -+ On OS X, update Info.plist to be 32/64 explicit and also updated ++ On OS X, update Info.plist to be 32/64 explicit and also updated JavaApplicationStub for update 4. -+ Clicking the preferences location in the Preferences window will - now open the parent folder for the preferences file. ++ Clicking the preferences location in the Preferences window will + now open the parent folder for the preferences file. http://dev.processing.org/bugs/show_bug.cgi?id=1279 + Update to Java 6 update 15 for the Windows and Linux releases. -[ fixed earlier ] +[ fixed earlier ] + Mangled menu text with Java 6u10. http://dev.processing.org/bugs/show_bug.cgi?id=1065 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.5 (REV 0167) - 7 June 2009 Bug fix release, mostly dealing with regressions from 1.0.4. -[ bug fixes ] +[ bug fixes ] + Make the tab key work again inside the editor http://dev.processing.org/bugs/show_bug.cgi?id=1267 @@ -8515,20 +9940,20 @@ Bug fix release, mostly dealing with regressions from 1.0.4. + Updated reference files. -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.4 (REV 0166) - 31 May 2009 -Bug fix release. +Bug fix release. -[ changes ] +[ changes ] + Changed the workaround for Apple's Java bug related to the menus in OS X. Rather than placing the menubar inside the sketch window, File > Sketchbook and File > Examples are simply dimmed out. Instead, use the Open button on the toolbar, which provides access to the same items. The preference - to place the menu bar inside the window is still available, in case you + to place the menu bar inside the window is still available, in case you prefer the previous workaround. http://dev.processing.org/bugs/show_bug.cgi?id=786 @@ -8536,7 +9961,7 @@ Bug fix release. [ bug fixes ] -+ Fixed IDE crash when changing color scheme on windows ++ Fixed IDE crash when changing color scheme on windows http://dev.processing.org/bugs/show_bug.cgi?id=1237 + Typo in the Linux shell script was preventing it from running @@ -8545,16 +9970,16 @@ Bug fix release. + OS X finder info on application updated to say 1.0.4 http://dev.processing.org/bugs/show_bug.cgi?id=1226 -+ Removed warning message "Non-String for 8 value in 'Properties' ++ Removed warning message "Non-String for 8 value in 'Properties' sub-dictionary in 'Java' sub-dictionary of Info.plist" on OS X + Added warning to build script for users on OS X 10.4 http://dev.processing.org/bugs/show_bug.cgi?id=1179 -+ Disable point() going to set() from PGraphicsJava2D. The set() command ++ Disable point() going to set() from PGraphicsJava2D. The set() command doesn't honor alpha consistently, and it also causes problems with PDF -+ PImage cacheMap problem when using PImage.get() ++ PImage cacheMap problem when using PImage.get() http://dev.processing.org/bugs/show_bug.cgi?id=1245 + Fix problems with > 512 points and P3D/OPENGL @@ -8574,11 +9999,11 @@ Bug fix release. + Fix significant point() and set() slowdown on OS X http://dev.processing.org/bugs/show_bug.cgi?id=1094 -[ known issues ] +[ known issues ] -+ Currently no 64-bit support for any platforms. On some platforms, you'll ++ Currently no 64-bit support for any platforms. On some platforms, you'll simply need to replace the Java folder with the distribution with something - more suitable for your operating system. + more suitable for your operating system. + Command line support is currently broken http://dev.processing.org/bugs/show_bug.cgi?id=1048 @@ -8593,12 +10018,12 @@ Bug fix release. + See dev.processing.org/bugs for much, much more! -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.3 (REV 0165) - 24 February 2009 -Bug fix release to repair a couple of regressions caused by changes in 1.0.2, +Bug fix release to repair a couple of regressions caused by changes in 1.0.2, as well as a couple other new problems encountered since. [ bug fixes ] @@ -8617,31 +10042,31 @@ as well as a couple other new problems encountered since. + ArrayIndexOutOfBoundsException with point() http://dev.processing.org/bugs/show_bug.cgi?id=1168 -[ changes ] +[ changes ] + Update to iText 2.1.4 for the PDF library -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.2 (REV 0164) - 21 February 2009 This release fixes many bugs and adds two minor functions to the XML library. -[ bug fixes ] +[ bug fixes ] + Empty "code" folder causing problems with Export http://dev.processing.org/bugs/show_bug.cgi?id=1084 -+ Sketches not loading when .pde file is opened from the Windows Explorer - on Asian Windows systems. ++ Sketches not loading when .pde file is opened from the Windows Explorer + on Asian Windows systems. http://dev.processing.org/bugs/show_bug.cgi?id=1089 + Disable copying of metadata and resource forks in OS X build http://dev.processing.org/bugs/show_bug.cgi?id=1098 -+ Suppress goofy Apple error message about JVMArchs ++ Suppress goofy Apple error message about JVMArchs + StringIndexOutOfBoundsException caused by import statements with no dots http://dev.processing.org/bugs/show_bug.cgi?id=1145 @@ -8693,7 +10118,7 @@ This release fixes many bugs and adds two minor functions to the XML library. http://dev.processing.org/bugs/show_bug.cgi?id=1099 http://dev.processing.org/bugs/show_bug.cgi?id=1144 -+ Fix algorithm for quadratic to cubic curve conversion ++ Fix algorithm for quadratic to cubic curve conversion http://dev.processing.org/bugs/show_bug.cgi?id=1122 Thanks to user bits.in.shambles for providing a fix. @@ -8705,7 +10130,7 @@ This release fixes many bugs and adds two minor functions to the XML library. + Fix for getChild() and getChildren() with XML elements that have null names -[ additions ] +[ additions ] + Added listChildren() method to XMLElement @@ -8713,7 +10138,7 @@ This release fixes many bugs and adds two minor functions to the XML library. in XMLElement -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0.1 (REV 0163) - 29 November 2008 @@ -8724,11 +10149,11 @@ in the last few months here: http://processing.org/reference/changes.html Also see the "known issues" section of the troubleshooting page: http://processing.org/reference/troubleshooting/#known -This release (1.0.1) fixes a handful of issues that only showed up once we +This release (1.0.1) fixes a handful of issues that only showed up once we had more testing, particularly with the wider audience we've received in the past week following the announcement. -[ bug fixes ] +[ bug fixes ] + ArrayIndexOutOfBoundsException with File > New http://dev.processing.org/bugs/show_bug.cgi?id=1067 @@ -8752,7 +10177,7 @@ past week following the announcement. + Fixed problem where small ellipses weren't showing up. -[ changes ] +[ changes ] + Implement multi-line tab via tab key (also outdent) http://dev.processing.org/bugs/show_bug.cgi?id=1075 @@ -8761,7 +10186,7 @@ past week following the announcement. http://dev.processing.org/bugs/show_bug.cgi?id=1064 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PROCESSING 1.0 (REV 0162) - 24 November 2008 @@ -8769,22 +10194,22 @@ PROCESSING 1.0 (REV 0162) - 24 November 2008 Processing 1.0 has arrived! You can read an overview of changes introduced in the last few months here: http://processing.org/reference/changes.html -[ known issues ] +[ known issues ] -+ Sketches that size(w, h, OPENGL) and do not clear the background on each ++ Sketches that size(w, h, OPENGL) and do not clear the background on each frame can cause major flickering or problems when the screen clears anyway. There are several possible solutions: 1. You may need to disable the default 2x smoothing by using hint(DISABLE_OPENGL_2X_SMOOTH). - + 2. Update the drivers for your graphics card. 3. Get a decent graphics card -- the OpenGL renderer is for advanced - use, we don't support using it with cheaper built-in graphics hardware - like the Intel GMA 950. + use, we don't support using it with cheaper built-in graphics hardware + like the Intel GMA 950. - 4. If you're running Windows Vista, try disabling the Aero theme. + 4. If you're running Windows Vista, try disabling the Aero theme. This flickering issue is being tracked here: http://dev.processing.org/bugs/show_bug.cgi?id=1056 @@ -8794,23 +10219,23 @@ in the last few months here: http://processing.org/reference/changes.html reproduce it on any of our test machines, which has delayed a fix. http://dev.processing.org/bugs/show_bug.cgi?id=986 -+ With P2D, P3D, and OPENGL, series of connected lines (such as the stroke - around a polygon, triangle, or ellipse) produce unattractive results when ++ With P2D, P3D, and OPENGL, series of connected lines (such as the stroke + around a polygon, triangle, or ellipse) produce unattractive results when strokeWeight is set. http://dev.processing.org/bugs/show_bug.cgi?id=955 + Unlike most applications, the menu bar is inside the editor window when - Processing is used with Mac OS X 10.5. This is a workaround for an Apple - bug in Java 1.5 and 1.6 on Mac OS X 10.5 that causes the menu bar to be + Processing is used with Mac OS X 10.5. This is a workaround for an Apple + bug in Java 1.5 and 1.6 on Mac OS X 10.5 that causes the menu bar to be so excessively slow that the application appears to have crashed. http://dev.processing.org/bugs/show_bug.cgi?id=786 Please file a bug report with Apple at bugreporter.apple.com if you want - this fixed. The problem has existed since the spring, and we first filed - a bug with them in June, and we have received no indication that it when + this fixed. The problem has existed since the spring, and we first filed + a bug with them in June, and we have received no indication that it when it will be fixed, or if it will ever be fixed. - Or if you want to take your chances with the slow menu bar, + Or if you want to take your chances with the slow menu bar, you can change the default setting in the Preferences window. + Sketches that use the video library plus OpenGL have a problem on some @@ -8827,16 +10252,16 @@ in the last few months here: http://processing.org/reference/changes.html + The first few frames of OpenGL sketches on Windows run slowly. http://dev.processing.org/bugs/show_bug.cgi?id=874 -+ When used with P3D, strokeWeight does not interpolate the Z-coordinates - of the lines, which means that when rotated, these flat lines may - disappear. (Since, uh, lines are, you know, flat.) The OPENGL renderer - setting does not share this problem because it always draws lines ++ When used with P3D, strokeWeight does not interpolate the Z-coordinates + of the lines, which means that when rotated, these flat lines may + disappear. (Since, uh, lines are, you know, flat.) The OPENGL renderer + setting does not share this problem because it always draws lines perpendicular to the screen (which we hope to do in a future release). http://dev.processing.org/bugs/show_bug.cgi?id=956 -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . in spite of their historical feel good campiness, i've removed the -notes from earlier releases because this file was getting out of hand. +notes from earlier releases because this file was getting out of hand. diff --git a/build/shared/tools/MovieMaker/src/ch/randelshofer/gui/datatransfer/FileTextFieldTransferHandler.java b/build/shared/tools/MovieMaker/src/ch/randelshofer/gui/datatransfer/FileTextFieldTransferHandler.java index 5288fe7a79..dc56b11578 100644 --- a/build/shared/tools/MovieMaker/src/ch/randelshofer/gui/datatransfer/FileTextFieldTransferHandler.java +++ b/build/shared/tools/MovieMaker/src/ch/randelshofer/gui/datatransfer/FileTextFieldTransferHandler.java @@ -84,7 +84,8 @@ public boolean importData(JComponent comp, Transferable t) { } try { - java.util.List list = (List) t.getTransferData(DataFlavor.javaFileListFlavor); + List list = (List) + t.getTransferData(DataFlavor.javaFileListFlavor); if (list.size() > 0) { File file = (File) list.get(0); @@ -108,9 +109,7 @@ public boolean importData(JComponent comp, Transferable t) { c.setText(file.getPath()); } imported = true; - } catch (UnsupportedFlavorException ex) { - // ex.printStackTrace(); - } catch (IOException ex) { + } catch (UnsupportedFlavorException | IOException ex) { // ex.printStackTrace(); } } @@ -128,11 +127,7 @@ public boolean importData(JComponent comp, Transferable t) { boolean useRead = false; handleReaderImport(r, c, useRead); imported = true; - } catch (UnsupportedFlavorException ex) { - // ex.printStackTrace(); - } catch (BadLocationException ex) { - // ex.printStackTrace(); - } catch (IOException ex) { + } catch (UnsupportedFlavorException | BadLocationException | IOException ex) { // ex.printStackTrace(); } } diff --git a/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/DataAtomOutputStream.java b/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/DataAtomOutputStream.java index ff42b53dda..a1bc78011b 100644 --- a/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/DataAtomOutputStream.java +++ b/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/DataAtomOutputStream.java @@ -11,6 +11,7 @@ package ch.randelshofer.media.quicktime; import java.io.*; +import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import javax.imageio.stream.ImageOutputStreamImpl; @@ -31,7 +32,8 @@ public class DataAtomOutputStream extends FilterOutputStream { ImageOutputStreamImpl impl; - protected static final long MAC_TIMESTAMP_EPOCH = new GregorianCalendar(1904, GregorianCalendar.JANUARY, 1).getTimeInMillis(); + protected static final long MAC_TIMESTAMP_EPOCH = new GregorianCalendar(1904, Calendar.JANUARY, 1).getTimeInMillis(); + /** * The number of bytes written to the data output stream so far. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 1823ea00cf..bbfd28abf5 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -533,10 +533,10 @@ private void createMovie(final File movieFile) { // --------------------------------- // Create the QuickTime movie // --------------------------------- - SwingWorker w = new SwingWorker() { + new SwingWorker() { @Override - protected Object doInBackground() { + protected Throwable doInBackground() { try { // Read image files File[] imgFiles = null; @@ -600,25 +600,23 @@ Dimension findSize(File[] imgFiles) { @Override protected void done() { - Object o; + Throwable t; try { - o = get(); + t = get(); } catch (Exception ex) { - o = ex; + t = ex; } - if (o instanceof Throwable) { - Throwable t = (Throwable) o; + if (t != null) { t.printStackTrace(); JOptionPane.showMessageDialog(MovieMaker.this, - Language.text("movie_maker.error.movie_failed") + "\n" + (t.getMessage() == null ? t.toString() : t.getMessage()), - Language.text("movie_maker.error.sorry"), - JOptionPane.ERROR_MESSAGE); + Language.text("movie_maker.error.movie_failed") + "\n" + + (t.getMessage() == null ? t.toString() : t.getMessage()), + Language.text("movie_maker.error.sorry"), + JOptionPane.ERROR_MESSAGE); } createMovieButton.setEnabled(true); } - }; - w.execute(); - + }.execute(); }//GEN-LAST:event_createMovie @@ -694,7 +692,7 @@ private BufferedImage readImage(File file) { } - private void cannotRead(File file) { + static private void cannotRead(File file) { String path = file.getAbsolutePath(); String msg = Language.interpolate("movie_maker.error.cannot_read", path); System.err.println(msg); diff --git a/build/windows/about.bmp b/build/windows/about.bmp index 52e1c977b3..51a3ba312a 100644 Binary files a/build/windows/about.bmp and b/build/windows/about.bmp differ diff --git a/build/windows/config.xml b/build/windows/config.xml index 1d7955ca7c..1184cb4066 100755 --- a/build/windows/config.xml +++ b/build/windows/config.xml @@ -39,6 +39,11 @@ directory of processing.exe (the current working directory). --> -Djna.boot.library.path=lib -Djna.nounpack=true + + -Dsun.java2d.d3d=false + -Dsun.java2d.ddoffscreen=false + -Dsun.java2d.noddraw=true 1.8.0_60 @@ -53,7 +58,7 @@ An error occurred while starting the application. This application was configured to use a bundled Java Runtime Environment but the runtime is missing or corrupted. If running from a folder with non-ASCII characters, try moving this folder to another location. - Required files could not be found. If running from a folder with non-ASCII characters, try moving this folder to another location. + Required files could not be found. Be sure to first extract the entire Processing folder from the .zip file download. Or if running from a folder with non-ASCII characters, try moving the Processing folder to another location. The registry refers to a nonexistent Java installation or the runtime is corrupted. An application instance is already running. diff --git a/build/windows/processing.bat b/build/windows/processing.bat index c5ec6768af..8f71b553dd 100755 --- a/build/windows/processing.bat +++ b/build/windows/processing.bat @@ -1,3 +1,3 @@ @echo off -.\java\bin\java -cp lib/pde.jar;core/library/core.jar;lib/jna.jar;lib/jna-platform.jar;lib/antlr.jar;lib/ant.jar;lib/ant-launcher.jar processing.app.Base \ No newline at end of file +.\java\bin\java -cp lib\pde.jar;core\library\core.jar;lib\jna.jar;lib\jna-platform.jar;lib\antlr.jar;lib\ant.jar;lib\ant-launcher.jar processing.app.Base diff --git a/core/.gitignore b/core/.gitignore index ba077a4031..84e7b5c836 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -1 +1,2 @@ bin +.idea diff --git a/core/.settings/org.eclipse.jdt.core.prefs b/core/.settings/org.eclipse.jdt.core.prefs index 6c6ce4e4e9..f57dd085ab 100644 --- a/core/.settings/org.eclipse.jdt.core.prefs +++ b/core/.settings/org.eclipse.jdt.core.prefs @@ -98,7 +98,12 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 @@ -107,24 +112,39 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 @@ -133,6 +153,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line @@ -142,32 +163,38 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false org.eclipse.jdt.core.formatter.comment.format_block_comments=true org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=1 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true @@ -180,6 +207,7 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=2 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert @@ -189,6 +217,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -202,11 +231,15 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -233,9 +266,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declar org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -260,13 +298,20 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -310,9 +355,13 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_decla org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -349,9 +398,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -363,20 +415,59 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_decla org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never org.eclipse.jdt.core.formatter.lineSplit=80 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.text_block_indentation=0 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/core/.settings/org.eclipse.jdt.ui.prefs b/core/.settings/org.eclipse.jdt.ui.prefs index 18a5c596a2..1286aca0bb 100644 --- a/core/.settings/org.eclipse.jdt.ui.prefs +++ b/core/.settings/org.eclipse.jdt.ui.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true formatter_profile=_processing -formatter_settings_version=12 +formatter_settings_version=18 org.eclipse.jdt.ui.text.custom_code_templates= sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false @@ -16,10 +16,12 @@ sp_cleanup.always_use_blocks=true sp_cleanup.always_use_parentheses_in_expressions=false sp_cleanup.always_use_this_for_non_static_field_access=false sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false sp_cleanup.convert_to_enhanced_for_loop=false sp_cleanup.correct_indentation=false sp_cleanup.format_source_code=false sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false sp_cleanup.make_local_variable_final=false sp_cleanup.make_parameters_final=false sp_cleanup.make_private_fields_final=true @@ -35,6 +37,7 @@ sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class= sp_cleanup.qualify_static_member_accesses_with_declaring_class=false sp_cleanup.qualify_static_method_accesses_with_declaring_class=false sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=true sp_cleanup.remove_trailing_whitespaces=true sp_cleanup.remove_trailing_whitespaces_all=true sp_cleanup.remove_trailing_whitespaces_ignore_empty=false @@ -48,8 +51,10 @@ sp_cleanup.remove_unused_private_methods=true sp_cleanup.remove_unused_private_types=true sp_cleanup.sort_members=false sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false sp_cleanup.use_blocks=false sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false sp_cleanup.use_parentheses_in_expressions=false sp_cleanup.use_this_for_non_static_field_access=false sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true diff --git a/core/build.xml b/core/build.xml index 93b8f1d9c5..e1bf0fd5fc 100644 --- a/core/build.xml +++ b/core/build.xml @@ -15,17 +15,20 @@ - + + + - - + @@ -34,7 +37,10 @@ - + + + + @@ -45,33 +51,34 @@ includeAntRuntime="false" debug="true" destdir="bin" - classpath="apple.jar; - library/jogl-all.jar; + classpath="apple.jar; + library/jogl-all.jar; library/gluegen-rt.jar" nowarn="true"> - + - + - + - + - + - +
diff --git a/core/done.txt b/core/done.txt index a4d16b206d..a04e597a69 100644 --- a/core/done.txt +++ b/core/done.txt @@ -1,3 +1,471 @@ +0270 (3.5.4) +no changes + + +0269 (3.5.3) +X fix/clean a few file i/o issues +X deal with possible resource leak when loading URLs +X create intermediate folders when saving temp files +X fix resource leaks (open files) in loadJSONObject and loadJSONArray +X get rid of errant 'Could not parse -1 for display' message + +contrib +X Update missing @Deprecated tags in PApplet.java +X https://github.com/processing/processing/pull/5686 + + +0268 (3.5.2) +X Ctrl-click on Mac OS X result in all subsequent clicks reported as right-click +X https://github.com/processing/processing/issues/5765 +X https://github.com/processing/processing/pull/5766 + + +0267 (3.5.1) +X no changes to core in this release + + +0266 (3.5) +X fix javaPlatform variable for newer JDK versions +X https://github.com/processing/processing/pull/5626 +o many fonts installed causes slow startup on macos +o run that on a thread, and make sure default font doesn't need the list loaded +X can't be done, notes in the code for PFont.loadFonts() +X improve startup time when user-specified fonts are not used +X default font will be faster, using ttf/otf is fine +X only createFont("The Font Name") is still slow on macOS +X and PFont.list() +o check again whether element 0,0 in a Table is working +X https://github.com/processing/processing/issues/3011 +X was already checked, made a note and locked the issue + +api changes +X Dict.remove() should return value, not index (for consistency w/ others) +X returns the value removed, not the key, just like remove(key) +X rationale being that if you know the index, you probably know the key +X if unavailable, throw an exception; otherwise no consistent way to indicate error +X add circle() and square() +X add push() and pop() +X make JSONObject.quote() (both versions) public +X should DoubleDict create from Iterable or Map<>? +o (Map is more efficient b/c of size, Iterable more useful) +X Iterable of what, though? Map.Entry? +X sticking with just the Map<> version for now + +contrib +o make tabs into spaces, fixes pixelDensity(2) issue with tabs +o https://github.com/processing/processing/issues/5625 +o https://github.com/processing/processing/pull/5633 +X had to back this fix out again +X Fixes blend mode not being set correctly, fixing #5645 +X https://github.com/processing/processing/issues/5645 +X https://github.com/processing/processing/pull/5647 +X extended SVG support +X https://github.com/processing/processing/pull/4168 +X show a warning when a font isn't what the user expected +X https://github.com/processing/processing/issues/5481 +X https://github.com/processing/processing/pull/5605 + +gohai +X Profile GL3bc is not available on X11GraphicsDevice +X https://github.com/processing/processing/issues/5476 +X https://github.com/processing/processing/pull/5652 + +andres +X silence TIS/TSM warning message with P2D/P3D/OPENGL since macOS 10.13.4 +X https://github.com/processing/processing/issues/5462 +X improve matrix performance in P2D/P3D +X https://github.com/processing/processing/issues/5685 +X Initializing textures loads the pixels array, even if not needed aferwards +X https://github.com/processing/processing/issues/5748 +X Processing 3.4 takes 60 seconds before can edit file +X https://github.com/processing/processing/issues/5707 +X skip Android's SDK folder when adding sketches +X https://github.com/processing/processing/commit/5b653263cc6151f838c11a61689d756901c11e37 +X PShape.attrib() and PShape.setAttrib() are not working +X https://github.com/processing/processing/issues/5560 + +jakub +X Fix freeze when restarting sketch with variables in size +X https://github.com/processing/processing/pull/5708 +X Make sure Ctrl+Left Mouse on MacOS is consistent +X https://github.com/processing/processing/issues/5672 +X https://github.com/processing/processing/pull/5674 +X Stop frame rate counter from exaggerating +X https://github.com/processing/processing/pull/5697 +X Fix vertex buffer initialized with wrong number of components +X https://github.com/processing/processing/pull/5698 +X Recreate FBOs when offscreen PGraphicsOpenGL is resized +X https://github.com/processing/processing/pull/5699 + +cleaning +o WARNING: GL pipe is running in software mode (Renderer ID=0x1020400) +o is this coming from us? if so, need to provide actions +X haven't seen for a while, maybe fixed +X figure our size(img.width, img.height) situation +X just make loadImage() work in settings +X update the wiki and reference +o update wiki/docs to say "don't override sketchXxxx() methods" +o size() command not working to do a resize +X need a programmatic way to set size +o check on performance of the new EDT setup +X present mode is 30-40% slower than windowed +X w/ this example: https://github.com/processing/processing/issues/2423 + + +0265 (3.4) +X change lack of blendMode() to a warning rather than an error in PDF +X rewrite exec() to do threads, also handle fast/excessive output cases +X rewrite requestImage() to fix errors/slowness/concurrency problems + +data classes +X add Double and Long versions of the data classes +X also add subset(long) and subset(double) to PApplet +X change Sort class to use int for comparisons +X sort only uses the sign of the value +X more accurate than float, especially when using double and long values +X consistently implement write(PrintWriter) in the List and Dict classes +X add save(File) to the List and Dict classes +X prevent Table.sort() from throwing NPE with empty cells + +jakub +X Semi-transparent colors do not display properly in PGraphics +X https://github.com/processing/processing/issues/5519 +X Semi-transparent colors do not display properly in PGraphics +X https://github.com/processing/processing/issues/5519 +X https://github.com/processing/processing/pull/5522 + +gohai +X Various ARM-related updates +X https://github.com/processing/processing/pull/5440 +X make P3D work on Linux SBCs using ARM Mali graphics and their ES 3.1 driver +X https://github.com/processing/processing/pull/5475 + +contrib +X Fixed a crash occuring while loading certain SVGs exported from Illustrator +X https://github.com/processing/processing/pull/5526 +X Support PShape.contains() on GROUP objects +X https://github.com/processing/processing/pull/5550 +X Improve implementation of PShape.contains() to take the CTM into account +X https://github.com/processing/processing/pull/5549 + + +0264 (3.3.7) +X fix exception due to version parsing in Java 9 +X https://github.com/processing/processing/issues/5275 +X remove useless deprecation on PImage.mask(int[]) +X set colorModeDefault to true by default +X blendMode() with PDF isn't showing the warning about it not being available +X add blendMode() to nope() calls in PGraphicsPDF +X https://github.com/processing/processing/issues/5105 +X Table.insertRow() causes ArrayIndexOutOfBoundsException (with fix) +X https://github.com/processing/processing/issues/5406 + +data +X added setIndex() method to IntDict, FloatDict, StringDict +X added resize() to IntDict, FloatDict, StringDict +X fix entries() Iterator in IntDict, FloatDict, StringDict + +contrib +X minor bezierPoint() rewrite for performance +X https://github.com/processing/processing/pull/5251 +X void cursor() don't work after void noCursor() in P2D and P3D +X https://github.com/processing/processing/issues/5330 +X https://github.com/processing/processing/pull/5340 +X NullPointerException on close button with P3D and noLoop +X https://github.com/processing/processing/issues/5214 +X https://github.com/processing/processing/pull/5384 + +andres +X textureWrap() not updating when changed during draw() +X https://github.com/processing/processing/issues/5322 +X cap frameRate() to 1000 in OpenGL +X https://github.com/processing/processing/issues/5404 + +gohai +X ARM tweaks for shaders on the RPi +X https://github.com/processing/processing/pull/5297 +X Fix 3D on contemporary versions of Linux +X https://github.com/processing/processing/pull/5428 +X https://github.com/processing/processing/issues/5308 + +jakub +X fix line joins on triangles +X https://github.com/processing/processing/issues/5353 +X https://github.com/processing/processing/pull/5354 +X Make un/registering methods in PApplet thread-saf +X https://github.com/processing/processing/pull/5379 + + +0263 (3.3.6) +X lots of contribs! + +gohai +X shell discussion with gohai +X https://github.com/processing/processing/pull/5082 +X Workaround issues with Raspbian release August 2017 +X https://github.com/processing/processing/pull/5222 + +jakub +X Fix bugs in line vert shader +X https://github.com/processing/processing/pull/5184 +X https://github.com/processing/processing/issues/5181 +X https://github.com/processing/processing/issues/5182 +X https://github.com/processing/processing/issues/5183 +X https://github.com/processing/processing/issues/5194 + +contrib +X Add workaround for window size = 0 crash +X https://github.com/processing/processing/pull/5234 +X https://github.com/processing/processing/issues/5052 + + +0262 (3.3.5) +X default to using native select on all platforms + +contrib +X Add defaultFontOrDeath to OpenGL textWidth +X https://github.com/processing/processing/issues/5137 +X https://github.com/processing/processing/pull/5138 + + +0261 (3.3.4) +X add exec() with StringList options +X start to add stub for shell() function +X handle edge case for set() being called with a 2D vector, on a 3D vector +X https://github.com/processing/processing/issues/5092 +o keyPressed() problems with special press-and-hold behavior macOS Sierra +X https://github.com/processing/processing/issues/4952 +X added documentation in 3 places about it + +jakub +X Fix keyPressed for multiple keys +X https://github.com/processing/processing/pull/5050 +X https://github.com/processing/processing/issues/5049 + + +0260 (3.3.3) +X keyPressed not returning false once a key is released +X https://github.com/processing/processing/issues/5033 +X deal with loadBytes() regressions introduced by their rewrite +X (was breaking p5jsMode because of its use of loadBytes(File) + +jakub +X image tint() broken in 3.3.x +X https://github.com/processing/processing/issues/5040 +X https://github.com/processing/processing/pull/5042 + + +0259 (3.3.2) +X add (far) more efficient file loading for loadBytes(File) +X add loadBytes(URL) variant that uses content length header for array size +X keyPressed is false if one key is released while multiple keys are pressed +X https://github.com/processing/processing/issues/4993 +X createInput() wasn't returning null for files that were not found +X https://github.com/processing/processing/issues/5026 + +andres +X Assigning Pixels Vertically Flipped in P2D +X https://github.com/processing/processing/issues/5013 + +gohai +X improve loadBytes() performance +X https://github.com/processing/processing/pull/5027 + +jakub +X ArrayIndexOutOfBoundsException when using tint() or loadFont() +X https://github.com/processing/processing/issues/5028 +X https://github.com/processing/processing/pull/5029 + + +0258 (3.3.1) +X improve sum() functions in processing.data +X add sum() to IntDict and FloatDict +X add sumLong() to IntList, IntDict (to handle cases outside integer range) +X add sumDouble() to FloatList, FloatDict (to handle outside float range) +X throw exception when using sum() with numbers that are too large or small +X createInput() and createOutput() now both use buffered streams by default +X createInputRaw() does not, however +X don't derive the font again if the size is unchanged +X part of https://github.com/processing/processing/issues/4956 +X fix temporary file handling for saveBytes(), saveStream(), etc +X wasn't handling gzip output properly +X also could have problems w/ names under length 3 + +jakub +X major work on window placement and pixel density +X https://github.com/processing/processing/pull/5011 + +gohai +X Fix MeshTweening vertex shader +X https://github.com/processing/processing-docs/issues/523 +X https://github.com/processing/processing-docs/pull/524 +X ARM: Allow Raspberry Pi's Mesa GL driver to use up to 8 lights +X https://github.com/processing/processing/pull/4915 +X ...and revert it back again +X https://github.com/processing/processing/pull/4922 +X Retry with multisampling disabled if creating a framebuffer fails +X because of INCOMPLETE_MULTISAMPLE +X https://github.com/processing/processing/pull/4921 +X Report more error conditions in validateFramebuffer +X https://github.com/processing/processing/pull/4920 +X Add more Raspberry Pi related fixes to JOGL +X https://github.com/processing/processing/pull/4911 +X Unblock hardware-accelerated P3D on ARM Mali devices +X https://github.com/processing/processing/pull/5014 + + +0257 (3.3) +X return null for PApplet.trim(null) +X StringDict(TableRow) constructor +X allow lone double quotes in the midst of csv strings +X make trim() work on column titles as well +o add trimRows() and trimColumns() +o would you ever use one w/o the other? +X just make this part of trim() +X also remove rows/columns from beginning +X since that's what trim() on strings does +X consume Unicode BOM (0xFEFF) in createReader() and Table parser +o no prompt shows with selectInput() on 10.11 and 10.12 +X https://github.com/processing/processing/issues/4758 +X can't fix, seems embedded in the Java implementation +X return null for getString(), getJSONObject(), and getJSONArray() +X when key is not present, more in line w/ other p5 api + +contrib +X Fix a number of memory leaks (jdf) +X https://github.com/processing/processing/pull/4862 +X https://github.com/jdf/processing.py/issues/233 +X https://github.com/processing/processing/pull/4873 + + +0256 (3.2.4) +X write exec() documentation +X https://github.com/processing/processing/issues/4740 +X add xmlns to elements procured from getChild() +X make sure newline is added after XML header when formatting + +api additions +X add listPaths(), listFiles() +X https://github.com/processing/processing/issues/4622 +X add increment() method that takes IntDict to merge another dictionary +X Calling this increment() since it doesn't make sense in practice for +X the other dictionary types, even though it's technically an add() +X add Entry class for iterating StringDict, IntDict, FloatDict +X add XML.print() method (prints with indent of 2) + +contribs +X Adding missing docs and keywords for TableRow +X https://github.com/processing/processing/pull/4333 +X PShape in Java2D wasn't respecting 'kind' +X https://github.com/processing/processing/issues/4826 +X https://github.com/processing/processing/pull/4834 + +cleaning +o probably should also check to make sure PApplet running JVM 8 +X or compile against 1.8 and force it? + +andres +X PShape array index out of bounds when using P3D +X https://github.com/processing/processing/issues/4773 +X modelX/Y/Z() should be disabled in P2D +X https://github.com/processing/processing/issues/4813 + +jakub +X FX: Prevent matrix stack overflow +X https://github.com/processing/processing/pull/4799 +X https://github.com/processing/processing/issues/4206 +X FX: Reset transform to identity before drawing background +X https://github.com/processing/processing/pull/4795 +X FX: Implement mouse wheel event +X https://github.com/processing/processing/issues/4169 +X https://github.com/processing/processing/pull/4796 +X FX: Fix curveVertex drawing all curves together as one long curve +X https://github.com/processing/processing/pull/4800 +X https://github.com/processing/processing/issues/4382 +X FX: Add exception handler which reports exceptions from user code +X https://github.com/processing/processing/pull/4798 +X https://github.com/processing/processing/issues/4339 +X Unify mouse pressed/released events across renderers +X https://github.com/processing/processing/issues/4361 +X https://github.com/processing/processing/pull/4797 +X Fix typo in GLSL preprocessor +X https://github.com/processing/processing/issues/4810 +X https://github.com/processing/processing/pull/4816 +X Keep Windows timer resolution high for OpenGL sketches +X prevents frame rate in OpenGL hovering around 30 instead of 60 +X https://github.com/processing/processing/pull/4847 +X https://github.com/processing/processing/issues/4846 +X Sketches still running in the background after closing +X https://github.com/processing/processing/issues/4831 +X (needed to allow JAVA2D to terminate when animation thread dies) +X https://github.com/processing/processing/pull/4839 + + +0255 (3.2.3) + +andres +X automatic detection of POINT and LINE shaders fails +X https://github.com/processing/processing/issues/4725 +X show warning when frameRate() less than 1 is called with P2D and P3D +X https://github.com/processing/processing/issues/4716 + + +0254 (3.2.2) +X fix quoting problem in IntDict.toJSON() +X add getRenderer() to SurfaceInfo +X https://github.com/processing/processing/issues/4441 +X Exceptions thrown in OpenGL apps when hitting window close box +X https://github.com/processing/processing/issues/4690 +X add getRowMap() function +o do we want rows() to not be transient? +X write docs for getRowMap() +o Add options to saveJSONArray documentation (enhancement) +o https://github.com/processing/processing/issues/4683 +X made note in the docs repo +X go back to textMode(MODEL) is native font not available for textMode(SHAPE) +X https://github.com/processing/processing/issues/4680 +X NPE thrown when using textMode(SHAPE) with a .vlw font +X https://github.com/processing/processing/issues/4680 +X add toJSON() method to IntDict +X had to use JSONObject.quote() to wrap the text +X do the same for the other data classes +o note the difference between this and toJSONObject() or toJSONArray() +o or is that the better way to handle it? hm +X we can add JSONObject and JSONArray later perhaps +X keep toJSONObject() for turning XxxxList into a numbered lookup + +contrib +X Call glGetProgramiv to retrieve program log length +X https://github.com/processing/processing/issues/4659 +X https://github.com/processing/processing/pull/4660 +X JSONObject get() method is private +X https://github.com/processing/processing/issues/4334 +X https://github.com/processing/processing/pull/4336 + +andres +X Automatic handling of screen FBOs breaks readPixels() for user-provided FBO +X https://github.com/processing/processing/issues/4643 +X PGraphicsOpenGL: camera info not updated +X https://github.com/processing/processing/issues/4609 +X Fix PShape, updateTessellation, matrix transformations +X https://github.com/processing/processing/issues/4662 +X QUAD_STRIP as child shape draws extra lines +X https://github.com/processing/processing/issues/4656 +X remove extra glClear() calls +X https://github.com/processing/processing/issues/4694 +X PShapes do not show up in PDF with P2D renderer +X https://github.com/processing/processing/issues/4647 +X Some semi-transparent edges of sphere() meshes rendered in higher density +X https://github.com/processing/processing/issues/4720 +X P2D and P3D not stopping with empty draw() blocks +X https://github.com/processing/processing/issues/4722 + + +0253 (3.2.1) +X implement defaultUncaughtExceptionHandler +X helps avoid needing to double-quit OS X applications + + 0252 (3.2) X some Table cleanup based on other CSV parsing work X use StandardCharsets.UTF_8 instead of getting encoding by name @@ -26,7 +494,7 @@ X disable async saveFrame() by default X https://github.com/processing/processing/issues/4578 gohai -X Fix GLExceptions on Raspberry Pi when using offscreen PGraphics +X Fix GLExceptions on Raspberry Pi when using offscreen PGraphics X https://github.com/processing/processing/pull/4524 leslie @@ -112,7 +580,7 @@ X Flipped Y-axis in JavaFX is now done (JDK bug) X https://github.com/processing/processing/issues/3795 jakub -X Initialize sketch args before calling settings() +X Initialize sketch args before calling settings() X https://github.com/processing/processing/issues/4219 X https://github.com/processing/processing/pull/4220 @@ -137,7 +605,7 @@ X strokeWeight() not working properly with point() in P2D and P3D X https://github.com/processing/processing/issues/4188 X exit() is not called in P2D/P3D X https://github.com/processing/processing/issues/4156 -X attrib*() function does not work well with PShape +X attrib*() function does not work well with PShape X https://github.com/processing/processing/issues/4048 contribs @@ -171,7 +639,7 @@ X https://github.com/processing/processing/issues/3961 X https://github.com/processing/processing/issues/3968 andres -X cursor() fails to work as expected with P2D/P3D +X cursor() fails to work as expected with P2D/P3D X https://github.com/processing/processing/issues/3955 X Topics/Shader/Convay broken X https://github.com/processing/processing/issues/3947 @@ -284,7 +752,7 @@ X https://github.com/processing/processing/issues/3718 X Implement standard cursor types in OpenGL X https://github.com/processing/processing/issues/3554 X Change value of constants PRIMITIVE, PATH, and GEOMETRY constants in PShape -X This avoids a collision with entries in PConstants which causes +X This avoids a collision with entries in PConstants which causes X confusing errors or no errors to be thrown at all X https://github.com/processing/processing/issues/3776 X Fix flickering cursor regression with Java2D on Windows introduced by #3472 @@ -319,7 +787,7 @@ X FX - fix transformation stack NPE X https://github.com/processing/processing/pull/3710 X FX - fix rad-deg conversion in rotate() X https://github.com/processing/processing/pull/3711 -X FX - basic pixel operations (get, set, load, update) +X FX - basic pixel operations (get, set, load, update) X https://github.com/processing/processing/pull/3709 X FX - align to pixel grid when drawing 1 px strokes X https://github.com/processing/processing/pull/3712 @@ -359,7 +827,7 @@ X FX - fix bug where fonts would share a tint cache X https://github.com/processing/processing/pull/3771 X textFont() and textSize() are each calling one another X move createFont() to PGraphics -X Fix PShape creation in P3D +X Fix PShape creation in P3D X https://github.com/processing/processing/pull/3781 X keyTyped() not firing with P2D and P3D X https://github.com/processing/processing/issues/3582 @@ -516,7 +984,7 @@ X https://github.com/processing/processing/issues/324 X Jakub: fixed somewhere between 0179 and 0184 cleaning/fixed earlier -X splice() throws ClassCastException when used with objects like PVector +X splice() throws ClassCastException when used with objects like PVector X http://code.google.com/p/processing/issues/detail?id=1407 X https://github.com/processing/processing/issues/1445 o Semitransparent rect drawn over image not rendered correctly @@ -576,13 +1044,13 @@ X http://code.google.com/p/processing/issues/detail?id=146 X https://github.com/processing/processing/issues/185 X OPENGL sketches flicker w/ Vista when background() not used inside draw() X Disabling Aero scheme sometimes prevents the problem -X Updating graphics drivers may prevent the problem +X Updating graphics drivers may prevent the problem X ellipse scaling method isn't great X http://code.google.com/p/processing/issues/detail?id=87 X Stroking a rect() leaves off the upper right pixel X http://code.google.com/p/processing/issues/detail?id=67 X https://github.com/processing/processing/issues/106 -X opengl applet problems with tabs - needs to handle stop() and start() +X opengl applet problems with tabs - needs to handle stop() and start() X http://code.google.com/p/processing/issues/detail?id=196 X stop() called between tabs/pages, start() may be called again X http://java.sun.com/docs/books/tutorial/deployment/applet/lifeCycle.html @@ -616,7 +1084,7 @@ X Remove mode parameters from createShape(), fixes parameter collision issues X https://github.com/processing/processing/pull/3516 X radius for rect not working on PShape X https://github.com/processing/processing/issues/2646 -X bug in arc with createShape +X bug in arc with createShape X https://github.com/processing/processing/issues/3018 X OpenGL sketch flickers when draw() is missing or empty X https://github.com/processing/processing/issues/3473 @@ -625,7 +1093,7 @@ X size() errors X https://github.com/processing/processing/issues/3483 X improve hint(ENABLE_DEPTH_SORT) to use proper painter's algo X https://github.com/processing/processing/issues/90 -X also for begin/endRaw: +X also for begin/endRaw: X https://github.com/processing/processing/issues/2235 X polygon z-order depth sorting with alpha in opengl X complete the implementation of hint() with proper implementation @@ -670,7 +1138,7 @@ X Device parsing on Linux is incorrect X https://github.com/processing/processing/issues/3532 o don't show display warning when display 1 doesn't exist X apparently this was an OpenGL bug (#3532) -X flush geometry when lighting changes +X flush geometry when lighting changes X otherwise lights apply to the entire scene X https://github.com/processing/processing/issues/3533 @@ -688,10 +1156,10 @@ X https://github.com/processing/processing/issues/3378 X PGraphic ignores PNG transparency (regression from 3.0a5) X https://github.com/processing/processing/issues/3317 X (same issue as 3378) -X move error messages out of PConstants (into PApplet? PGraphics?) +X move error messages out of PConstants (into PApplet? PGraphics?) o replace sketchXxxx() methods with another mechanism? o and an internal dictionary that stores them all? -o intParam(), stringParam() and setParam()? +o intParam(), stringParam() and setParam()? o or sketchInt() or settingsInt()? o surface.size(), surface.noSmooth()... just like PGraphics methods? o make final to move folks away from these? @@ -800,7 +1268,7 @@ X Closing OpenGL sketch from the PDE doesn't stop java.exe process X https://github.com/processing/processing/issues/2335 cleaning -o keep Danger2D? +o keep Danger2D? o can't do version that draws to BufferStrategy directly o pixel operations (get/set/loadPixels/saveFrame) might be fixable o but can't re-run draw() to re-blit the screen @@ -812,7 +1280,7 @@ X decided to put efforts into JavaFX 0237 (3.0a10) X retain original java.awt.Frame when it's available from PSurfaceAWT -X set frame icon images for Java2D (dock and cmd-tab) +X set frame icon images for Java2D (dock and cmd-tab) X https://github.com/processing/processing/issues/257 X strokeWeight() in setup() not working for default renderer X https://github.com/processing/processing/issues/3331 @@ -884,7 +1352,7 @@ X size() inside setup() can only have numbers X size() inside settings() is left alone and can do whatever it wants X comments are being removed before size() is getting checked X probably remove anything inside settings() as well? -X looks like we're off by 1 on monitor numbering +X looks like we're off by 1 on monitor numbering X https://github.com/processing/processing/issues/3309 X full screen doesn't work on second window w/o present mode X https://github.com/processing/processing/issues/3271 @@ -927,7 +1395,7 @@ X https://github.com/processing/processing/issues/2125 X group shapes are broken in 3.0a9 X https://github.com/processing/processing/issues/3336 X only a quarter of the sketch is appearing with P2D_2X and P3D_2X -X (i.e. the image shows up too large) +X (i.e. the image shows up too large) X https://github.com/processing/processing/issues/3332 X https://github.com/processing/processing/issues/3327 X single transparent pixel at end of textures in OpenGL @@ -989,7 +1457,7 @@ X https://github.com/processing/processing/issues/3293 0235 (3.0a8) -X fairly major rewrite of createShape() +X fairly major rewrite of createShape() X prevents same code from appearing 5x (!) in the source X improves bad api design with the static createShapeImpl() methods X errors in case changes not correctly reported @@ -1023,7 +1491,7 @@ X otherwise args == null checks are weird X saveFrame() from setup() gives a black screen when size() is called X as seen in the 'numbers' sketch X this was fixed earlier? -X fix flicker when resizing window +X fix flicker when resizing window X running through PSurfaceAWT.setSize() is probably overkill o setLocationRelativeTo(null) was removed, will it be missed? @@ -1196,13 +1664,13 @@ X Linux throwing IllegalStateException: Buffers have not been created X in render() (called from blit) PSurfaceAWT:301 -0232 core (3.0a5) +0232 core (3.0a5) X detect CMYK JPEG images and return null X https://community.oracle.com/thread/1272045?start=0&tstart=0 X show a warning when calling getVertexCount() on GROUP or PRIMITIVE shapes X https://github.com/processing/processing/issues/2873 X https://github.com/processing/processing-docs/issues/167 -X replace is3D(boolean) with set3D() +X replace is3D(boolean) with set3D() data X fix XML.getString() with a default when no attrs are present at all @@ -1269,7 +1737,7 @@ X update to new version of JOGL (Andres) 0230 core (3.0a3) X add another NaN check when sorting FloatList/Dict classes X if all values were NaN, an ArrayIndexOutOfBoundsException was thrown -X PShape for JAVA2D +X PShape for JAVA2D X https://github.com/processing/processing/pull/2756 X add trim() method to the XML library @@ -1406,7 +1874,7 @@ X https://github.com/processing/processing/issues/2331 X https://github.com/processing/processing/pull/2338 X bug in relative moveto commands for SVG X https://github.com/processing/processing/issues/2377 -X Add a constructor to bind Server to a specific address +X Add a constructor to bind Server to a specific address X https://github.com/processing/processing/issues/2356 X add disconnectEvent() to Server X https://github.com/processing/processing/pull/2466 @@ -1414,18 +1882,18 @@ X https://github.com/processing/processing/issues/2133 X don't document for now cleaning -o how much of com.benfry.* should go in? +o how much of com.benfry.* should go in? o Table? StringIntPairs? JSON? MD5? Integrator? ColorIntegrator? o decision: depends on if we can think of a good name X finished these up in the 2.x series o check on DXFWriter, since it used to subclass P3D -o at least implement is3D? +o at least implement is3D? X should be working, barring recent regression o sleep time needs to be set *much* higher for dormant applets o 10s should be fine--no need to keep spinning (bad for android too) o just call interrupt() when it's time to get back to work X applets removed -X test PGraphicsRetina2D w/ 7u40 +X test PGraphicsRetina2D w/ 7u40 X make sure that 7u40 doesn't reintroduce starvation issue on retina Macs X createGraphics() with no renderer param to point to JAVA2D X docs: P2D and P3D are now OpenGL variations @@ -1528,7 +1996,7 @@ X alpha values from the pixels array coming back as 0 X only tested on background(), not image() X https://github.com/processing/processing/issues/2030 -opengl +opengl X Using sketchQuality() does not work properly with P3D, OPENGL, P2D X https://github.com/processing/processing/pull/2157 X Fix crashes when the sketch window is resized @@ -1571,7 +2039,7 @@ X https://github.com/processing/processing/issues/2113 X constrain lerpColor() between 0 and 1 X JSONObject/Array.format(-1) not working on embedded JSONObjects X https://github.com/processing/processing/issues/2119 -X allow println() and print() to take varargs +X allow println() and print() to take varargs o https://github.com/processing/processing/issues/2056 X causes conflict with printing arrays X added printArray() function instead @@ -1669,7 +2137,7 @@ X Error in IntList and FloatList insert() X https://github.com/processing/processing/issues/1929 X selectInput() in exported OS X sketch treats .app package as a folder o Oracle Java 7 problem, but maybe a workaround? -o might be a problem with awt dialogs for directories? +o might be a problem with awt dialogs for directories? X https://github.com/processing/processing/issues/1959 X turns out this is an apple.awt tweak for the exported Info.plist X getSubset() broken in IntList, StringList, and missing from FloatList @@ -1685,7 +2153,7 @@ X add sum() to IntList and FloatList X https://github.com/processing/processing/issues/1893 X retain blendMode() between frames X https://github.com/processing/processing/issues/1962 -X this should actually be in the code.. +X this should actually be in the code.. X maybe not working on OS X/retina? X perhaps it's a getGraphics() issue? X when using increment() on IntList, make sure the index exists @@ -1708,7 +2176,7 @@ o require people to put things in the data folder table X add sort() to Table X implement version of Table that takes a dictionary file -X dictionary=blah.tsv +X dictionary=blah.tsv X tsv only, ignores extension X if allowed extension, we couldn't use .dict instead X and that's probably the most useful @@ -1817,7 +2285,7 @@ X switch to CATEGORY instead of CATEGORICAL X removed createXML() and createTable()... just use 'new' for these X implement means for setting dpi in PNG images X need to add something for API yet -o JAI handles setting image size for png (check javax.imageio?) +o JAI handles setting image size for png (check javax.imageio?) o PNGEncodeParam png = PNGEncodeParam.getDefaultEncodeParam(bufImage); o png.setPhysicalDimension(round(dpi*39.370079), round(dpi*39.370079), 1); o JAI.create("filestore", bufImage, filename+".png", "PNG"); @@ -1829,7 +2297,7 @@ X only call setModified(), not updatePixels() in endDraw() andres A lines not properly renderered in P3D when using ortographic projection A https://github.com/processing/processing/issues/1661 -A "deleted n framebuffer objects" +A "deleted n framebuffer objects" A last lines of a beginShape(LINES) are invisible in the P2D renderer A https://github.com/processing/processing/issues/1761 A Incorrect number of vertices on beginShape(TRIANGLES) affect subsequent Shapes @@ -1840,7 +2308,7 @@ A https://github.com/processing/processing/issues/1757 earlier X decision on registered methods X remove registerPre() et al -X add register("pause", ...) +X add register("pause", ...) X size() should be resize(), so it can be overridden (ala pause()) X add PEvent X need to wrap mouse/key events for p5 @@ -1891,17 +2359,17 @@ X api note: size() used in data classes X length() too confusing w/ array.length being built-in (when to use ()?) X size() a bit confusing with the p5 size command, but less problematic o also shorter than getCount() or getLength() -o why not HashMap and ArrayList for JSON? +o why not HashMap and ArrayList for JSON? o could enable loadHash() and loadArray() functions X because the types coming back out would always have to be cast o add loadDict() and loadList() for JSON? -o Dict and List could be interfaces? +o Dict and List could be interfaces? X "hash.toJSONObject()" or "new JSONObject(hash)" X opted to use "new JSONObject" version, appears less awkward o match? find? on StringList? X naming for descending sort -o rsort(), sortReverse(), sortKeysReverse, -o sortDescend, sortDescending, sortKeysDescending, +o rsort(), sortReverse(), sortKeysReverse, +o sortDescend, sortDescending, sortKeysDescending, o sortHighLow, sortHigh, sortHighest, sortDown X sortReverse() is the final decision @@ -1920,7 +2388,7 @@ o inc(), inc(amount), dec(), dec(amount) X replace (especially for null and NaN) X make note that these work, and are special cases o listAttributes() in XML is like array from keys() etc in our data classes -X removeIndex() vs removeValue() vs remove() +X removeIndex() vs removeValue() vs remove() X remove() refers to an index (with array) or key (with hash) X more consistent with other APIs (Java) X replaceValue[s]() the same, though more on the line @@ -1948,15 +2416,15 @@ X misc bugs with last release X https://github.com/processing/processing/issues/1660 X https://github.com/processing/processing/issues/1680 X Dan having trouble with JSON -X keys() vs keySet() in JSON.. +X keys() vs keySet() in JSON.. X keys() doesn't iterate, keySet() introduces 'Set' type X parseJSONObject(x) and parseJSONArray(x) table -X do we need getColumnType() inside TableRow? +X do we need getColumnType() inside TableRow? X also inside Table X also do we make the constants public? -X table writing twice when .csv is added +X table writing twice when .csv is added X https://github.com/processing/processing/issues/1734 X checkOptions() is a mess.. need to use different options for load/save X rewrite it as necessary @@ -1967,7 +2435,7 @@ X handling gz properly, but gz has to be the extension X adding it to options is too messy o add 'gz' as one of the loadXxx() options o helps .svgz case from being weird, also generally dealing w/ compressed data -X include SQL, HTML, ODS, binary? +X include SQL, HTML, ODS, binary? X decide on TableODS, TableHTML X HTML is out--too confusing X ODS is in for loading, and finished @@ -2010,7 +2478,7 @@ o when using loadFont(), don't enable native fonts unless hint() in use o but on createFont(), we're probably OK o might need to make reference notes about the two behaviors X decision: remove hint(ENABLE_NATIVE_FONTS) -X PImage.resize() greater than image size hangs +X PImage.resize() greater than image size hangs X http://code.google.com/p/processing/issues/detail?id=1463 X turns out to be errata from the book X add warning message when registering AWT mouse/key events @@ -2128,7 +2596,7 @@ X makeEmptyNull() -> replace("", null); X saveTable("filename.tsv") or saveTable("filename.txt", "tsv") X createTable() method in PApplet X removed getUniqueXxxx() and some others, pending names -X added listUnique() and tallyUnique() +X added listUnique() and tallyUnique() X added getColumnCount() to TableRow X cleaned up checkBounds() @@ -2146,15 +2614,15 @@ o isWhitespace() method for nodes? (that's the capitalization used in Character) X doesn't help much o get back to PhiLho once finished X XML toString(0) means no indents or newlines -X but no way to remove indents and still have newlines... +X but no way to remove indents and still have newlines... X toString(-1)? a new method? X format(2), format(4)... toString() -> default to 2 params X fix this across the other items X look into json and how it would work wrt XML -o 1) we bring back getFloatAttribute() et al., +o 1) we bring back getFloatAttribute() et al., o and make getFloat() be equivalent to parseFloat(xml.getContent()) o 2) we keep getFloat() like it is, and add getFloatContent(), etc. -o 3) we deprecate our nice short getFloat/getInt/etc and go with +o 3) we deprecate our nice short getFloat/getInt/etc and go with o getXxxxAttribute() and getXxxxContent() methods. X not gonna do getFloatContent() since it's not really any shorter X beginning slash in getChild() threw an NPE @@ -2168,7 +2636,7 @@ X change to getRows() method for iterating through the Table object X add parseInto() method (provisional) X change translate() and rotate() to use x, y, z as param names o opengl.jar with eclipse -o auto-extract native libs from opengl.jar +o auto-extract native libs from opengl.jar o to remove java.library.path problems (!) X no longer necessary, JOGL does this by default X implement clip()/noClip() @@ -2215,7 +2683,7 @@ X make note for Casey to include this in the reference X Potential race condition when resizing sketches X http://code.google.com/p/processing/issues/detail?id=697 X removed mask(int[]).. check reference to make sure it's not in use -X how to handle get(x, y, w, h) when off screen? +X how to handle get(x, y, w, h) when off screen? X http://code.google.com/p/processing/issues/detail?id=925 A curves aren't rendered seperately when P3D or P2D is specified A http://code.google.com/p/processing/issues/detail?id=1317 @@ -2263,7 +2731,7 @@ X change name for hint() that controls stroke/fill combo: andres (cleanup) A when turning smoothing on, internal lines of shapes are visible -o add an edge flag when tesselating +o add an edge flag when tesselating o mind the opengl tesselation flags o need to turn off smoothing for the interior of shapes A http://code.google.com/p/processing/issues/detail?id=53 @@ -2319,7 +2787,7 @@ o loading lots of images is a problem, describe how to unload o is it possible? necessary to call delay(5) or something? events -X make sure alt/ctl/meta/etc all work (for both mouse and key) +X make sure alt/ctl/meta/etc all work (for both mouse and key) X remove thread blocking when dequeueing events X finish postEvent() X need to make events interleave @@ -2397,7 +2865,7 @@ A Using ortho() breaks stroke rendering A http://code.google.com/p/processing/issues/detail?id=1207 earlier -A Implement support for complex shapes when using the OpenGL renderer +A Implement support for complex shapes when using the OpenGL renderer A in opengl mode, use its tesselator A because the vertex calls can just come right back to regular vertex calls A this way we can also implement breakShape() for opengl @@ -2412,7 +2880,7 @@ A http://code.google.com/p/processing/issues/detail?id=902 A updatePixels wth OpenGL requires a lot of memory, need better texture update A http://code.google.com/p/processing/issues/detail?id=77 A text characters showing up as opaque rectangles in tga files -o solution is to implement alpha compositing across all of P3D +o solution is to implement alpha compositing across all of P3D o http://en.wikipedia.org/wiki/Alpha_compositing A http://code.google.com/p/processing/issues/detail?id=80 A changing framerate causes program to crash with P2D in 2.0a6 @@ -2437,13 +2905,13 @@ X provide a way to clear the PGraphics with plain alpha X removed in the end... background() can already do it X work on making API more generic and consistent X PFont.getFont() changed to PFont.getNative() (returns an Object) -X PFont.getTypeface() changed to PFont.getNative() +X PFont.getTypeface() changed to PFont.getNative() X PImage.getBitmap() and getImage() changed to PImage.getNative() X use getNative() to return the native object for X PImage (BufferedImage and Bitmap), PFont (Typeface or awt.Font) X Jagged / Glitchy JAVA2D shape strokes in Java 1.6 -X g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, -X RenderingHints.VALUE_STROKE_PURE); +X g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, +X RenderingHints.VALUE_STROKE_PURE); X http://code.google.com/p/processing/issues/detail?id=1068 X loadShape() cleanup A remove PShape2D/3D @@ -2499,7 +2967,7 @@ X broken in the recent releases X http://code.google.com/p/processing/issues/detail?id=1157 fixed earlier -A ArrayIndexOutOfBoundsException inside PFontTexture.updateGlyphsTexCoords() +A ArrayIndexOutOfBoundsException inside PFontTexture.updateGlyphsTexCoords() A http://code.google.com/p/processing/issues/detail?id=1104 A Camera function hot changing the upward axis A http://code.google.com/p/processing/issues/detail?id=534 @@ -2557,7 +3025,7 @@ o otherwise can crash the whole browser o z value hack for lines is causing trouble for 2D o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1089737928;start=0 o rewrite line and stroke code, it's a buggy mess -o lines become 2 pixels thick after a 3D transform +o lines become 2 pixels thick after a 3D transform o better handling of single-pixel special case o flat_line_retribution is a hack, can go away o some optimizations from zach @@ -2568,7 +3036,7 @@ o one pixel lines have no z value.. argh o bug re: 3d depth sorting on lines o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1043894019;start=0 o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1042004618 -o translate(58, 48, 0); +o translate(58, 48, 0); o rotateY(0.5); o box(40); o cursor() broken in applets on macosx? @@ -2589,7 +3057,7 @@ X createGraphics for JAVA2D generates the wrong error msg w/ w/h <= 0 X http://code.google.com/p/processing/issues/detail?id=983 X move to processing.data.* package X update the internal code for Android and desktop to add the import -X add loadTable().. +X add loadTable().. X loadXML and loadTable are now in desktop o trimming text on URLs? o http://code.google.com/p/processing/issues/detail?id=715 @@ -2598,7 +3066,7 @@ X update wiki.processing.org/w/Window_Size_and_Full_Screen X add createGraphics() with no renderer param to point to JAVA2D X also added to Android X removals -X CENTER_RADIUS, CENTER_DIAMETER, NORMALIZED +X CENTER_RADIUS, CENTER_DIAMETER, NORMALIZED X text(x, y, w, h, z) X textX/Y/Z variables X update changes Wiki @@ -2609,7 +3077,7 @@ X it hasn't worked for a while, also not a good way to get updates on size X use pre() or something like that instead o displayWidth/Height not set until just before setup o don't use size(displayWidth, displayHeight) anymore -o to do full screen, should use: +o to do full screen, should use: X did not work well andres @@ -2662,7 +3130,7 @@ o should this be the default to be more like old XML? o otherwise document how things are sometimes null in XML o test xml examples to see if they break X changed to make it return #text for the name, which is more correct -X white space in XML +X white space in XML X http://code.google.com/p/processing/issues/detail?id=975 o finish updating XML documentation o http://code.google.com/p/processing/issues/detail?id=382 @@ -2684,10 +3152,10 @@ X several other items under the LIBRARIES / XML section below sort out full screen issues X make screenWidth and screenHeight work properly with multiple screens X also set screenX and screenY -X boolean sketchFullscreen() ? +X boolean sketchFullscreen() ? X for more options, just integrate the fs library? X let hansi know when it's integrated so he can update his library -X casey: I think we only want to most basic functionality, +X casey: I think we only want to most basic functionality, X to go full screen across monitors. X http://www.superduper.org/processing/fullscreen_api/ X https://github.com/kritzikratzi/jAppleMenuBar/blob/master/src/native/jAppleMenuBar.m @@ -2720,7 +3188,7 @@ X frame.setSize() works, but we aren't going to add the title bar back X just too problematic and buggy to get this to work perfectly X default is that full screen app doesn't cover multiple displays X this is fine since opengl can't usually go across both -o but include an example for how to use full in gl +o but include an example for how to use full in gl o full screen not working on snow leopard X fix build script to include the jnilib, also add more error checks X screenX and screenY are both already taken, so not including vars for them @@ -2728,7 +3196,7 @@ X decide on naming for the next release 0204 core (2.0a5) -X Abnormal high Java CPU usage at empty sketch with draw() +X Abnormal high Java CPU usage at empty sketch with draw() X http://code.google.com/p/processing/issues/detail?id=729 X https://forum.processing.org/topic/absurd-java-cpu-usage-at-empty-sketch-with-draw X "Framingham" example has BufferOverflowException @@ -2757,7 +3225,7 @@ X remove textMode(SCREEN) o is it possible to do decent vlw text with JAVA2D and OPENGL? o optimize textMode(MODEL) with textMode(SCREEN) o in PGraphics and PGraphics3, check to see if matrix is within epsilon -o of one of the rotation matrices (many fewer steps) +o of one of the rotation matrices (many fewer steps) o if identity, or just translate, or a rotate, make OBJECT into SCREEN o textMode(SCREEN) needs to be faster o need flat image implementation that takes no transforms @@ -2812,7 +3280,7 @@ X add orientation() no-op and the two constants 0198 core -o arrayobjects (and others) flicker like hell in chrome 10 +o arrayobjects (and others) flicker like hell in chrome 10 o http://code.google.com/p/processing/issues/detail?id=646 o http://code.google.com/p/chromium/issues/detail?id=62004 o http://code.google.com/p/chromium/issues/detail?id=79939 @@ -2866,10 +3334,10 @@ A implement repeating textures A http://code.google.com/p/processing/issues/detail?id=94 o add a limit to pushStyle() to catch unmatched sets? X http://code.google.com/p/processing/issues/detail?id=198 -X how should quadVertex() be named? bezierVertex() quadraticVertex() +X how should quadVertex() be named? bezierVertex() quadraticVertex() X decision: quadraticVertex() to avoid confusion with quads X more efficient version of copy() added for 2D -X rounded rectangle method +X rounded rectangle method X http://code.google.com/p/processing/issues/detail?id=265 X clockwise from upper-left X check with casey about finalizing and adding to the docs @@ -2887,20 +3355,20 @@ X http://code.google.com/p/processing/issues/detail?id=455 X decision: post() only gets called in draw, not setup.. document opengl applets -X implement new applet-opengl.html based on the latest jogl +X implement new applet-opengl.html based on the latest jogl o jogl demos, NEWT examples crash on osx http://jogamp.org/jogl-demos/www/ o http://jogamp.org/jogl-demos/www/applettest-jnlp.html X not sure why these do/don't work, but it's mostly working X OpenGL Applets won't load with JRE 6 update 21 or higher X need to make the final call on this and implement X http://code.google.com/p/processing/issues/detail?id=429 -o why we can't do OpenGL applets that are self-signed (wiki?) +o why we can't do OpenGL applets that are self-signed (wiki?) o http://www.cert.org/blogs/vuls/2008/06/signed_java_security_worse_tha.html cleanup o if too many errors come through during setup, app will terminate o printStackTrace() throttles on osx and poops out -o seen especially on old mac laptops (slow ppc garbage) +o seen especially on old mac laptops (slow ppc garbage) o can this be confirmed properly? o * this may just be an OutOfMemoryError happening o when drawing into a JAVA2D surface, have to call loadPixels() @@ -2920,9 +3388,9 @@ o filter() checks to see if inside begin/endPixels, if so doesn't call o if line() is called inside beginpixels, call updatepixels? o when NPE on line with pixels[], suggest user includes beginPixels o need to test/straighten out load/update pixels -o loadPixels() and updatePixels() only need to be used when +o loadPixels() and updatePixels() only need to be used when o touching pixels[]. All other functions including get(), set(), -o filter(), etc shouldn't need them. +o filter(), etc shouldn't need them. o image memory use.. how to handle lots of images o need to figure out exactly how they should/can unload o don't do a loadPixels unless an updatePixels has completed @@ -3038,7 +3506,7 @@ o i.e. ABGR_EXT might allow for just two shifts instead of 4 o allow access to native pixel buffer in opengl and power of 2 o so that no need to copy/update everything o how to handle gluTessVertex calls -o need to re-map through the regular "vertex" command, +o need to re-map through the regular "vertex" command, o but that makes things messy because the glu calls make calls to vertex() o and i don't want an additional "pathVertex()" function o with opengl optimizations via call lists.. @@ -3072,7 +3540,7 @@ o Stroked polygons losing stroke pixels due to z-buffer issues in P3D o http://code.google.com/p/processing/issues/detail?id=73 X refactor PApplet.main() and Runner.startInternal() to remove duplication X http://dev.processing.org/bugs/show_bug.cgi?id=245 -o PFont.size not available.. other font accessors? +o PFont.size not available.. other font accessors? o http://dev.processing.org/bugs/show_bug.cgi?id=1510 o implement method for lightweight components with processing applets o http://dev.processing.org/bugs/show_bug.cgi?id=686 @@ -3105,7 +3573,7 @@ X i.e. some fonts don't work with PDF, or bg color can't be re-set X clean up filter stuff? X filter(GRAY) -> to push things to luminosity-based gray X already implemented this way -o filter(MASK, ...) -> or ALPHA? +o filter(MASK, ...) -> or ALPHA? o filter(TINT, tintColor) X decision: use luminosity for gray X decision: tinting is usually for a dynamic thing, so not necessary @@ -3136,8 +3604,8 @@ o even if not actually working properly.. just in naming of things o sorting of polygons/lines on simple painters algorithm o better lighting model to show darkness at various depths o maybe just ultra-high res bitmaps from gl -o cairo tesselation used: -o John Hobby, Practical Segment Intersection with Finite Precision Output. +o cairo tesselation used: +o John Hobby, Practical Segment Intersection with Finite Precision Output. o Computational Geometry Theory and Application, 13(4), 1999. o http://citeseer.ist.psu.edu/hobby93practical.html o textMode(SHAPE) and textMode(IMAGE)? @@ -3148,7 +3616,7 @@ o or use a getXxxx() method? o in PShape, getChild(name) refers to a o however in an XML file, that's , meaning the name of the tag o change it to getShape(name)? also for fonts getShape(char c) -o decision: use getShape() (maybe add getShapeCount and getShape(int)) +o decision: use getShape() (maybe add getShapeCount and getShape(int)) o and remove getChild() from PShape o oops: getParent() is in there, as is getChildren() and others... o svg examples should use getShape(name) not getChild(name) @@ -3284,7 +3752,7 @@ X workaround from Christian Thiemann X http://code.google.com/p/processing/issues/detail?id=467 stop/destroy/dispose -L stop() not working very well +L stop() not working very well L as a result, dispose() methods aren't being called on libraries L http://dev.processing.org/bugs/show_bug.cgi?id=131 L http://dev.processing.org/bugs/show_bug.cgi?id=77 (dupe) @@ -3297,13 +3765,13 @@ L http://code.google.com/p/processing/issues/detail?id=180 0191 core (pre) X fix background(PImage) for OpenGL X http://code.google.com/p/processing/issues/detail?id=336 -X skip null entries with trim(String[]) +X skip null entries with trim(String[]) X NaN with PVector.angleBetween X http://code.google.com/p/processing/issues/detail?id=340 X fix missing getFloat() method in XML library X setAttribute? setString/Int/Float or just set? X get() set() methods are confusing.. too spare -X make sure that paths are created with saveStream() +X make sure that paths are created with saveStream() X make createWriter() use buffering X saveStream() doesn't work when intermediate directories don't exist @@ -3417,7 +3885,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=1174 0181 core (pre-release) -X no changes for 0181 +X no changes for 0181 0180 core (pre-release) @@ -3435,7 +3903,7 @@ X cache font information for the PDF library to improve setup time X when using createFont("xxxx.ttf"), should use textMode(SHAPE) with PDF X because ttf files will not be installed on the system when opening pdf X added error messages for users -X bring back old-style textAscent() +X bring back old-style textAscent() X needs to just quickly run characters d and p X only takes a couple ms, so no problem X pdf library @@ -3485,7 +3953,7 @@ X probably regression b/c camera/perspective can't be called then X http://dev.processing.org/bugs/show_bug.cgi?id=1391 -0175 core (private) +0175 core (private) X changed createInputRaw() to only bother checking URLs if : present @@ -3495,13 +3963,13 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=1408 0173 core (private) -X Re-enabled hack for temporary clipping. +X Re-enabled hack for temporary clipping. X Clipping still needs to be implemented properly, however. Please help! X http://dev.processing.org/bugs/show_bug.cgi?id=1393 0172 core (private) -X no changes to the core (or were there?) +X no changes to the core (or were there?) 0171 core (1.0.9) @@ -3513,11 +3981,11 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=1352 0170 core (1.0.8) X added some min/max functions that work with doubles X not sure if those are staying in or not -X filter(RGB) supposed to be filter(OPAQUE) +X filter(RGB) supposed to be filter(OPAQUE) X http://dev.processing.org/bugs/show_bug.cgi?id=1346 X implement non-power-of-2 textures X fix get() when used with save() in OpenGL mode -X immediately update projection with OpenGL +X immediately update projection with OpenGL X in the past, projection updates required a new frame X also prevents camera/project from being reset with setSize() (regression?) X which was a problem anyway because it made GL calls outside draw() @@ -3557,7 +4025,7 @@ X set() doesn't honor alpha consistently X also causes problems with PDF X preliminary thread() implementation X double param version of map() -X PImage cacheMap problem when using PImage.get() +X PImage cacheMap problem when using PImage.get() X http://dev.processing.org/bugs/show_bug.cgi?id=1245 X problems with > 512 points and P3D/OPENGL (thx DopeShow) X http://dev.processing.org/bugs/show_bug.cgi?id=1255 @@ -3593,7 +4061,7 @@ X text() with char array o add documentation o add this for text in a rectangle? X minor bug fix to svg files that weren't being resized properly -X OpenGL is rendering darker in 0149+ +X OpenGL is rendering darker in 0149+ X http://dev.processing.org/bugs/show_bug.cgi?id=958 X the fix has been found, just incorporate it X thanks to dave bollinger @@ -3613,7 +4081,7 @@ X save styles when nextPage() is called X beginRaw() broken (no DXF, etc working) X http://dev.processing.org/bugs/show_bug.cgi?id=1099 X http://dev.processing.org/bugs/show_bug.cgi?id=1144 -X Fix algorithm for quadratic to cubic curve conversion +X Fix algorithm for quadratic to cubic curve conversion X wrong algorithm in PGraphicsOpenGL and PShapeSVG X (thanks to user 'shambles') X http://dev.processing.org/bugs/show_bug.cgi?id=1122 @@ -3696,7 +4164,7 @@ X also a typo in the ColorWheel example X http://dev.processing.org/bugs/show_bug.cgi?id=1019 X P2D - null pointer exception drawing line with alpha stroke X http://dev.processing.org/bugs/show_bug.cgi?id=1023 -X P2D endShape() is working like endShape(CLOSE) +X P2D endShape() is working like endShape(CLOSE) X http://dev.processing.org/bugs/show_bug.cgi?id=1021 X http://dev.processing.org/bugs/show_bug.cgi?id=1028 (mark as dupe) X arc() center transparent @@ -3757,7 +4225,7 @@ X add skewX() and skewY() to PMatrix X Add support style attribute for path tag to Candy SVG (ricard) X http://dev.processing.org/bugs/show_bug.cgi?id=771 X remove setX/Y/Z from PVector, copy() (use get() instead), add mult/div -X remove copy() from PVector? +X remove copy() from PVector? X add mult() and div() with vector inputs? @@ -3843,7 +4311,7 @@ X figure out how to handle constructor mess X clean up setMainDrawingSurface() X should instead be inside size(), and init(), no? X add to hint(DISABLE_DEPTH_TEST) -X gl.glClear(GL.GL_DEPTH_BUFFER_BIT); +X gl.glClear(GL.GL_DEPTH_BUFFER_BIT); X or clearing the zbuffer for P3D X also add a note to the hint() reference X DISABLE_DEPTH_TEST bad results @@ -3945,7 +4413,7 @@ X working on pshape X add shape() methods to PGraphics/PApplet X test and fix svg examples X revisions.txt for x/y/z/ tx/ty/tz.. other changes in api.txt -X bring svg into main lib +X bring svg into main lib X need to straighten out 'table' object for quick object lookup X maybe add to all parent tables? (no, this gets enormous quickly) X fix svg caps/joins for opengl with svg library @@ -3975,7 +4443,7 @@ X need to check this--isn't this referring to DISABLE_DEPTH_TEST? X ENABLE_DEPTH_SORT causing trouble with MovieMaker X need to make the flush() api accessible X http://dev.processing.org/bugs/show_bug.cgi?id=692 -X image smoothing +X image smoothing X straighten out default vs. ACCURATE vs. whatever X Java2D and P3D and OpenGL are all inconsistent o need to be able to do hint() to do nearest neighbor filtering @@ -4099,13 +4567,13 @@ X that is, if a loadImage() turns up an access denied page X added an error message for this, and the image width and height will be -1 X added loadImageAsync() for threaded image loading -opengl fixes +opengl fixes X incorporate changes from andres colubri into PGraphicsOpenGL X most of the changes incorporated, something weird with constructors X use gluErrorString() for glError() stuff X PGraphicsOpenGL.java: X directionalLight() and .pointLight() are both calling -X glLightNoAmbient() which then creates a new FloatBuffer +X glLightNoAmbient() which then creates a new FloatBuffer X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1199376364 @@ -4115,7 +4583,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=407 X filed as bug #4769141 with apple http://bugreport.apple.com/ X appears that asking for the postscript name no longer works o fix "create font" and associated font stuff to straighten it out -X was grabbing the wrong native font with ico sketch +X was grabbing the wrong native font with ico sketch X seems that the psname is no longer a good way to grab the font? related? X available font issues X is getFontList returning a different set of fonts from device2d? @@ -4160,7 +4628,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=774 0137 core X add gz handling for createOutput() X change openStream() to createInput() (done in 0136) -X add createOutput() +X add createOutput() X deprecate openStream() naming @@ -4175,7 +4643,7 @@ X figure out why tiff images won't open with after effects X http://dev.processing.org/bugs/show_bug.cgi?id=153 X open with photoshop, resave, see which tags change X specifically, which tags that were in the original image file -X perhaps something gets corrected? +X perhaps something gets corrected? X had a fix, but decided not to re-implement the loadTIFF stuff too X fix for bezierTangent() problem from dave bollinger X http://dev.processing.org/bugs/show_bug.cgi?id=710 @@ -4201,7 +4669,7 @@ X modelX/Y/Z still having trouble X http://dev.processing.org/bugs/show_bug.cgi?id=486 X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1186614415 X add docs for model/screen/Y/Z -X added for model, along with example. +X added for model, along with example. X screen was already complete X bring back opengl mipmaps (create them myself? try w/ newer jogl?) X opengl mipmaps are leaking (regression in spite of #150 fix) @@ -4213,7 +4681,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=681 X check on the bug report for this one as well X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1173394373 -earlier +earlier o add notes about fixing serial on the mac to the faq (and link to bug) X not necessary, hopefuly things working better now X utf8 and encodings @@ -4281,7 +4749,7 @@ X seems as though the begin/end should happen inside beginRaw/Record X defaults() gets called by the size() command in PApplet o would be cool if could sort w/o the sort class.. o meaning use reflection to sort objects, just by implementing a few methods -o would be much simpler and less confusing than new Sort() etc +o would be much simpler and less confusing than new Sort() etc o or would it be ridiculously slow? X just using Comparator instead, since moving to Java 1.4 X make a PException that extends RuntimeException but packages an ex? @@ -4329,7 +4797,7 @@ X set(x, y, image) x, y not setting with processing fixed earlier X is the texture[] array in PGraphics3D causing the problems with memory? -X actually it's a PGraphicsGL problem.. +X actually it's a PGraphicsGL problem.. X maybe the image binding not getting unbound? o should image i/o be moved into PImage? o still needs applet object, so it's not like this is very useful @@ -4338,15 +4806,15 @@ X relevant parts were moved in, others not o loadImage() using spaces in the name o if loadImage() with spaces when online(), throw an error o get tiff exporter for p5 to support argb and gray -X would also need to modify the tiff loading code, +X would also need to modify the tiff loading code, X because the header would be different X http://dev.processing.org/bugs/show_bug.cgi?id=343 X map() is not colored, neither is norm X image outofmemoryerror for casey's students X http://dev.processing.org/bugs/show_bug.cgi?id=355 X this may be related to a ton of other memory bugs -X 1.5.0_07 and 1.4.2_12 contain the -XX:+HeapDumpOnOutOfMemoryError switch -X invaluable for tracking down memory leaks +X 1.5.0_07 and 1.4.2_12 contain the -XX:+HeapDumpOnOutOfMemoryError switch +X invaluable for tracking down memory leaks X can't replicate anymore X texture mapping X very odd, "doom era" stuff @@ -4416,7 +4884,7 @@ X need to strip off past the file separator or something 0130 core X fixed problem with size() and the default renderer -X the renderer was being reset after setup(), +X the renderer was being reset after setup(), X so anything that occurred inside setup() was completely ignored. X http://dev.processing.org/bugs/show_bug.cgi?id=646 X http://dev.processing.org/bugs/show_bug.cgi?id=648 @@ -4473,7 +4941,7 @@ X draw() called twice in vista with java 1.6 X http://dev.processing.org/bugs/show_bug.cgi?id=587 cleanup from previous releases -X P3D not doing bilinear interpolation in text and images +X P3D not doing bilinear interpolation in text and images X because smooth() has to be set (and smooth throws an error in P3D) X how should this be handled? a hint? allowing smooth()? X probably just allow smooth() but don't smooth anything @@ -4518,8 +4986,8 @@ X getFontList stuff in PFont causes problems 0127 core X pixel operations are broken in opengl -X get(), set(), copy(), blend(), loadPixels, updatePixels() -X set(x, y, image) y reversed in openGL +X get(), set(), copy(), blend(), loadPixels, updatePixels() +X set(x, y, image) y reversed in openGL X background(image) also broken X also textMode(SCREEN) X http://dev.processing.org/bugs/show_bug.cgi?id=91 @@ -4527,7 +4995,7 @@ o replaceAll() not supported by 1.1 o http://dev.processing.org/bugs/show_bug.cgi?id=561 o make version of loadBytes that checks length of the stream first o this might not be worth it -o the number of cases where this works is small (half of url streams) +o the number of cases where this works is small (half of url streams) o and who knows if the value returned will be correct o (i.e. will it be the uncompressed or compressed size of the data?) @@ -4550,7 +5018,7 @@ X they can call Runtime.getRuntime().exec() if they want more control fixed earlier (in 0125) by ewjordan X accuracy in P3D is very low X http://dev.processing.org/bugs/show_bug.cgi?id=95 -X textured polys throwing a lot of exceptions (ouch) +X textured polys throwing a lot of exceptions (ouch) X http://dev.processing.org/bugs/show_bug.cgi?id=546 X polygons in z axis with nonzero x or y not filling properly X http://dev.processing.org/bugs/show_bug.cgi?id=547 @@ -4569,7 +5037,7 @@ X instead, returns an array X unregisterXxxx() calls to remove methods from libs X http://dev.processing.org/bugs/show_bug.cgi?id=312 X implemented by ewjordan -X sort() on strings ignores case +X sort() on strings ignores case X mention the change in the reference X added MIN_FLOAT, MAX_FLOAT, MIN_INT, MAX_INT to PConstants X throw AIOOBE when min() or max() called on zero length array @@ -4590,21 +5058,21 @@ X add match() method that returns an array of matched items 0125 core X more blend() modes (the five listed on the thread below?) X http://dev.processing.org/bugs/show_bug.cgi?id=132 -X figure out what the modes should actually be: -X photoshop: normal, dissolve; darken, multiply, color burn, +X figure out what the modes should actually be: +X photoshop: normal, dissolve; darken, multiply, color burn, X linear burn; lighten, screen, color dodge, linear -X dodge; overlay, soft light, hard light, vivid light, -X linear light, pin light, hard mix; difference, +X dodge; overlay, soft light, hard light, vivid light, +X linear light, pin light, hard mix; difference, X exclusion; hue, saturation, color, luminosity X illustrator: normal; darken, multiply, color burn; lighten, -X screen, color dodge; overlay, soft light, hard light; +X screen, color dodge; overlay, soft light, hard light; X difference, exclusion; hue, sat, color, luminosity -X director: Copy, Transparent, Reverse, Ghost, Not copy, +X director: Copy, Transparent, Reverse, Ghost, Not copy, X Not transparent, Not reverse, Not ghost, Matte, Mask; X (below seems more useful: X Blend, Add pin, Add, Subtract pin, Background transparent, X Lightest, Subtract, Darkest, Lighten, Darken -X flash: +X flash: X DIFFERENCE: C = abs(A-B); X MULTIPLY: C = (A * B ) / 255 X SCREEN: C= 255 - ( (255-A) * (255-B) / 255 ) @@ -4626,11 +5094,11 @@ o should we mention String.split? X ironed out more of the preproc parseXxxx() functions X deal with targa upside-down and non-rle encoding for tga images X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1171576234 -X change println(array) to be useful +X change println(array) to be useful o document using join() for old method X remove print(array) since it's silly? X make sure it's not in the reference -X [0] "potato", [1] "tomato", [2] "apple" +X [0] "potato", [1] "tomato", [2] "apple" X fix filter(GRAY) on an ALPHA image to produce a good RGB image 0125p2 @@ -4652,7 +5120,7 @@ X given to andy 0125p3 X PImage.save() method is not working with get() X http://dev.processing.org/bugs/show_bug.cgi?id=558 -X NullPointerException in Create Font with "All Characters" enabled +X NullPointerException in Create Font with "All Characters" enabled X http://dev.processing.org/bugs/show_bug.cgi?id=564 X added min() and max() for float and int arrays X need to update reference @@ -4661,7 +5129,7 @@ X opengl image memory leaking X when creating a new PImage on every frame, slurps a ton of memory X workaround is to write the code properly, but suggests something bad X http://dev.processing.org/bugs/show_bug.cgi?id=150 -X opengl keeping memory around.. +X opengl keeping memory around.. X could this be in vertices that have an image associated X or the image buffer used for textures X that never gets cleared fully? @@ -4684,7 +5152,7 @@ X things not showing up in linux X this may be fixed along with bug #341 X probably threading issue, 98 doesn't have any trouble X signs point to Runner or PApplet changes between 98 and 99 -X commenting out applet.setupFrameResizeListener() +X commenting out applet.setupFrameResizeListener() X in line 307 from Runner.java solved the problem X http://dev.processing.org/bugs/show_bug.cgi?id=282 X size of sketch different in setup() and draw() on linux @@ -4752,7 +5220,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=478 X copy() sort of broken in JAVA2D X example sketch posted with bug report X http://dev.processing.org/bugs/show_bug.cgi?id=372 -o saveStrings(filename, strings, count) +o saveStrings(filename, strings, count) o otherwise the save is kinda wonky o or maybe that should just be done with the array fxns @@ -4761,14 +5229,14 @@ o sketches often freeze when stop is hit on an HT machine o need to test the examples cited on pardis' machine o http://dev.processing.org/bugs/show_bug.cgi?id=232 X debug NumberFormat InterruptedException on dual proc machine -X use notify() instead of interrupt()? +X use notify() instead of interrupt()? X or Thread.currentThread() should be checked first? o svg loader is on the list for 1.0 o maybe include as part of PApplet (casey thinks so) X using gl, lines don't show up in pdf with record (they're ok with p3d) X http://dev.processing.org/bugs/show_bug.cgi?id=325 o with network connection -o download a copy of the source for 0069, get the renderer +o download a copy of the source for 0069, get the renderer o svn mv PGraphics2 PGraphicsJava o version of BApplet that replaces g. with ai. or pdf. @@ -4804,14 +5272,14 @@ X background(0, 0, 0, 0) is the way to really clear everything with zeroes X or background(0, 0), but the former is prolly better conceptually X how to clear the screen with alpha? background(0, 0, 0, 0)? o background(EMPTY) -> background(0x01000000) or something? -X size(), beginRecords(), beginRaw(), createGraphics() +X size(), beginRecords(), beginRaw(), createGraphics() X broken for file-based renderers in 0120 X http://dev.processing.org/bugs/show_bug.cgi?id=434 0120 core X fixed error when using hint(ENABLE_NATIVE_FONTS) with JAVA2D -X java.lang.IllegalArgumentException: +X java.lang.IllegalArgumentException: X null incompatible with Global antialiasing enable key X fix issue where ambientLight(r, g, b) was instead ambientLight(r, g, r) X http://dev.processing.org/bugs/show_bug.cgi?id=412 @@ -4824,7 +5292,7 @@ X actually was z = Float.MAX_VALUE regression X http://dev.processing.org/bugs/show_bug.cgi?id=390 X two examples in sketchbook X this has been reported several times -X concave polygons having trouble if points come back to meet +X concave polygons having trouble if points come back to meet X tesselator/triangulator gets confused when points doubled up X might need to avoid previous vertex hitting itself X http://dev.processing.org/bugs/show_bug.cgi?id=97 @@ -4840,7 +5308,7 @@ o update run.bat for new quicktime o unfortunately this is messy because qtjava sometimes has quotes o and qtsystem might be somewhere besides c:\progra~1 X run.bat has been removed from current releases -X registering font directories in pdf.. is it necessary? +X registering font directories in pdf.. is it necessary? X (commented out for 0100) X re-added for 0120 o when re-calling size() with opengl, need to remove the old canvas @@ -4927,7 +5395,7 @@ X expand, append, contract, subset, splice, concat, reverse X typed version of array functions: X append(), shorten(), splice, slice, subset, concat, reverse X http://dev.processing.org/bugs/show_bug.cgi?id=115 -X fix issue where processing applets would run extremely fast +X fix issue where processing applets would run extremely fast X after having been starved of resources where there framerate dropped X http://dev.processing.org/bugs/show_bug.cgi?id=336 X added color/stroke/tint/fill(#FF8800, 30); @@ -4985,7 +5453,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=392 X loadImage() problems with png and jpg X actually it's an issue with some types of jpeg files X http://dev.processing.org/bugs/show_bug.cgi?id=279 -X java.lang.IllegalArgumentException: +X java.lang.IllegalArgumentException: X Width (-1) and height (-1) cannot be <= 0 X identical to what happens when the image data is bad X for instance, trying to load a tiff image with the jpg loader @@ -5008,13 +5476,13 @@ X or maybe this should be hint(ENABLE_NATIVE_FONTS) instead? X figure out default behavior for native text fonts X make sure insideDrawWait() is in other resize() methods X begin/end/alloc waits to PGraphicsJava2D, PGraphicsOpenGL, PGraphics3D -X fix bug with fill(#ffcc00, 50); +X fix bug with fill(#ffcc00, 50); X toInt() on a float string needs to work X need to check for periods to see if float -> int first X shape changes X remove LINE_STRIP - tell people to use beginShape() with no params X remove LINE_LOOP - tell people to use endShape(CLOSE) -o also remove POLYGON? +o also remove POLYGON? X may as well remove it X though something still needed as an internal constant X add endShape(CLOSE) or CLOSED @@ -5065,7 +5533,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=260 0114 core -X added createGraphics(width, height, renderer) +X added createGraphics(width, height, renderer) X no need to use (..., null) anymore X fix set() for JAVA2D, also fixes background(PImage) for JAVA2D X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1145108567 @@ -5095,7 +5563,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=322 X fix enable/disable textures for some objects X also a big problem for fonts X calling updatePixels() on each frame fixes the issue (sorta) -X images are memory leaking pretty badly +X images are memory leaking pretty badly X texture re-allocated on each frame X lighting bug introduced in rev 109 X spotLight has troubles with an invalid value @@ -5103,26 +5571,26 @@ X probably somethign weird about the params (3 vs 4) being sent X the first spotLight works fine, it's something with the second X (the one that follows the mouse) X just something to debug in the example -X regression from contributed code.. +X regression from contributed code.. X was using apply() instead of set() in PMatrix inverse copy X filter() is also broken (not rewinding the intbuffer) X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1144561113 sound has been removed o duration as an internal param, not a function -o When a sound is finished playing, +o When a sound is finished playing, o it should return to 0 so it can play again o Putting sound.loop() in draw() seemed to spawn multiple sounds threads? o After a sound is paused, it will only play from where it was paused o to its end and will not loop again o The ref in PSound2 says volume accepts vals from 0...1 o but values larger than one increase the volume. -o SoundEvent // is sound finished?? Can't access now. +o SoundEvent // is sound finished?? Can't access now. o make java 1.1 version of PSound work properly o merge PSound and PSound2 via reflection? o once debugged, merge these back together and use reflection o (unless it's a messy disaster) -o Unsupported control type: Master Gain +o Unsupported control type: Master Gain o what's actually causing this error? o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115467831 o PSound.play() won't play the sound a 2nd time (reopened) @@ -5133,7 +5601,7 @@ X need to just remove PSound altogether 0111 core -X need to have a better way of getting/figuring out the endian +X need to have a better way of getting/figuring out the endian X use ByteOrder class in jdk 1.4, since issue is local to JOGL X security ex when run as an applet X also can no longer assume that macosx is big endian @@ -5228,12 +5696,12 @@ X same issue occurs with pdf and creating graphics obj get initial version of pdf working X get rid of beginFrame/endFrame echo to recorders? X that way begin/end can just be where the recorder starts/stops? -X recordRaw is really confusing.. +X recordRaw is really confusing.. X when to use beginFrame/endFrame X is beginRaw/endRaw really needed? X seems to be a problem that it's an applet method X but then it's called on the g of the applet -X but then it's the recorderRaw of that g that gets it called.. +X but then it's the recorderRaw of that g that gets it called.. X how to flush when the sketch is done X inside dispose method? explicit close? X call exit() at end of pdf apps? exit calls dispose on gfx? @@ -5245,13 +5713,13 @@ X write documentation on images (they suck) and fonts (use ttf) 0099 core X removed playing() method from PSound X integrate destroy() method from shiffman as dispose() in PSound2 -X ComponentListener is probably what's needed for resize() +X ComponentListener is probably what's needed for resize() X make sure that components can be resized properly via size() X http://dev.processing.org/bugs/show_bug.cgi?id=209 X or that it properly responds to a setBounds() call X calling size() elsewhere in the app doesn't quite work -X A second call to size almost works. -X The buffer apparently gets allocated and saveFrame saves the +X A second call to size almost works. +X The buffer apparently gets allocated and saveFrame saves the X new size but drawing appears to be disabled. X http://dev.processing.org/bugs/show_bug.cgi?id=243 @@ -5353,7 +5821,7 @@ X tag release 93 (francis thinks it's rev 1666) 0095 core -X undo the fix that causes the width/height to be properly set +X undo the fix that causes the width/height to be properly set 0094 core @@ -5364,7 +5832,7 @@ X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action X "folder" has been renamed to "path" to match savePath(). X added "dataPath" to return the full path to something in the data folder X savePath should maybe be appletPath or sketchPath -X because can be used for opening files too +X because can be used for opening files too X (i.e. if needing a File object) X width, height set to zero in static mode X probably only set when resize() is called, and it's not happening @@ -5426,7 +5894,7 @@ X vertices not included because switching to triangleImpl and lineImpl X fix for copy() in java2d to make things a little speedier X make PApplet.main() for java 1.3 friendly (Color class constants) X remove call to background() in PGraphics2 -o change PGraphics to PGraphics2 +o change PGraphics to PGraphics2 o or not, because PGraphics has all the base stuff for 3D o change PGraphics2 to PGraphicsJava or PGraphicsJava2D o maybe wait until the new shape stuff is done? @@ -5452,13 +5920,13 @@ X add ability to draw text from the current text position X change to synchronization to hopefully fix some update issues X curveVertex() problem in P2D when > 128 points fixed _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115856359;start=0 -X for present mode, need to set a default display +X for present mode, need to set a default display X currently crashes if only --present is specified w/o --display o make the 1.4 code in PApplet load via reflection X doesn't appear necessary with 1.3 applets o or is some of the stuff usable in 1.3 but not all? o ie. the device config classes exist but not the set full screen method -X currently some bugs in the main() because it's not sizing applets +X currently some bugs in the main() because it's not sizing applets X if running in present mode it works ok X but that also needs its display set.. argh X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115834600;start=0 @@ -5489,7 +5957,7 @@ X no changes since 88 X createFont crashes on verdana (win2k) X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115258282;start=0 X made ceil(), floor(), and round() return ints instead of floats -X fix for PSound: Unsupported control type: Master Gain +X fix for PSound: Unsupported control type: Master Gain X just shuts off the volume control X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115467831;start=0 @@ -5620,9 +6088,9 @@ X how to handle full screen (opengl especially) or no screen (for scripts) tweaking up simong light code o what's up with resetLights? o add PLight object to avoid method overflow -o preApplyMatrix, invApplyMatrix? +o preApplyMatrix, invApplyMatrix? o applyMatrixPre and applyMatrixIn -o rotateXInv is ugly.. +o rotateXInv is ugly.. o irotateX?, papplyMatrix? wednesday evening @@ -5632,7 +6100,7 @@ X call it open() X what to call firstMouse X implement rightMouse? X yes, mouseButton = LEFT, CENTER, or RIGHT -X error when running on 1.1... +X error when running on 1.1... X You need to install Java 1.3 or later to view this content. X Click here to visit java.com and install. X make inverseCamera into cameraInv @@ -5649,7 +6117,7 @@ X use canonicalPath to flag possible problems X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1096508877;start=5 o fix shapes in P3D (line loop, polygons, etc) o should we include a from and to for the directional light? -X no, cuz it doesn't do much really.. +X no, cuz it doesn't do much really.. X fromX-toX etc is all that's different thursday day @@ -5661,12 +6129,12 @@ o textMode(ALIGN_LEFT) etc, should make sure that left/center/right not used X though since have to change to LEFT, should be easy to switch friday night -o should toInt('5') return the ascii or the char? +o should toInt('5') return the ascii or the char? X since (int) '5' returns the ascii, that's what it does X made a note in the PApplet reference text api -X textMode ALIGN_CENTER _LEFT _RIGHT -> CENTER, LEFT, RIGHT ? +X textMode ALIGN_CENTER _LEFT _RIGHT -> CENTER, LEFT, RIGHT ? X use built-in font if available? yes o text() with \n is semi-broken X does the font or PApplet control the size? (the font, ala java) @@ -5683,12 +6151,12 @@ o since needs to render to screen as well o font has to be installed to get psname X fine because why would you embed a ps font that you don't have? o need to resolve SCREEN_SPACE vs OBJECT_SPACE -o can this be auto-detected with noDepth()? +o can this be auto-detected with noDepth()? o how does rotated text work? o PFont.rotate(180) rotate(PI) o or can this be detected from the matrix? X don't use pixels to do screen space text inside PFont -X add a function in PGraphics for direct pixel image impl +X add a function in PGraphics for direct pixel image impl X store the font name in the vlw font file (at the end) o could include multiple names for multi platforms X get text impl stuff working properly @@ -5698,7 +6166,7 @@ o NEW_GRAPHICS totally smashes everything friday postgame X implement createFont() X with a .ttf does a create font internally (1.3+ only) -X although the images aren't populated +X although the images aren't populated X until a P2D/P3D/OPENGL tries to draw them, which triggers it X but if PGraphics2, just uses the built-in font X also works for font names and just creating them @@ -5747,7 +6215,7 @@ X write list of params that can be passed to PApplet o document in the code a note about how size() et al place themselves X saveFrame was double-adding the save path because of save() changes -size(200, 200, P3D) - createGraphics and placement issues +size(200, 200, P3D) - createGraphics and placement issues X make pappletgl work back inside papplet X and then size(300, 300, DEPTH) etc X get rid of opengl renderer menu @@ -5757,8 +6225,8 @@ X how to force PGraphics() instead of PGraphics2() X size(300, 200, P2D); X size() doing a setBounds() is really bad X because it means things can't be embedded properly -o applets on osx (and windows) sometimes show up 20 pixels off the top -X how to shut off rendering to screen when illustrator in use? +o applets on osx (and windows) sometimes show up 20 pixels off the top +X how to shut off rendering to screen when illustrator in use? X need size(30000, 20000) for illustrator, problem in papplet X size(30000, 20000, ILLUSTRATOR) X make Graphics2 et al load dynamically using reflection @@ -5773,7 +6241,7 @@ present mode o call present() from inside the code? o that if applet is 500x500, centers on a 800x600 window X no, that's nasty... use --present to launch in present window -X though how do you get the screen size? +X though how do you get the screen size? X screen.width and screen.height? - yes X write java 1.4 code for full screen version of PApplet X this might be used for presentation mode @@ -5790,13 +6258,13 @@ X make sure the program compiles before starting present mode 0080 core X PApplet.saveFrame() is saving to sketch folder, PApplet.save() is not -X PApplet.save() will save to the applet folder, +X PApplet.save() will save to the applet folder, X but PImage.save() or PGraphics.save() will save only to the current X working directory, usually the Processing folder. X removed static version of mask() from PImage X no more PImage.mask(theImage, maskImage) X just use theImage.mask(maskImage) -X PImage.filter() +X PImage.filter() X maybe use quasimondo's gaussian blur code? X http://incubator.quasimondo.com/processing/gaussian_blur_1.php o filter() on subsections? yes, in keeping with rest of api @@ -5819,7 +6287,7 @@ o check to see if it's a rounding error with width() o get text rect working again (seems to be in infinite loop) X nope, was just that the space width wasn't being scaled up properly X clean up the javadoc so no more errors -X change mbox to PFont.size? +X change mbox to PFont.size? o make width() return values based on natural size? X not a great idea.. plus java2d uses 1 pixel font for things X email simon re: lighting api @@ -5832,7 +6300,7 @@ X goodbye sphere(x, y, z, r) o should available() be waiting() or something like that instead? o go through and see what functions (no pixel ops?) frame recorders should have X decided instead to use recordFrame(PGraphics) -o remove SCREEN_SPACE altogether? +o remove SCREEN_SPACE altogether? X can't do this for now implemented in 79 @@ -5908,14 +6376,14 @@ X (as they are working in Processing mode) o screenX/Y aren't properly working for 2D points against a 3D matrix o (ryan alexander rounding bug) o Just to clarify, it works completely correctly with rounding -o screenX/Y and also using the 3 arg version of translate - -o ie translate(hw,hh,0) instead of just translate(hw,hh). +o screenX/Y and also using the 3 arg version of translate - +o ie translate(hw,hh,0) instead of just translate(hw,hh). X no longer an issue because moving to 2D and 3D modes o PImage: remove the static versions of manipulators? o probably not, because they're inherited by PApplet -o i.e. mask(image, themask); +o i.e. mask(image, themask); X no PImage needed b/c PGraphics is a PImage -o colorMode(GRAY) to avoid stroke(0) causing trouble? +o colorMode(GRAY) to avoid stroke(0) causing trouble? o or maybe get rid of stroke(0)? hrm @@ -5981,9 +6449,9 @@ X pushing all intelligence down into class that implements PMethods o keep hints about type of geometry used to reconstruct o no special class, just uses public vars from PGraphics o how to hook into curve rendering so that curve segments are drawn -o maybe lines are rendered and sorted, -o but they point to an original version of the curve geometry -o that can be re-rendered +o maybe lines are rendered and sorted, +o but they point to an original version of the curve geometry +o that can be re-rendered o also integrate catmull-rom -> bezier inverse matrices o even with the general catmull-rom, to render via ai beziers @@ -6017,7 +6485,7 @@ o loadImage() needs to handle 1.1 vs 1.3 loading o set image.format to be BUFFERED? no.. just use RGBA always o have a flag to always use the cache, i.e. with BufferedImage o turn that off when someone modifies it (nope, no need to) -X PImage.getPixels(), updatePixels(), updatePixels(x, y, w, h), +X PImage.getPixels(), updatePixels(), updatePixels(x, y, w, h), o PImage.setPixels(int another[]); X imageMode(CENTER) is weird for copy() and updatePixels() X perhaps copy() and get() ignore imageMode and use xywh or x1y1x2y2? @@ -6069,7 +6537,7 @@ X no changes, only launcher issues 0075 X textureMode(NORMAL_SPACE) screws up the image() command -X image() appears to require IMAGE_SPACE to function properly. +X image() appears to require IMAGE_SPACE to function properly. X added focusGained() and focusLost() X lots of changes to internal naming of vars X screenX(x, y) and screenY(x, y) added for noDepth() @@ -6087,7 +6555,7 @@ X remove pmouseX/Y altogether X maintain things a bit different o email the beta@ list to see how people are using pmouseX X changed PMovie.length to PMovie.duration -X move around/simplify loadImage() inside PApplet +X move around/simplify loadImage() inside PApplet X working to add more die() statements inside PApplet o can ALPHA fonts work using the other replace modes? @@ -6120,15 +6588,15 @@ X bring back renderer menu X reading/saving pref for opengl renderer X remove cameraMode(PERSPECTIVE) on each frame X why is the first one failing? -X still threading issues with running opengl -X threading really horks up dual processor machine.. -X first run hangs until quit +X still threading issues with running opengl +X threading really horks up dual processor machine.. +X first run hangs until quit X though doesn't seem to replicate when p5 is restarted X make sure background() gets called at least once with opengl X otherwise screen never actually updates X beginFrame() around setup() -X draw mode stuff happens inside setup.. -o or maybe need to get better at size() inside of draw() ? +X draw mode stuff happens inside setup.. +o or maybe need to get better at size() inside of draw() ? X make this consistent with the regular PApplet X otherwise things are going to be weird/difficult for debugging @@ -6146,7 +6614,7 @@ X hacked for a fix in 72, but need to better coordinate with openStream() 0072 core X make m00, m01 etc public -X hack to make loadImage() work +X hack to make loadImage() work X cache settings are ignored, may be slow as hell X make hints[] no longer static X they weren't properly resetting @@ -6201,7 +6669,7 @@ X need to resolve issues between rendering screen/file X illustrator-based rendering needs to work for ars projects X screen may be 400x400 pixels, but file be 36x36" X launcher.cpp broke serial.. see versions in processing.notcvs -X rewrite bagel code.. +X rewrite bagel code.. X for this release, because it will break things along with the lib stuff X switch to PImage, PApplet, etc o bug in BImage.smooth() when resizing an image @@ -6261,7 +6729,7 @@ o problem is that BGraphics has the loadStream code, not BApplet o new sphere code from toxi o already added a while back o http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1067005325 -o sphere code needs only front face polygon +o sphere code needs only front face polygon o all triangles must be counter-clockwise (front-facing) X fix loadImage to be inside PApplet @@ -6303,10 +6771,10 @@ X text(String text, x, y, width, height) // based on rectMode X textMode() for align left, center, right (no justify.. har!) X hex(), binary(), unhex(), unbinary() -040725 +040725 X fix array functions not returning a value -040726 +040726 X noiseSeed and randomSeed X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1090749784;start=0 @@ -6317,15 +6785,15 @@ X incorporated NO_FLYING_POO line/poly hack developed for axel X sort() should return an array, rather than sort in place X fix binary function, had wrong offset number X casey: i wan't able to get binary() to work at all: -o Typography: Helix won't compile +o Typography: Helix won't compile o works fine, just needs BFont -> PFont X standalone 'alpha' function for PImage (static methods for alpha fxns) X Image: Edge, Image: Blur: Alpha not set? The error is easier to see on Blur X turns out bounds checking wasn't working properly on colors -040903 +040903 X fix mouse/key events, make properly public for the package stuff -X The biggest problem was the key and mouse functions not working. +X The biggest problem was the key and mouse functions not working. X Input: Mouse_Functions X Input: Keyboard_Functions X processing.net -> PClient, PServer @@ -6347,7 +6815,7 @@ X loop/noLoop setup 040920 X make loop/noLoop work properly X fixes/changes to key and mousehandling -X tab key not working? +X tab key not working? X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1091853942;start=0 X mousePressed, keyPressed, others.. queue them all X queue multiple times @@ -6365,7 +6833,7 @@ X otherwise noLoop() in setup means no drawing happens at all X defaults for PApplet and PGraphics are different o PGraphics has none.. PApplet has fill/stroke X actually not the case, only that wasn't calling decent superclass -X set PImage.format as RGB by default? +X set PImage.format as RGB by default? X this was problem with rendering an image from PGraphics on board X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1091798655;start=0 X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1080671926;start=0 @@ -6376,7 +6844,7 @@ X bug in get() that was removing the high bits (rather than adding) 040921 evening X lots of work on libraries, figuring out PLibrary api -040922 +040922 X get library stuff debugged X port arcball and finish up dxf writer X beginCamera() no longer sets an identity matrix @@ -6412,7 +6880,7 @@ X printMatrix() and printCamera() to output the matrices for each X more functions made static (loadStrings, loadBytes) that could be X print() commands in BApplet were among these X die() command to exit an application or just stall out an applet -X die(String error) and die(String error, Exception e) +X die(String error) and die(String error, Exception e) X more documentation in comments for functions X chop() function that properly also handles nbsp X join() was handled weird diff --git a/core/library/export.txt b/core/library/export.txt index 88d0bc274b..a750489709 100644 --- a/core/library/export.txt +++ b/core/library/export.txt @@ -8,4 +8,5 @@ application.windows32=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-wind application.windows64=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-windows-amd64.jar,gluegen-rt-natives-windows-amd64.jar application.linux32=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-i586.jar,gluegen-rt-natives-linux-i586.jar application.linux64=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-amd64.jar,gluegen-rt-natives-linux-amd64.jar -application.linux-armv6hf=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-armv6hf.jar,gluegen-rt-natives-linux-armv6hf.jar \ No newline at end of file +application.linux-armv6hf=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-armv6hf.jar,gluegen-rt-natives-linux-armv6hf.jar +application.linux-arm64=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-aarch64.jar,gluegen-rt-natives-linux-aarch64.jar diff --git a/core/library/gluegen-rt-natives-linux-aarch64.jar b/core/library/gluegen-rt-natives-linux-aarch64.jar new file mode 100644 index 0000000000..94c6d5e27b Binary files /dev/null and b/core/library/gluegen-rt-natives-linux-aarch64.jar differ diff --git a/core/library/jogl-all-natives-linux-aarch64.jar b/core/library/jogl-all-natives-linux-aarch64.jar new file mode 100644 index 0000000000..c856f34c2c Binary files /dev/null and b/core/library/jogl-all-natives-linux-aarch64.jar differ diff --git a/core/library/jogl-all.jar b/core/library/jogl-all.jar index e2c7b44b42..970a7dead9 100644 Binary files a/core/library/jogl-all.jar and b/core/library/jogl-all.jar differ diff --git a/core/src/processing/awt/PGraphicsJava2D.java b/core/src/processing/awt/PGraphicsJava2D.java index 325563526e..7d6e1c5972 100644 --- a/core/src/processing/awt/PGraphicsJava2D.java +++ b/core/src/processing/awt/PGraphicsJava2D.java @@ -82,7 +82,7 @@ public class PGraphicsJava2D extends PGraphics { float[] curveDrawY; int transformCount; - AffineTransform transformStack[] = + AffineTransform[] transformStack = new AffineTransform[MATRIX_STACK_DEPTH]; double[] transform = new double[6]; @@ -302,32 +302,41 @@ public Graphics2D checkImage() { // image = new BufferedImage(width * pixelFactor, height * pixelFactor // format == RGB ? BufferedImage.TYPE_INT_ARGB); - GraphicsConfiguration gc = null; - if (surface != null) { - Component comp = null; //surface.getComponent(); - if (comp == null) { -// System.out.println("component null, but parent.frame is " + parent.frame); - comp = parent.frame; - } - if (comp != null) { - gc = comp.getGraphicsConfiguration(); - } - } - // If not realized (off-screen, i.e the Color Selector Tool), gc will be null. - if (gc == null) { - //System.err.println("GraphicsConfiguration null in initImage()"); - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - gc = ge.getDefaultScreenDevice().getDefaultConfiguration(); - } +// Commenting this out, because we are not drawing directly to the screen [jv 2018-06-01] +// +// GraphicsConfiguration gc = null; +// if (surface != null) { +// Component comp = null; //surface.getComponent(); +// if (comp == null) { +//// System.out.println("component null, but parent.frame is " + parent.frame); +// comp = parent.frame; +// } +// if (comp != null) { +// gc = comp.getGraphicsConfiguration(); +// } +// } +// // If not realized (off-screen, i.e the Color Selector Tool), gc will be null. +// if (gc == null) { +// //System.err.println("GraphicsConfiguration null in initImage()"); +// GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); +// gc = ge.getDefaultScreenDevice().getDefaultConfiguration(); +// } // Formerly this was broken into separate versions based on offscreen or // not, but we may as well create a compatible image; it won't hurt, right? + // P.S.: Three years later, I'm happy to report it did in fact hurt [jv 2018-06-01] int wide = width * pixelDensity; int high = height * pixelDensity; // System.out.println("re-creating image"); - image = gc.createCompatibleImage(wide, high, Transparency.TRANSLUCENT); -// image = gc.createCompatibleVolatileImage(wide, high); - //image = surface.getComponent().createImage(width, height); + + // For now we expect non-premultiplied INT ARGB and the compatible image + // might not be it... create the image directly. It's important that the + // image has all four bands, otherwise we get garbage alpha during blending + // (see https://github.com/processing/processing/pull/2645, + // https://github.com/processing/processing/pull/3523) + // + // image = gc.createCompatibleImage(wide, high, Transparency.TRANSLUCENT); + image = new BufferedImage(wide, high, BufferedImage.TYPE_INT_ARGB); } return (Graphics2D) image.getGraphics(); } @@ -409,8 +418,6 @@ public void beginDraw() { checkSettings(); resetMatrix(); // reset model matrix vertexCount = 0; - - g2.scale(pixelDensity, pixelDensity); } @@ -775,7 +782,7 @@ public void vertex(float x, float y) { //float vertex[]; if (vertexCount == vertices.length) { - float temp[][] = new float[vertexCount<<1][VERTEX_FIELD_COUNT]; + float[][] temp = new float[vertexCount<<1][VERTEX_FIELD_COUNT]; System.arraycopy(vertices, 0, temp, 0, vertexCount); vertices = temp; //message(CHATTER, "allocating more vertices " + vertices.length); @@ -1573,8 +1580,8 @@ protected void imageImpl(PImage who, // Nuke the cache if the image was resized if (cash != null) { - if (who.width != cash.image.getWidth() || - who.height != cash.image.getHeight()) { + if (who.pixelWidth != cash.image.getWidth() || + who.pixelHeight != cash.image.getHeight()) { cash = null; } } @@ -1601,12 +1608,17 @@ protected void imageImpl(PImage who, // This might be a PGraphics that hasn't been drawn to yet. // Can't just bail because the cache has been created above. // https://github.com/processing/processing/issues/2208 - who.pixels = new int[who.width * who.height]; + who.pixels = new int[who.pixelWidth * who.pixelHeight]; } cash.update(who, tint, tintColor); who.setModified(false); } + u1 *= who.pixelDensity; + v1 *= who.pixelDensity; + u2 *= who.pixelDensity; + v2 *= who.pixelDensity; + g2.drawImage(((ImageCache) getCache(who)).image, (int) x1, (int) y1, (int) x2, (int) y2, u1, v1, u2, v2, null); @@ -1674,14 +1686,14 @@ public void update(PImage source, boolean tint, int tintColor) { // in the alpha channel when drawn to the screen. // https://github.com/processing/processing/issues/2030 if (image == null) { - image = new BufferedImage(source.width, source.height, + image = new BufferedImage(source.pixelWidth, source.pixelHeight, BufferedImage.TYPE_INT_ARGB); } WritableRaster wr = image.getRaster(); if (tint) { - if (tintedTemp == null || tintedTemp.length != source.width) { - tintedTemp = new int[source.width]; + if (tintedTemp == null || tintedTemp.length != source.pixelWidth) { + tintedTemp = new int[source.pixelWidth]; } int a2 = (tintColor >> 24) & 0xff; // System.out.println("tint color is " + a2); @@ -1695,8 +1707,8 @@ public void update(PImage source, boolean tint, int tintColor) { // The target image is opaque, meaning that the source image has no // alpha (is not ARGB), and the tint has no alpha. int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + for (int y = 0; y < source.pixelHeight; y++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1710,7 +1722,7 @@ public void update(PImage source, boolean tint, int tintColor) { ((g2 * g1) & 0xff00) | (((b2 * b1) & 0xff00) >> 8); } - wr.setDataElements(0, y, source.width, 1, tintedTemp); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } // could this be any slower? // float[] scales = { tintR, tintG, tintB }; @@ -1724,18 +1736,18 @@ public void update(PImage source, boolean tint, int tintColor) { (tintColor & 0xffffff) == 0xffffff) { int hi = tintColor & 0xff000000; int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + for (int y = 0; y < source.pixelHeight; y++) { + for (int x = 0; x < source.pixelWidth; x++) { tintedTemp[x] = hi | (source.pixels[index++] & 0xFFFFFF); } - wr.setDataElements(0, y, source.width, 1, tintedTemp); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } } else { int index = 0; - for (int y = 0; y < source.height; y++) { + for (int y = 0; y < source.pixelHeight; y++) { if (source.format == RGB) { int alpha = tintColor & 0xFF000000; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1746,7 +1758,7 @@ public void update(PImage source, boolean tint, int tintColor) { (((b2 * b1) & 0xff00) >> 8); } } else if (source.format == ARGB) { - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int a1 = (argb1 >> 24) & 0xff; int r1 = (argb1 >> 16) & 0xff; @@ -1760,13 +1772,13 @@ public void update(PImage source, boolean tint, int tintColor) { } } else if (source.format == ALPHA) { int lower = tintColor & 0xFFFFFF; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int a1 = source.pixels[index++]; tintedTemp[x] = (((a2 * a1) & 0xff00) << 16) | lower; } } - wr.setDataElements(0, y, source.width, 1, tintedTemp); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } } // Not sure why ARGB images take the scales in this order... @@ -1786,7 +1798,7 @@ public void update(PImage source, boolean tint, int tintColor) { // in a PImage and how the high bits will be set. } // If no tint, just shove the pixels on in there verbatim - wr.setDataElements(0, 0, source.width, source.height, source.pixels); + wr.setDataElements(0, 0, source.pixelWidth, source.pixelHeight, source.pixels); } this.tinted = tint; this.tintedColor = tintColor; @@ -1908,33 +1920,29 @@ protected boolean textModeCheck(int mode) { @Override protected void handleTextSize(float size) { // if a native version available, derive this font -// if (textFontNative != null) { -// textFontNative = textFontNative.deriveFont(size); -// g2.setFont(textFontNative); -// textFontNativeMetrics = g2.getFontMetrics(textFontNative); -// } Font font = (Font) textFont.getNative(); - //if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) { + // don't derive again if the font size has not changed if (font != null) { - Map map = - new HashMap(); - map.put(TextAttribute.SIZE, size); - map.put(TextAttribute.KERNING, - TextAttribute.KERNING_ON); + if (font.getSize2D() != size) { + Map map = + new HashMap<>(); + map.put(TextAttribute.SIZE, size); + map.put(TextAttribute.KERNING, + TextAttribute.KERNING_ON); // map.put(TextAttribute.TRACKING, // TextAttribute.TRACKING_TIGHT); - font = font.deriveFont(map); + font = font.deriveFont(map); + } g2.setFont(font); textFont.setNative(font); fontObject = font; -// Font dfont = font.deriveFont(size); -//// Map attrs = dfont.getAttributes(); -//// for (TextAttribute ta : attrs.keySet()) { -//// System.out.println(ta + " -> " + attrs.get(ta)); -//// } -// g2.setFont(dfont); -// textFont.setNative(dfont); + /* + Map attrs = font.getAttributes(); + for (TextAttribute ta : attrs.keySet()) { + System.out.println(ta + " -> " + attrs.get(ta)); + } + */ } // take care of setting the textSize and textLeading vars @@ -1951,7 +1959,7 @@ protected void handleTextSize(float size) { @Override - protected float textWidthImpl(char buffer[], int start, int stop) { + protected float textWidthImpl(char[] buffer, int start, int stop) { if (textFont == null) { defaultFontOrDeath("textWidth"); } @@ -2020,7 +2028,7 @@ protected float textWidthImpl(char buffer[], int start, int stop) { @Override - protected void textLineImpl(char buffer[], int start, int stop, + protected void textLineImpl(char[] buffer, int start, int stop, float x, float y) { Font font = (Font) textFont.getNative(); // if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) { @@ -2236,6 +2244,7 @@ public void shearY(float angle) { @Override public void resetMatrix() { g2.setTransform(new AffineTransform()); + g2.scale(pixelDensity, pixelDensity); } @@ -2819,7 +2828,7 @@ public void updatePixels(int x, int y, int c, int d) { // GET/SET - static int getset[] = new int[1]; + static int[] getset = new int[1]; @Override @@ -2840,12 +2849,6 @@ public int get(int x, int y) { //public PImage get(int x, int y, int w, int h) - @Override - public PImage get() { - return get(0, 0, width, height); - } - - @Override protected void getImpl(int sourceX, int sourceY, int sourceWidth, int sourceHeight, @@ -2856,7 +2859,7 @@ protected void getImpl(int sourceX, int sourceY, // ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); WritableRaster raster = getRaster(); - if (sourceWidth == target.width && sourceHeight == target.height) { + if (sourceWidth == target.pixelWidth && sourceHeight == target.pixelHeight) { raster.getDataElements(sourceX, sourceY, sourceWidth, sourceHeight, target.pixels); // https://github.com/processing/processing/issues/2030 if (raster.getNumBands() == 3) { @@ -2870,7 +2873,7 @@ protected void getImpl(int sourceX, int sourceY, // Copy the temporary output pixels over to the outgoing image int sourceOffset = 0; - int targetOffset = targetY*target.width + targetX; + int targetOffset = targetY*target.pixelWidth + targetX; for (int y = 0; y < sourceHeight; y++) { if (raster.getNumBands() == 3) { for (int i = 0; i < sourceWidth; i++) { @@ -2882,7 +2885,7 @@ protected void getImpl(int sourceX, int sourceY, System.arraycopy(temp, sourceOffset, target.pixels, targetOffset, sourceWidth); } sourceOffset += sourceWidth; - targetOffset += target.width; + targetOffset += target.pixelWidth; } } } @@ -2890,7 +2893,7 @@ protected void getImpl(int sourceX, int sourceY, @Override public void set(int x, int y, int argb) { - if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return; + if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return; // ((BufferedImage) image).setRGB(x, y, argb); getset[0] = argb; // WritableRaster raster = ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); @@ -2911,18 +2914,18 @@ protected void setImpl(PImage sourceImage, // ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); if ((sourceX == 0) && (sourceY == 0) && - (sourceWidth == sourceImage.width) && - (sourceHeight == sourceImage.height)) { + (sourceWidth == sourceImage.pixelWidth) && + (sourceHeight == sourceImage.pixelHeight)) { // System.out.format("%d %d %dx%d %d%n", targetX, targetY, // sourceImage.width, sourceImage.height, // sourceImage.pixels.length); raster.setDataElements(targetX, targetY, - sourceImage.width, sourceImage.height, + sourceImage.pixelWidth, sourceImage.pixelHeight, sourceImage.pixels); } else { // TODO optimize, incredibly inefficient to reallocate this much memory PImage temp = sourceImage.get(sourceX, sourceY, sourceWidth, sourceHeight); - raster.setDataElements(targetX, targetY, temp.width, temp.height, temp.pixels); + raster.setDataElements(targetX, targetY, temp.pixelWidth, temp.pixelHeight, temp.pixels); } } @@ -2938,7 +2941,6 @@ protected void setImpl(PImage sourceImage, @Override - @SuppressWarnings("deprecation") public void mask(int[] alpha) { if (primaryGraphics) { showWarning(MASK_WARNING); diff --git a/core/src/processing/awt/PSurfaceAWT.java b/core/src/processing/awt/PSurfaceAWT.java index cd4649436a..71a59e87f5 100644 --- a/core/src/processing/awt/PSurfaceAWT.java +++ b/core/src/processing/awt/PSurfaceAWT.java @@ -90,6 +90,8 @@ public class PSurfaceAWT extends PSurfaceNone { int sketchWidth; int sketchHeight; + int windowScaleFactor; + public PSurfaceAWT(PGraphics graphics) { //this.graphics = graphics; @@ -224,7 +226,7 @@ public void validate() { if (!oldSize.equals(newSize)) { // System.out.println("validate() render old=" + oldSize + " -> new=" + newSize); oldSize = newSize; - sketch.setSize(newSize.width, newSize.height); + sketch.setSize(newSize.width / windowScaleFactor, newSize.height / windowScaleFactor); // try { render(); // } catch (IllegalStateException ise) { @@ -423,8 +425,11 @@ public void initFrame(final PApplet sketch) {/*, int backgroundColor, sketch.displayWidth = screenRect.width; sketch.displayHeight = screenRect.height; - sketchWidth = sketch.sketchWidth(); - sketchHeight = sketch.sketchHeight(); + windowScaleFactor = PApplet.platform == PConstants.MACOSX ? + 1 : sketch.pixelDensity; + + sketchWidth = sketch.sketchWidth() * windowScaleFactor; + sketchHeight = sketch.sketchHeight() * windowScaleFactor; boolean fullScreen = sketch.sketchFullScreen(); // Removing the section below because sometimes people want to do the @@ -481,7 +486,7 @@ public void initFrame(final PApplet sketch) {/*, int backgroundColor, // http://dev.processing.org/bugs/show_bug.cgi?id=908 frame.add(canvas); - setSize(sketchWidth, sketchHeight); + setSize(sketchWidth / windowScaleFactor, sketchHeight / windowScaleFactor); /* if (fullScreen) { @@ -940,6 +945,16 @@ public void placeWindow(int[] location, int[] editorLocation) { // needs to resize the frame, which will resize the canvas, and so on... @Override public void setSize(int wide, int high) { + // When the surface is set to resizable via surface.setResizable(true), + // a crash may occur if the user sets the window to size zero. + // https://github.com/processing/processing/issues/5052 + if (high <= 0) { + high = 1; + } + if (wide <= 0) { + wide = 1; + } + // if (PApplet.DEBUG) { // //System.out.format("frame visible %b, setSize(%d, %d) %n", frame.isVisible(), wide, high); // new Exception(String.format("setSize(%d, %d)", wide, high)).printStackTrace(System.out); @@ -954,8 +969,8 @@ public void setSize(int wide, int high) { return; // unchanged, don't rebuild everything } - sketchWidth = wide; - sketchHeight = high; + sketchWidth = wide * windowScaleFactor; + sketchHeight = high * windowScaleFactor; // canvas.setSize(wide, high); // frame.setSize(wide, high); @@ -1142,8 +1157,9 @@ public void componentResized(ComponentEvent e) { // overall size of the window. Perhaps JFrame sets its coord // system so that (0, 0) is always the upper-left of the content // area. Which seems nice, but breaks any f*ing AWT-based code. - setSize(windowSize.width - currentInsets.left - currentInsets.right, - windowSize.height - currentInsets.top - currentInsets.bottom); + int w = windowSize.width - currentInsets.left - currentInsets.right; + int h = windowSize.height - currentInsets.top - currentInsets.bottom; + setSize(w / windowScaleFactor, h / windowScaleFactor); // correct the location when inset size changes setLocation(x - currentInsets.left, y - currentInsets.top); @@ -1300,19 +1316,10 @@ protected void nativeMouseEvent(java.awt.event.MouseEvent nativeEvent) { peButton = PConstants.RIGHT; } - // If running on Mac OS, allow ctrl-click as right mouse. Prior to 0215, - // this used isPopupTrigger() on the native event, but that doesn't work - // for mouseClicked and mouseReleased (or others). - if (PApplet.platform == PConstants.MACOSX) { - //if (nativeEvent.isPopupTrigger()) { - if ((modifiers & InputEvent.CTRL_MASK) != 0) { - peButton = PConstants.RIGHT; - } - } - sketch.postEvent(new MouseEvent(nativeEvent, nativeEvent.getWhen(), peAction, peModifiers, - nativeEvent.getX(), nativeEvent.getY(), + nativeEvent.getX() / windowScaleFactor, + nativeEvent.getY() / windowScaleFactor, peButton, peCount)); } diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 048276d8a1..c43fbca8cb 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -24,28 +24,40 @@ package processing.core; -// used by link() -import java.awt.Desktop; -import java.awt.DisplayMode; -import java.awt.EventQueue; -import java.awt.FileDialog; +// dummy object for backwards compatibility, plus the select methods import java.awt.Frame; + +// before calling settings() to get displayWidth/Height +import java.awt.DisplayMode; +// handleSettings() and displayDensity() import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; +// used to present the fullScreen() warning about Spaces on OS X +import javax.swing.JOptionPane; + +// inside runSketch() to warn users about headless import java.awt.HeadlessException; -import java.awt.Image; import java.awt.Toolkit; + +// used by loadImage() +import java.awt.Image; import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; - -// used by loadImage() functions import javax.imageio.ImageIO; // allows us to remove our own MediaTracker code import javax.swing.ImageIcon; + // used by selectInput(), selectOutput(), selectFolder() +import java.awt.EventQueue; +import java.awt.FileDialog; import javax.swing.JFileChooser; -// used to present the fullScreen() warning about Spaces on OS X -import javax.swing.JOptionPane; + +// set the look and feel, if specified +import javax.swing.UIManager; + +// used by link() +import java.awt.Desktop; + // used by desktopFile() method import javax.swing.filechooser.FileSystemView; @@ -60,6 +72,11 @@ import java.nio.charset.StandardCharsets; import java.text.*; import java.util.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; import java.util.regex.*; import java.util.zip.*; @@ -108,45 +125,25 @@ public class PApplet implements PConstants { static public final String javaVersionName = System.getProperty("java.version"); -// /** Short name of Java version, i.e. 1.8. */ -// static public final String javaVersionShort = -// //javaVersionName.substring(0, 3); -// javaVersionName.substring(0, javaVersionName.indexOf(".", 2)); -// // can't use this one, it's 1.8.0 and breaks things -// //javaVersionName.substring(0, javaVersionName.indexOf("_")); - - static public final int javaPlatform = - PApplet.parseInt(PApplet.split(javaVersionName, '.')[1]); -// static { -// try { -// javaPlatform = PApplet.split(javaVersionName, '.')[1]; -// } catch (Exception e) { -// javaPlatform = "8"; // set a default in case -// } -// } + static public final int javaPlatform; + static { + String version = javaVersionName; + if (javaVersionName.startsWith("1.")) { + version = version.substring(2); + javaPlatform = parseInt(version.substring(0, version.indexOf('.'))); + } else { + // Remove -xxx and .yyy from java.version (@see JEP-223) + javaPlatform = parseInt(version.replaceAll("-.*","").replaceAll("\\..*","")); + } + } /** - * Version of Java that's in use, whether 1.1 or 1.3 or whatever, - * stored as a float. - *

- * Note that because this is stored as a float, the values may not be - * exactly 1.3 or 1.4. The PDE will make 1.8 or whatever into - * a float automatically, so outside the PDE, make sure you're comparing - * against 1.3f or 1.4f, which will have the same amount of error - * (i.e. 1.40000001). This could just be a double, but since Processing - * only uses floats, it's safer as a float because specifying a double - * (with this narrow case especially) with the preprocessor is awkward. - *

- * @deprecated Java 10 is around the corner. Use javaPlatform when you need - * a number for comparisons, i.e. "if (javaPlatform >= 7)". + * Do not use; javaPlatform or javaVersionName are better options. + * For instance, javaPlatform is useful when you need a number for + * comparison, i.e. "if (javaPlatform >= 9)". */ @Deprecated - public static final float javaVersion = - new Float(javaVersionName.substring(0, 3)); -// public static final float javaVersion = -// new Float(javaVersionName.substring(0, javaVersionName.indexOf(".", 2))).floatValue(); -// // Making this a String in 3.0, in anticipation of Java 10 -// public static final String javaVersion = "1." + javaPlatform; + public static final float javaVersion = 1 + javaPlatform / 10f; /** * Current platform in use, one of the @@ -173,12 +170,10 @@ public class PApplet implements PConstants { /** * Whether to use native (AWT) dialogs for selectInput and selectOutput. - * The native dialogs on Linux tend to be pretty awful. With selectFolder() - * this is ignored, because there is no native folder selector, except on - * Mac OS X. On OS X, the native folder selector will be used unless - * useNativeSelect is set to false. + * The native dialogs on some platforms can be ugly, buggy, or missing + * features. For 3.3.5, this defaults to true on all platforms. */ - static public boolean useNativeSelect = (platform != LINUX); + static public boolean useNativeSelect = true; /** The PGraphics renderer associated with this PApplet */ public PGraphics g; @@ -286,6 +281,9 @@ public class PApplet implements PConstants { * @see PApplet#get(int, int, int, int) * @see PApplet#set(int, int, int) * @see PImage + * @see PApplet#pixelDensity() + * @see PApplet#pixelWidth + * @see PApplet#pixelHeight */ public int[] pixels; @@ -565,6 +563,14 @@ public class PApplet implements PConstants { */ public boolean mousePressed; + // MACOSX: CTRL + Left Mouse is converted to Right Mouse. This boolean keeps + // track of whether the conversion happened on PRESS, because we should report + // the same button during DRAG and on RELEASE, even though CTRL might have + // been released already. Otherwise the events are inconsistent, e.g. + // Left Pressed - Left Drag - CTRL Pressed - Right Drag - Right Released. + // See: https://github.com/processing/processing/issues/5672 + private boolean macosxLeftButtonWithCtrlPressed; + /** @deprecated Use a mouse event handler that passes an event instead. */ @Deprecated @@ -655,6 +661,7 @@ public class PApplet implements PConstants { * @see PApplet#keyReleased() */ public boolean keyPressed; + List pressedKeys = new ArrayList<>(6); /** * The last KeyEvent object passed into a mouse function. @@ -708,7 +715,7 @@ public class PApplet implements PConstants { * @see PApplet#frameRate(float) * @see PApplet#frameCount */ - public float frameRate = 10; + public float frameRate = 60; protected boolean looping = true; @@ -787,6 +794,8 @@ public class PApplet implements PConstants { */ static public final String ARGS_SKETCH_FOLDER = "--sketch-path"; + static public final String ARGS_DENSITY = "--density"; + /** * When run externally to a PdeEditor, * this is sent by the sketch when it quits. @@ -906,6 +915,9 @@ public PSurface getSurface() { // Unlike the others above, needs to be public to support // the pixelWidth and pixelHeight fields. public int pixelDensity = 1; + int suggestedDensity = -1; + + boolean present; String outputPath; OutputStream outputStream; @@ -994,6 +1006,7 @@ void handleSettings() { if ("0".equals(result)) { EventQueue.invokeLater(new Runnable() { public void run() { + checkLookAndFeel(); final String msg = "To use fullScreen(SPAN), first turn off “Displays have separate spaces”\n" + "in System Preferences \u2192 Mission Control. Then log out and log back in."; @@ -1124,23 +1137,23 @@ final public int sketchPixelDensity() { * @see PApplet#size(int,int) */ public int displayDensity() { - if (display == SPAN) { - // walk through all displays, use lowest common denominator - for (int i = 0; i < displayDevices.length; i++) { - if (displayDensity(i) != 2) { - return 1; - } + if (display != SPAN && (fullScreen || present)) { + return displayDensity(display); + } + // walk through all displays, use 2 if any display is 2 + for (int i = 0; i < displayDevices.length; i++) { + if (displayDensity(i+1) == 2) { + return 2; } - // If nobody's density is 1 (or != 2, to be exact) then everyone is 2 - return 2; } - return displayDensity(display); + // If nobody's density is 2 then everyone is 1 + return 1; } /** * @param display the display number to check */ - static public int displayDensity(int display) { + public int displayDensity(int display) { if (PApplet.platform == PConstants.MACOSX) { // This should probably be reset each time there's a display change. // A 5-minute search didn't turn up any such event in the Java 7 API. @@ -1183,6 +1196,15 @@ static public int displayDensity(int display) { } } catch (Exception ignore) { } } + } else if (PApplet.platform == PConstants.WINDOWS || + PApplet.platform == PConstants.LINUX) { + if (suggestedDensity == -1) { + // TODO: detect and return DPI scaling using JNA; Windows has + // a system-wide value, not sure how it works on Linux + return 1; + } else if (suggestedDensity == 1 || suggestedDensity == 2) { + return suggestedDensity; + } } return 1; } @@ -1191,20 +1213,29 @@ static public int displayDensity(int display) { /** * @webref environment * @param density 1 or 2 - * + * @see PApplet#pixelWidth + * @see PApplet#pixelHeight */ public void pixelDensity(int density) { + //println(density + " " + this.pixelDensity); if (density != this.pixelDensity) { if (insideSettings("pixelDensity", density)) { if (density != 1 && density != 2) { throw new RuntimeException("pixelDensity() can only be 1 or 2"); } - if (density == 2 && displayDensity() == 1) { + if (!FX2D.equals(renderer) && density == 2 && displayDensity() == 1) { + // FX has its own check in PSurfaceFX // Don't throw exception because the sketch should still work - throw new RuntimeException("pixelDensity(2) is not available for this display"); + System.err.println("pixelDensity(2) is not available for this display"); + this.pixelDensity = 1; } else { this.pixelDensity = density; } + } else { + System.err.println("not inside settings"); + // this should only be reachable when not running in the PDE, + // so saying it's a settings()--not just setup()--issue should be ok + throw new RuntimeException("pixelDensity() can only be used inside settings()"); } } } @@ -1379,7 +1410,10 @@ public void resume() { } /** Map of registered methods, stored by name. */ HashMap registerMap = - new HashMap(); + new HashMap<>(); + + /** Lock when un/registering from multiple threads */ + private final Object registerLock = new Object[0]; class RegisteredMethods { @@ -1522,16 +1556,17 @@ public void registerMethod(String methodName, Object target) { private void registerNoArgs(String name, Object o) { - RegisteredMethods meth = registerMap.get(name); - if (meth == null) { - meth = new RegisteredMethods(); - registerMap.put(name, meth); - } Class c = o.getClass(); try { - Method method = c.getMethod(name, new Class[] {}); - meth.add(o, method); - + Method method = c.getMethod(name); + synchronized (registerLock) { + RegisteredMethods meth = registerMap.get(name); + if (meth == null) { + meth = new RegisteredMethods(); + registerMap.put(name, meth); + } + meth.add(o, method); + } } catch (NoSuchMethodException nsme) { die("There is no public " + name + "() method in the class " + o.getClass().getName()); @@ -1543,16 +1578,17 @@ private void registerNoArgs(String name, Object o) { private void registerWithArgs(String name, Object o, Class cargs[]) { - RegisteredMethods meth = registerMap.get(name); - if (meth == null) { - meth = new RegisteredMethods(); - registerMap.put(name, meth); - } Class c = o.getClass(); try { Method method = c.getMethod(name, cargs); - meth.add(o, method); - + synchronized (registerLock) { + RegisteredMethods meth = registerMap.get(name); + if (meth == null) { + meth = new RegisteredMethods(); + registerMap.put(name, meth); + } + meth.add(o, method); + } } catch (NoSuchMethodException nsme) { die("There is no public " + name + "() method in the class " + o.getClass().getName()); @@ -1569,32 +1605,38 @@ private void registerWithArgs(String name, Object o, Class cargs[]) { public void unregisterMethod(String name, Object target) { - RegisteredMethods meth = registerMap.get(name); - if (meth == null) { - die("No registered methods with the name " + name + "() were found."); - } - try { + synchronized (registerLock) { + RegisteredMethods meth = registerMap.get(name); + if (meth == null) { + die("No registered methods with the name " + name + "() were found."); + } + try { // Method method = o.getClass().getMethod(name, new Class[] {}); // meth.remove(o, method); - meth.remove(target); - } catch (Exception e) { - die("Could not unregister " + name + "() for " + target, e); + meth.remove(target); + } catch (Exception e) { + die("Could not unregister " + name + "() for " + target, e); + } } } protected void handleMethods(String methodName) { - RegisteredMethods meth = registerMap.get(methodName); - if (meth != null) { - meth.handle(); + synchronized (registerLock) { + RegisteredMethods meth = registerMap.get(methodName); + if (meth != null) { + meth.handle(); + } } } protected void handleMethods(String methodName, Object[] args) { - RegisteredMethods meth = registerMap.get(methodName); - if (meth != null) { - meth.handle(args); + synchronized (registerLock) { + RegisteredMethods meth = registerMap.get(methodName); + if (meth != null) { + meth.handle(args); + } } } @@ -1962,6 +2004,9 @@ public void fullScreen(String renderer, int display) { * @param height height of the display window in units of pixels * @see PApplet#width * @see PApplet#height + * @see PApplet#setup() + * @see PApplet#settings() + * @see PApplet#fullScreen() */ public void size(int width, int height) { // Check to make sure the width/height have actually changed. It's ok to @@ -2395,9 +2440,34 @@ public void handleDraw() { } else { // frameCount > 0, meaning an actual draw() // update the current frameRate - double rate = 1000000.0 / ((now - frameRateLastNanos) / 1000000.0); - float instantaneousRate = (float) (rate / 1000.0); - frameRate = (frameRate * 0.9f) + (instantaneousRate * 0.1f); + + // Calculate frameRate through average frame times, not average fps, e.g.: + // + // Alternating 2 ms and 20 ms frames (JavaFX or JOGL sometimes does this) + // is around 90.91 fps (two frames in 22 ms, one frame 11 ms). + // + // However, averaging fps gives us: (500 fps + 50 fps) / 2 = 275 fps. + // This is because we had 500 fps for 2 ms and 50 fps for 20 ms, but we + // counted them with equal weight. + // + // If we average frame times instead, we get the right result: + // (2 ms + 20 ms) / 2 = 11 ms per frame, which is 1000/11 = 90.91 fps. + // + // The counter below uses exponential moving average. To do the + // calculation, we first convert the accumulated frame rate to average + // frame time, then calculate the exponential moving average, and then + // convert the average frame time back to frame rate. + { + // Get the frame time of the last frame + double frameTimeSecs = (now - frameRateLastNanos) / 1e9; + // Convert average frames per second to average frame time + double avgFrameTimeSecs = 1.0 / frameRate; + // Calculate exponential moving average of frame time + final double alpha = 0.05; + avgFrameTimeSecs = (1.0 - alpha) * avgFrameTimeSecs + alpha * frameTimeSecs; + // Convert frame time back to frames per second + frameRate = (float) (1.0 / avgFrameTimeSecs); + } if (frameCount != 0) { handleMethods("pre"); @@ -2556,38 +2626,8 @@ public boolean isLooping() { ////////////////////////////////////////////////////////////// - InternalEventQueue eventQueue = new InternalEventQueue(); - - - static class InternalEventQueue { - protected Event queue[] = new Event[10]; - protected int offset; - protected int count; - - synchronized void add(Event e) { - if (count == queue.length) { - queue = (Event[]) expand(queue); - } - queue[count++] = e; - } - - synchronized Event remove() { - if (offset == count) { - throw new RuntimeException("Nothing left on the event queue."); - } - Event outgoing = queue[offset++]; - if (offset == count) { - // All done, time to reset - offset = 0; - count = 0; - } - return outgoing; - } - - synchronized boolean available() { - return count != 0; - } - } + BlockingQueue eventQueue = new LinkedBlockingQueue<>(); + private final Object eventQueueDequeueLock = new Object[0]; /** @@ -2604,16 +2644,17 @@ public void postEvent(processing.event.Event pe) { protected void dequeueEvents() { - while (eventQueue.available()) { - Event e = eventQueue.remove(); - - switch (e.getFlavor()) { - case Event.MOUSE: - handleMouseEvent((MouseEvent) e); - break; - case Event.KEY: - handleKeyEvent((KeyEvent) e); - break; + synchronized (eventQueueDequeueLock) { + while (!eventQueue.isEmpty()) { + Event e = eventQueue.remove(); + switch (e.getFlavor()) { + case Event.MOUSE: + handleMouseEvent((MouseEvent) e); + break; + case Event.KEY: + handleKeyEvent((KeyEvent) e); + break; + } } } } @@ -2648,8 +2689,27 @@ protected void handleMouseEvent(MouseEvent event) { mouseY = event.getY(); } + int button = event.getButton(); + + // If running on Mac OS, allow ctrl-click as right mouse. + if (PApplet.platform == PConstants.MACOSX && event.getButton() == PConstants.LEFT) { + if (action == MouseEvent.PRESS && event.isControlDown()) { + macosxLeftButtonWithCtrlPressed = true; + } + if (macosxLeftButtonWithCtrlPressed) { + button = PConstants.RIGHT; + event = new MouseEvent(event.getNative(), event.getMillis(), + event.getAction(), event.getModifiers(), + event.getX(), event.getY(), + button, event.getCount()); + } + if (action == MouseEvent.RELEASE) { + macosxLeftButtonWithCtrlPressed = false; + } + } + // Get the (already processed) button code - mouseButton = event.getButton(); + mouseButton = button; /* // Compatibility for older code (these have AWT object params, not P5) @@ -2937,11 +2997,14 @@ protected void handleKeyEvent(KeyEvent event) { switch (event.getAction()) { case KeyEvent.PRESS: + Long hash = ((long) keyCode << Character.SIZE) | key; + if (!pressedKeys.contains(hash)) pressedKeys.add(hash); keyPressed = true; keyPressed(keyEvent); break; case KeyEvent.RELEASE: - keyPressed = false; + pressedKeys.remove(((long) keyCode << Character.SIZE) | key); + keyPressed = !pressedKeys.isEmpty(); keyReleased(keyEvent); break; case KeyEvent.TYPE: @@ -3123,7 +3186,10 @@ public void keyTyped(KeyEvent event) { public void focusGained() { } - public void focusLost() { } + public void focusLost() { + // TODO: if user overrides this without calling super it's not gonna work + pressedKeys.clear(); + } @@ -3476,20 +3542,183 @@ static public Process launch(String... args) { } + /** + * Pass a set of arguments directly to the command line. Uses Java's + * Runtime.exec() + * method. This is different from the launch() + * method, which uses the operating system's launcher to open the files. + * It's always a good idea to use a full path to the executable here. + *

+   * exec("/usr/bin/say", "welcome to the command line");
+   * 
+ * Or if you want to wait until it's completed, something like this: + *
+   * Process p = exec("/usr/bin/say", "waiting until done");
+   * try {
+   *   int result = p.waitFor();
+   *   println("the process returned " + result);
+   * } catch (InterruptedException e) { }
+   * 
+ * You can also get the system output and error streams from the Process + * object, but that's more that we'd like to cover here. + * @return a Process object + */ static public Process exec(String... args) { try { return Runtime.getRuntime().exec(args); } catch (Exception e) { - throw new RuntimeException("Could not open " + join(args, ' '), e); + throw new RuntimeException("Exception while attempting " + join(args, ' '), e); } } - // yuck.. maybe this is just a class -// static public int exec(StringList stdout, StringList stderr, String... args) { -// Process p = exec(args); -// int result = p.waitFor(); -// } + static class LineThread extends Thread { + InputStream input; + StringList output; + + + LineThread(InputStream input, StringList output) { + this.input = input; + this.output = output; + start(); + } + + @Override + public void run() { + // It's not sufficient to use BufferedReader, because if the app being + // called fills up stdout or stderr to quickly, the app will hang. + // Instead, write to a byte[] array and then parse it once finished. + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + saveStream(baos, input); + BufferedReader reader = + createReader(new ByteArrayInputStream(baos.toByteArray())); + String line; + while ((line = reader.readLine()) != null) { + output.append(line); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + + /** + * Alternative version of exec() that retrieves stdout and stderr into the + * StringList objects provided. This is a convenience function that handles + * simple exec() calls. If the results will be more than a couple lines, + * you shouldn't use this function, you should use a more elaborate method + * that makes use of proper threading (to drain the shell output) and error + * handling to address the many things that can go wrong within this method. + * + * @param stdout a non-null StringList object to be filled with any output + * @param stderr a non-null StringList object to be filled with error lines + * @param args each argument to be passed as a series of String objects + * @return the result returned from the application, or -1 if an Exception + * occurs before the application is able to return a result. + */ + static public int exec(StringList stdout, StringList stderr, String... args) { + Process p = exec(args); + + Thread outThread = new LineThread(p.getInputStream(), stdout); + Thread errThread = new LineThread(p.getErrorStream(), stderr); + /* + final InputStream err = p.getErrorStream(); + final InputStream out = p.getInputStream(); + Thread outThread = new Thread(() -> { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String line; + try { + saveStream(baos, out); + BufferedReader err2 = createReader(new ByteArrayInputStream(baos.toByteArray())); + while ((line = err2.readLine()) != null) { + stdout.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + }); + outThread.start(); + + Thread errThread = new Thread(() -> { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String line; + try { + saveStream(baos, err); + BufferedReader err2 = createReader(new ByteArrayInputStream(baos.toByteArray())); + while ((line = err2.readLine()) != null) { + stderr.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + }); + errThread.start(); + */ + + try { + int result = p.waitFor(); + outThread.join(); + errThread.join(); + return result; + + } catch (InterruptedException e) { + // Throwing the exception here because we can't give a valid 'result' + throw new RuntimeException(e); + } + } + + + /** + * Same as exec() above, but prefixes the call with a shell. + */ + static public int shell(StringList stdout, StringList stderr, String... args) { + String shell; + String runCmd; + StringList argList = new StringList(); + if (platform == WINDOWS) { + shell = System.getenv("COMSPEC"); + runCmd = "/C"; + } else { + shell = "/bin/sh"; + runCmd = "-c"; + // attempt emulate the behavior of an interactive shell + // can't use -i or -l since the version of bash shipped with macOS does not support this together with -c + // also we want to make sure no motd or similar gets returned as stdout + argList.append("if [ -f /etc/profile ]; then . /etc/profile >/dev/null 2>&1; fi;"); + argList.append("if [ -f ~/.bash_profile ]; then . ~/.bash_profile >/dev/null 2>&1; elif [ -f ~/.bash_profile ]; then . ~/.bash_profile >/dev/null 2>&1; elif [ -f ~/.profile ]; then ~/.profile >/dev/null 2>&1; fi;"); + } + for (String arg : args) { + argList.append(arg); + } + return exec(stdout, stderr, shell, runCmd, argList.join(" ")); + } + + + /* + static private final String shellQuoted(String arg) { + if (arg.indexOf(' ') != -1) { + // check to see if already quoted + if ((arg.charAt(0) != '\"' || arg.charAt(arg.length()-1) != '\"') && + (arg.charAt(0) != '\'' || arg.charAt(arg.length()-1) != '\'')) { + + // see which quotes we can use + if (arg.indexOf('\"') == -1) { + // if no double quotes, try those first + return "\"" + arg + "\""; + + } else if (arg.indexOf('\'') == -1) { + // if no single quotes, let's use those + return "'" + arg + "'"; + } + } + } + return arg; + } + */ ////////////////////////////////////////////////////////////// @@ -3607,6 +3836,17 @@ public void dispose() { // run dispose() methods registered by libraries handleMethods("dispose"); } + + if (platform == MACOSX) { + try { + final String td = "processing.core.ThinkDifferent"; + final Class thinkDifferent = getClass().getClassLoader().loadClass(td); + thinkDifferent.getMethod("cleanup").invoke(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + } @@ -5165,7 +5405,6 @@ public void noiseDetail(int lod) { /** * @see #noiseDetail(int) - * @param lod number of octaves to be used by the noise * @param falloff falloff factor for each octave */ public void noiseDetail(int lod, float falloff) { @@ -5267,9 +5506,10 @@ public PImage loadImage(String filename) { */ public PImage loadImage(String filename, String extension) { //, Object params) { - // await... has to run on the main thread, because P2D and P3D call GL functions - // If this runs on background, requestImage() already called await... on the main thread - if (g != null && !Thread.currentThread().getName().startsWith(ASYNC_IMAGE_LOADER_THREAD_PREFIX)) { + // awaitAsyncSaveCompletion() has to run on the main thread, because P2D + // and P3D call GL functions. If this runs on background, requestImage() + // already called awaitAsyncSaveCompletion() on the main thread. + if (g != null && !Thread.currentThread().getName().startsWith(REQUEST_IMAGE_THREAD_PREFIX)) { g.awaitAsyncSaveCompletion(filename); } @@ -5278,14 +5518,16 @@ public PImage loadImage(String filename, String extension) { //, Object params) int dot = filename.lastIndexOf('.'); if (dot == -1) { extension = "unknown"; // no extension found - } - extension = lower.substring(dot + 1); - // check for, and strip any parameters on the url, i.e. - // filename.jpg?blah=blah&something=that - int question = extension.indexOf('?'); - if (question != -1) { - extension = extension.substring(0, question); + } else { + extension = lower.substring(dot + 1); + + // check for, and strip any parameters on the url, i.e. + // filename.jpg?blah=blah&something=that + int question = extension.indexOf('?'); + if (question != -1) { + extension = extension.substring(0, question); + } } } @@ -5306,7 +5548,7 @@ public PImage loadImage(String filename, String extension) { //, Object params) } if (extension.equals("tif") || extension.equals("tiff")) { - byte bytes[] = loadBytes(filename); + byte[] bytes = loadBytes(filename); PImage image = (bytes == null) ? null : PImage.loadTIFF(bytes); // if (params != null) { // image.setParams(g, params); @@ -5321,7 +5563,7 @@ public PImage loadImage(String filename, String extension) { //, Object params) if (extension.equals("jpg") || extension.equals("jpeg") || extension.equals("gif") || extension.equals("png") || extension.equals("unknown")) { - byte bytes[] = loadBytes(filename); + byte[] bytes = loadBytes(filename); if (bytes == null) { return null; } else { @@ -5395,8 +5637,12 @@ public PImage loadImage(String filename, String extension) { //, Object params) } + static private final String REQUEST_IMAGE_THREAD_PREFIX = "requestImage"; + // fixed-size thread pool used by requestImage() + ExecutorService requestImagePool; + + public PImage requestImage(String filename) { -// return requestImage(filename, null, null); return requestImage(filename, null); } @@ -5430,62 +5676,17 @@ public PImage requestImage(String filename, String extension) { g.awaitAsyncSaveCompletion(filename); } PImage vessel = createImage(0, 0, ARGB); - AsyncImageLoader ail = - new AsyncImageLoader(filename, extension, vessel); - ail.start(); - return vessel; - } - - -// /** -// * @nowebref -// */ -// public PImage requestImage(String filename, String extension, Object params) { -// PImage vessel = createImage(0, 0, ARGB, params); -// AsyncImageLoader ail = -// new AsyncImageLoader(filename, extension, vessel); -// ail.start(); -// return vessel; -// } - - - /** - * By trial and error, four image loading threads seem to work best when - * loading images from online. This is consistent with the number of open - * connections that web browsers will maintain. The variable is made public - * (however no accessor has been added since it's esoteric) if you really - * want to have control over the value used. For instance, when loading local - * files, it might be better to only have a single thread (or two) loading - * images so that you're disk isn't simply jumping around. - */ - public int requestImageMax = 4; - volatile int requestImageCount; - private static final String ASYNC_IMAGE_LOADER_THREAD_PREFIX = "ASYNC_IMAGE_LOADER"; - - class AsyncImageLoader extends Thread { - String filename; - String extension; - PImage vessel; - - public AsyncImageLoader(String filename, String extension, PImage vessel) { - // Give these threads distinct name so we can check whether we are loading - // on the main/background thread; for now they are all named the same - super(ASYNC_IMAGE_LOADER_THREAD_PREFIX); - this.filename = filename; - this.extension = extension; - this.vessel = vessel; + // if the image loading thread pool hasn't been created, create it + if (requestImagePool == null) { + ThreadFactory factory = new ThreadFactory() { + public Thread newThread(Runnable r) { + return new Thread(r, REQUEST_IMAGE_THREAD_PREFIX); + } + }; + requestImagePool = Executors.newFixedThreadPool(4, factory); } - - @Override - public void run() { - while (requestImageCount == requestImageMax) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { } - } - requestImageCount++; - + requestImagePool.execute(() -> { PImage actual = loadImage(filename, extension); // An error message should have already printed @@ -5503,31 +5704,11 @@ public void run() { vessel.pixelHeight = actual.height; vessel.pixelDensity = 1; } - requestImageCount--; - } + }); + return vessel; } - // done internally by ImageIcon -// /** -// * Load an AWT image synchronously by setting up a MediaTracker for -// * a single image, and blocking until it has loaded. -// */ -// protected PImage loadImageMT(Image awtImage) { -// MediaTracker tracker = new MediaTracker(this); -// tracker.addImage(awtImage, 0); -// try { -// tracker.waitForAll(); -// } catch (InterruptedException e) { -// //e.printStackTrace(); // non-fatal, right? -// } -// -// PImage image = new PImage(awtImage); -// image.parent = this; -// return image; -// } - - /** * Use Java 1.4 ImageIO methods to load an image. */ @@ -5584,7 +5765,7 @@ protected PImage loadImageTGA(String filename) throws IOException { InputStream is = createInput(filename); if (is == null) return null; - byte header[] = new byte[18]; + byte[] header = new byte[18]; int offset = 0; do { int count = is.read(header, offset, header.length - offset); @@ -5704,7 +5885,7 @@ header[17] image descriptor (packed bits) } else { // header[2] is 10 or 11 int index = 0; - int px[] = outgoing.pixels; + int[] px = outgoing.pixels; while (index < px.length) { int num = is.read(); @@ -5818,7 +5999,11 @@ public XML loadXML(String filename) { */ public XML loadXML(String filename, String options) { try { - return new XML(createReader(filename), options); + BufferedReader reader = createReader(filename); + if (reader != null) { + return new XML(reader, options); + } + return null; // can't use catch-all exception, since it might catch the // RuntimeException about the incorrect case sensitivity @@ -5898,17 +6083,38 @@ public JSONObject parseJSONObject(String input) { * @see PApplet#saveJSONArray(JSONArray, String) */ public JSONObject loadJSONObject(String filename) { - return new JSONObject(createReader(filename)); + // can't pass of createReader() to the constructor b/c of resource leak + BufferedReader reader = createReader(filename); + JSONObject outgoing = new JSONObject(reader); + try { + reader.close(); + } catch (IOException e) { // not sure what would cause this + e.printStackTrace(); + } + return outgoing; } + /** + * @nowebref + */ static public JSONObject loadJSONObject(File file) { - return new JSONObject(createReader(file)); + // can't pass of createReader() to the constructor b/c of resource leak + BufferedReader reader = createReader(file); + JSONObject outgoing = new JSONObject(reader); + try { + reader.close(); + } catch (IOException e) { // not sure what would cause this + e.printStackTrace(); + } + return outgoing; } /** * @webref output:files + * @param json the JSONObject to save + * @param filename the name of the file to save to * @see JSONObject * @see JSONArray * @see PApplet#loadJSONObject(String) @@ -5919,8 +6125,9 @@ public boolean saveJSONObject(JSONObject json, String filename) { return saveJSONObject(json, filename, null); } + /** - * @nowebref + * @param options "compact" and "indent=N", replace N with the number of spaces */ public boolean saveJSONObject(JSONObject json, String filename, String options) { return json.save(saveFile(filename), options); @@ -5947,17 +6154,35 @@ public JSONArray parseJSONArray(String input) { * @see PApplet#saveJSONArray(JSONArray, String) */ public JSONArray loadJSONArray(String filename) { - return new JSONArray(createReader(filename)); + // can't pass of createReader() to the constructor b/c of resource leak + BufferedReader reader = createReader(filename); + JSONArray outgoing = new JSONArray(reader); + try { + reader.close(); + } catch (IOException e) { // not sure what would cause this + e.printStackTrace(); + } + return outgoing; } static public JSONArray loadJSONArray(File file) { - return new JSONArray(createReader(file)); + // can't pass of createReader() to the constructor b/c of resource leak + BufferedReader reader = createReader(file); + JSONArray outgoing = new JSONArray(reader); + try { + reader.close(); + } catch (IOException e) { // not sure what would cause this + e.printStackTrace(); + } + return outgoing; } /** * @webref output:files + * @param json the JSONArray to save + * @param filename the name of the file to save to * @see JSONObject * @see JSONArray * @see PApplet#loadJSONObject(String) @@ -5968,7 +6193,9 @@ public boolean saveJSONArray(JSONArray json, String filename) { return saveJSONArray(json, filename, null); } - + /** + * @param options "compact" and "indent=N", replace N with the number of spaces + */ public boolean saveJSONArray(JSONArray json, String filename, String options) { return json.save(saveFile(filename), options); } @@ -6132,18 +6359,6 @@ public PFont loadFont(String filename) { } - /** - * Used by PGraphics to remove the requirement for loading a font! - */ - protected PFont createDefaultFont(float size) { -// Font f = new Font("SansSerif", Font.PLAIN, 12); -// println("n: " + f.getName()); -// println("fn: " + f.getFontName()); -// println("ps: " + f.getPSName()); - return createFont("Lucida Sans", size, true, null); - } - - public PFont createFont(String name, float size) { return createFont(name, size, true, null); } @@ -6242,6 +6457,25 @@ private Frame selectFrame() { */ + static private boolean lookAndFeelCheck; + + /** + * Initialize the Look & Feel if it hasn't been already. + * Call this before using any Swing-related code in PApplet methods. + */ + static private void checkLookAndFeel() { + if (!lookAndFeelCheck) { + if (platform == WINDOWS) { + // Windows is defaulting to Metal or something else awful. + // Which also is not scaled properly with HiDPI interfaces. + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { } + } + lookAndFeelCheck = true; + } + } + /** * Open a platform-specific file chooser dialog to select a file for input. * After the selection is made, the selected File will be passed to the @@ -6454,6 +6688,7 @@ public void run() { selectedFile = new File(fileDialog.getDirectory(), fileDialog.getFile()); } } else { + checkLookAndFeel(); JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle(prompt); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); @@ -6486,11 +6721,138 @@ static private void selectCallback(File selectedFile, } catch (IllegalAccessException iae) { System.err.println(callbackMethod + "() must be public"); - } catch (InvocationTargetException ite) { - ite.printStackTrace(); + } catch (InvocationTargetException ite) { + ite.printStackTrace(); + + } catch (NoSuchMethodException nsme) { + System.err.println(callbackMethod + "() could not be found"); + } + } + + + + ////////////////////////////////////////////////////////////// + + // LISTING DIRECTORIES + + + public String[] listPaths(String path, String... options) { + File[] list = listFiles(path, options); + + int offset = 0; + for (String opt : options) { + if (opt.equals("relative")) { + if (!path.endsWith(File.pathSeparator)) { + path += File.pathSeparator; + } + offset = path.length(); + break; + } + } + String[] outgoing = new String[list.length]; + for (int i = 0; i < list.length; i++) { + // as of Java 1.8, substring(0) returns the original object + outgoing[i] = list[i].getAbsolutePath().substring(offset); + } + return outgoing; + } + + + public File[] listFiles(String path, String... options) { + File file = new File(path); + // if not an absolute path, make it relative to the sketch folder + if (!file.isAbsolute()) { + file = sketchFile(path); + } + return listFiles(file, options); + } + + + // "relative" -> no effect with the Files version, but important for listPaths + // "recursive" + // "extension=js" or "extensions=js|csv|txt" (no dot) + // "directories" -> only directories + // "files" -> only files + // "hidden" -> include hidden files (prefixed with .) disabled by default + static public File[] listFiles(File base, String... options) { + boolean recursive = false; + String[] extensions = null; + boolean directories = true; + boolean files = true; + boolean hidden = false; + + for (String opt : options) { + if (opt.equals("recursive")) { + recursive = true; + } else if (opt.startsWith("extension=")) { + extensions = new String[] { opt.substring(10) }; + } else if (opt.startsWith("extensions=")) { + extensions = split(opt.substring(10), ','); + } else if (opt.equals("files")) { + directories = false; + } else if (opt.equals("directories")) { + files = false; + } else if (opt.equals("hidden")) { + hidden = true; + } else if (opt.equals("relative")) { + // ignored + } else { + throw new RuntimeException(opt + " is not a listFiles() option"); + } + } + + if (extensions != null) { + for (int i = 0; i < extensions.length; i++) { + extensions[i] = "." + extensions[i]; + } + } + + if (!files && !directories) { + // just make "only files" and "only directories" mean... both + files = true; + directories = true; + } + + if (!base.canRead()) { + return null; + } + + List outgoing = new ArrayList<>(); + listFilesImpl(base, recursive, extensions, hidden, directories, files, outgoing); + return outgoing.toArray(new File[0]); + } - } catch (NoSuchMethodException nsme) { - System.err.println(callbackMethod + "() could not be found"); + + static void listFilesImpl(File folder, boolean recursive, + String[] extensions, boolean hidden, + boolean directories, boolean files, + List list) { + File[] items = folder.listFiles(); + if (items != null) { + for (File item : items) { + String name = item.getName(); + if (!hidden && name.charAt(0) == '.') { + continue; + } + if (item.isDirectory()) { + if (recursive) { + listFilesImpl(item, recursive, extensions, hidden, directories, files, list); + } + if (directories) { + list.add(item); + } + } else if (files) { + if (extensions == null) { + list.add(item); + } else { + for (String ext : extensions) { + if (item.getName().toLowerCase().endsWith(ext)) { + list.add(item); + } + } + } + } + } } } @@ -6584,7 +6946,20 @@ static public BufferedReader createReader(File file) { static public BufferedReader createReader(InputStream input) { InputStreamReader isr = new InputStreamReader(input, StandardCharsets.UTF_8); - return new BufferedReader(isr); + + BufferedReader reader = new BufferedReader(isr); + // consume the Unicode BOM (byte order marker) if present + try { + reader.mark(1); + int c = reader.read(); + // if not the BOM, back up to the beginning again + if (c != '\uFEFF') { + reader.reset(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return reader; } @@ -6650,20 +7025,12 @@ static public PrintWriter createWriter(OutputStream output) { } + ////////////////////////////////////////////////////////////// // FILE INPUT - // Removed for 3.0a8 -// /** -// * @deprecated As of release 0136, use createInput() instead. -// */ -// public InputStream openStream(String filename) { -// return createInput(filename); -// } - - /** * ( begin auto-generated from createInput.xml ) * @@ -6736,17 +7103,22 @@ static public PrintWriter createWriter(OutputStream output) { */ public InputStream createInput(String filename) { InputStream input = createInputRaw(filename); - final String lower = filename.toLowerCase(); - if ((input != null) && - (lower.endsWith(".gz") || lower.endsWith(".svgz"))) { - try { - return new GZIPInputStream(input); - } catch (IOException e) { - printStackTrace(e); - return null; + if (input != null) { + // if it's gzip-encoded, automatically decode + final String lower = filename.toLowerCase(); + if (lower.endsWith(".gz") || lower.endsWith(".svgz")) { + try { + // buffered has to go *around* the GZ, otherwise 25x slower + return new BufferedInputStream(new GZIPInputStream(input)); + + } catch (IOException e) { + printStackTrace(e); + } + } else { + return new BufferedInputStream(input); } } - return input; + return null; } @@ -6767,19 +7139,19 @@ public InputStream createInputRaw(String filename) { return null; } - // First check whether this looks like a URL. This will prevent online - // access logs from being spammed with GET /sketchfolder/http://blahblah + // First check whether this looks like a URL if (filename.contains(":")) { // at least smells like URL try { URL url = new URL(filename); URLConnection conn = url.openConnection(); + if (conn instanceof HttpURLConnection) { HttpURLConnection httpConn = (HttpURLConnection) conn; // Will not handle a protocol change (see below) httpConn.setInstanceFollowRedirects(true); int response = httpConn.getResponseCode(); - // Normally will not follow HTTPS redirects from HTTP due to security concerns - // http://stackoverflow.com/questions/1884230/java-doesnt-follow-redirect-in-urlconnection/1884427 + // Default won't follow HTTP -> HTTPS redirects for security reasons + // http://stackoverflow.com/a/1884427 if (response >= 300 && response < 400) { String newLocation = httpConn.getHeaderField("Location"); return createInputRaw(newLocation); @@ -6909,6 +7281,7 @@ public InputStream createInputRaw(String filename) { return null; } + /** * @nowebref */ @@ -6916,12 +7289,17 @@ static public InputStream createInput(File file) { if (file == null) { throw new IllegalArgumentException("File passed to createInput() was null"); } + if (!file.exists()) { + System.err.println(file + " does not exist, createInput() will return null"); + return null; + } try { InputStream input = new FileInputStream(file); - if (file.getName().toLowerCase().endsWith(".gz")) { - return new GZIPInputStream(input); + final String lower = file.getName().toLowerCase(); + if (lower.endsWith(".gz") || lower.endsWith(".svgz")) { + return new BufferedInputStream(new GZIPInputStream(input)); } - return input; + return new BufferedInputStream(input); } catch (IOException e) { System.err.println("Could not createInput() for " + file); @@ -6953,6 +7331,76 @@ static public InputStream createInput(File file) { * */ public byte[] loadBytes(String filename) { + String lower = filename.toLowerCase(); + // If it's not a .gz file, then we might be able to uncompress it into + // a fixed-size buffer, which should help speed because we won't have to + // reallocate and resize the target array each time it gets full. + if (!lower.endsWith(".gz")) { + // If this looks like a URL, try to load it that way. Use the fact that + // URL connections may have a content length header to size the array. + if (filename.contains(":")) { // at least smells like URL + InputStream input = null; + try { + URL url = new URL(filename); + URLConnection conn = url.openConnection(); + int length = -1; + + if (conn instanceof HttpURLConnection) { + HttpURLConnection httpConn = (HttpURLConnection) conn; + // Will not handle a protocol change (see below) + httpConn.setInstanceFollowRedirects(true); + int response = httpConn.getResponseCode(); + // Default won't follow HTTP -> HTTPS redirects for security reasons + // http://stackoverflow.com/a/1884427 + if (response >= 300 && response < 400) { + String newLocation = httpConn.getHeaderField("Location"); + return loadBytes(newLocation); + } + length = conn.getContentLength(); + input = conn.getInputStream(); + } else if (conn instanceof JarURLConnection) { + length = conn.getContentLength(); + input = url.openStream(); + } + + if (input != null) { + byte[] buffer = null; + if (length != -1) { + buffer = new byte[length]; + int count; + int offset = 0; + while ((count = input.read(buffer, offset, length - offset)) > 0) { + offset += count; + } + } else { + buffer = loadBytes(input); + } + input.close(); + return buffer; + } + } catch (MalformedURLException mfue) { + // not a url, that's fine + + } catch (FileNotFoundException fnfe) { + // Java 1.5+ throws FNFE when URL not available + // http://dev.processing.org/bugs/show_bug.cgi?id=403 + + } catch (IOException e) { + printStackTrace(e); + return null; + + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + // just deal + } + } + } + } + } + InputStream is = createInput(filename); if (is != null) { byte[] outgoing = loadBytes(is); @@ -6971,46 +7419,93 @@ public byte[] loadBytes(String filename) { return null; } + /** * @nowebref */ static public byte[] loadBytes(InputStream input) { try { - BufferedInputStream bis = new BufferedInputStream(input); ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; - int c = bis.read(); - while (c != -1) { - out.write(c); - c = bis.read(); + int bytesRead = input.read(buffer); + while (bytesRead != -1) { + out.write(buffer, 0, bytesRead); + bytesRead = input.read(buffer); } + out.flush(); return out.toByteArray(); } catch (IOException e) { e.printStackTrace(); - //throw new RuntimeException("Couldn't load bytes from stream"); } return null; } + /** * @nowebref */ static public byte[] loadBytes(File file) { - InputStream is = createInput(file); - byte[] byteArr = loadBytes(is); + if (!file.exists()) { + System.err.println(file + " does not exist, loadBytes() will return null"); + return null; + } + try { - is.close(); + InputStream input; + int length; + + if (file.getName().toLowerCase().endsWith(".gz")) { + RandomAccessFile raf = new RandomAccessFile(file, "r"); + raf.seek(raf.length() - 4); + int b4 = raf.read(); + int b3 = raf.read(); + int b2 = raf.read(); + int b1 = raf.read(); + length = (b1 << 24) | (b2 << 16) + (b3 << 8) + b4; + raf.close(); + + // buffered has to go *around* the GZ, otherwise 25x slower + input = new BufferedInputStream(new GZIPInputStream(new FileInputStream(file))); + + } else { + long len = file.length(); + // http://stackoverflow.com/a/3039805 + int maxArraySize = Integer.MAX_VALUE - 5; + if (len > maxArraySize) { + System.err.println("Cannot use loadBytes() on a file larger than " + maxArraySize); + return null; + } + length = (int) len; + input = new BufferedInputStream(new FileInputStream(file)); + } + byte[] buffer = new byte[length]; + int count; + int offset = 0; + // count will come back 0 when complete (or -1 if somehow going long?) + while ((count = input.read(buffer, offset, length - offset)) > 0) { + offset += count; + } + input.close(); + return buffer; + } catch (IOException e) { e.printStackTrace(); + return null; } - return byteArr; } + /** * @nowebref */ static public String[] loadStrings(File file) { + if (!file.exists()) { + System.err.println(file + " does not exist, loadStrings() will return null"); + return null; + } + InputStream is = createInput(file); if (is != null) { String[] outgoing = loadStrings(is); @@ -7024,6 +7519,7 @@ static public String[] loadStrings(File file) { return null; } + /** * ( begin auto-generated from loadStrings.xml ) * @@ -7104,12 +7600,12 @@ static public String[] loadStrings(InputStream input) { static public String[] loadStrings(BufferedReader reader) { try { - String lines[] = new String[100]; + String[] lines = new String[100]; int lineCount = 0; String line = null; while ((line = reader.readLine()) != null) { if (lineCount == lines.length) { - String temp[] = new String[lineCount << 1]; + String[] temp = new String[lineCount << 1]; System.arraycopy(lines, 0, temp, 0, lineCount); lines = temp; } @@ -7122,7 +7618,7 @@ static public String[] loadStrings(BufferedReader reader) { } // resize array to appropriate amount for these lines - String output[] = new String[lineCount]; + String[] output = new String[lineCount]; System.arraycopy(lines, 0, output, 0, lineCount); return output; @@ -7175,11 +7671,11 @@ public OutputStream createOutput(String filename) { static public OutputStream createOutput(File file) { try { createPath(file); // make sure the path exists - FileOutputStream fos = new FileOutputStream(file); + OutputStream output = new FileOutputStream(file); if (file.getName().toLowerCase().endsWith(".gz")) { - return new GZIPOutputStream(fos); + return new BufferedOutputStream(new GZIPOutputStream(output)); } - return fos; + return new BufferedOutputStream(output); } catch (IOException e) { e.printStackTrace(); @@ -7235,10 +7731,9 @@ public boolean saveStream(String target, InputStream source) { static public boolean saveStream(File target, InputStream source) { File tempFile = null; try { - File parentDir = target.getParentFile(); // make sure that this path actually exists before writing createPath(target); - tempFile = File.createTempFile(target.getName(), null, parentDir); + tempFile = createTempFile(target); FileOutputStream targetStream = new FileOutputStream(tempFile); saveStream(targetStream, source); @@ -7314,6 +7809,37 @@ public void saveBytes(String filename, byte[] data) { } + /** + * Creates a temporary file based on the name/extension of another file + * and in the same parent directory. Ensures that the same extension is used + * (i.e. so that .gz files are gzip compressed on output) and that it's done + * from the same directory so that renaming the file later won't cross file + * system boundaries. + */ + static private File createTempFile(File file) throws IOException { + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + String name = file.getName(); + String prefix; + String suffix = null; + int dot = name.lastIndexOf('.'); + if (dot == -1) { + prefix = name; + } else { + // preserve the extension so that .gz works properly + prefix = name.substring(0, dot); + suffix = name.substring(dot); + } + // Prefix must be three characters + if (prefix.length() < 3) { + prefix += "processing"; + } + return File.createTempFile(prefix, suffix, parentDir); + } + + /** * @nowebref * Saves bytes to a specific File location specified by the user. @@ -7321,8 +7847,7 @@ public void saveBytes(String filename, byte[] data) { static public void saveBytes(File file, byte[] data) { File tempFile = null; try { - File parentDir = file.getParentFile(); - tempFile = File.createTempFile(file.getName(), null, parentDir); + tempFile = createTempFile(file); OutputStream output = createOutput(tempFile); saveBytes(output, data); @@ -7394,7 +7919,7 @@ static public void saveBytes(OutputStream output, byte[] data) { * @see PApplet#loadBytes(String) * @see PApplet#saveBytes(String, byte[]) */ - public void saveStrings(String filename, String data[]) { + public void saveStrings(String filename, String[] data) { saveStrings(saveFile(filename), data); } @@ -7402,7 +7927,7 @@ public void saveStrings(String filename, String data[]) { /** * @nowebref */ - static public void saveStrings(File file, String data[]) { + static public void saveStrings(File file, String[] data) { saveStrings(createOutput(file), data); } @@ -7716,7 +8241,7 @@ static public String urlDecode(String str) { * @param list array to sort * @see PApplet#reverse(boolean[]) */ - static public byte[] sort(byte list[]) { + static public byte[] sort(byte[] list) { return sort(list, list.length); } @@ -7730,7 +8255,7 @@ static public byte[] sort(byte[] list, int count) { return outgoing; } - static public char[] sort(char list[]) { + static public char[] sort(char[] list) { return sort(list, list.length); } @@ -7741,7 +8266,7 @@ static public char[] sort(char[] list, int count) { return outgoing; } - static public int[] sort(int list[]) { + static public int[] sort(int[] list) { return sort(list, list.length); } @@ -7752,7 +8277,7 @@ static public int[] sort(int[] list, int count) { return outgoing; } - static public float[] sort(float list[]) { + static public float[] sort(float[] list) { return sort(list, list.length); } @@ -7763,7 +8288,7 @@ static public float[] sort(float[] list, int count) { return outgoing; } - static public String[] sort(String list[]) { + static public String[] sort(String[] list) { return sort(list, list.length); } @@ -7826,10 +8351,10 @@ static public void arrayCopy(Object src, Object dst) { System.arraycopy(src, 0, dst, 0, Array.getLength(src)); } - // /** - * @deprecated Use arrayCopy() instead. + * Use arrayCopy() instead. */ + @Deprecated static public void arraycopy(Object src, int srcPosition, Object dst, int dstPosition, int length) { @@ -7837,19 +8362,22 @@ static public void arraycopy(Object src, int srcPosition, } /** - * @deprecated Use arrayCopy() instead. + * Use arrayCopy() instead. */ + @Deprecated static public void arraycopy(Object src, Object dst, int length) { System.arraycopy(src, 0, dst, 0, length); } /** - * @deprecated Use arrayCopy() instead. + * Use arrayCopy() instead. */ + @Deprecated static public void arraycopy(Object src, Object dst) { System.arraycopy(src, 0, dst, 0, Array.getLength(src)); } + /** * ( begin auto-generated from expand.xml ) * @@ -7867,85 +8395,85 @@ static public void arraycopy(Object src, Object dst) { * @param list the array to expand * @see PApplet#shorten(boolean[]) */ - static public boolean[] expand(boolean list[]) { + static public boolean[] expand(boolean[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } /** * @param newSize new size for the array */ - static public boolean[] expand(boolean list[], int newSize) { - boolean temp[] = new boolean[newSize]; + static public boolean[] expand(boolean[] list, int newSize) { + boolean[] temp = new boolean[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public byte[] expand(byte list[]) { + static public byte[] expand(byte[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public byte[] expand(byte list[], int newSize) { - byte temp[] = new byte[newSize]; + static public byte[] expand(byte[] list, int newSize) { + byte[] temp = new byte[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public char[] expand(char list[]) { + static public char[] expand(char[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public char[] expand(char list[], int newSize) { - char temp[] = new char[newSize]; + static public char[] expand(char[] list, int newSize) { + char[] temp = new char[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public int[] expand(int list[]) { + static public int[] expand(int[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public int[] expand(int list[], int newSize) { - int temp[] = new int[newSize]; + static public int[] expand(int[] list, int newSize) { + int[] temp = new int[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public long[] expand(long list[]) { + static public long[] expand(long[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public long[] expand(long list[], int newSize) { - long temp[] = new long[newSize]; + static public long[] expand(long[] list, int newSize) { + long[] temp = new long[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public float[] expand(float list[]) { + static public float[] expand(float[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public float[] expand(float list[], int newSize) { - float temp[] = new float[newSize]; + static public float[] expand(float[] list, int newSize) { + float[] temp = new float[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public double[] expand(double list[]) { + static public double[] expand(double[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public double[] expand(double list[], int newSize) { - double temp[] = new double[newSize]; + static public double[] expand(double[] list, int newSize) { + double[] temp = new double[newSize]; System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; } - static public String[] expand(String list[]) { + static public String[] expand(String[] list) { return expand(list, list.length > 0 ? list.length << 1 : 1); } - static public String[] expand(String list[], int newSize) { - String temp[] = new String[newSize]; + static public String[] expand(String[] list, int newSize) { + String[] temp = new String[newSize]; // in case the new size is smaller than list.length System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length)); return temp; @@ -7989,31 +8517,31 @@ static public Object expand(Object list, int newSize) { * @see PApplet#shorten(boolean[]) * @see PApplet#expand(boolean[]) */ - static public byte[] append(byte array[], byte value) { + static public byte[] append(byte[] array, byte value) { array = expand(array, array.length + 1); array[array.length-1] = value; return array; } - static public char[] append(char array[], char value) { + static public char[] append(char[] array, char value) { array = expand(array, array.length + 1); array[array.length-1] = value; return array; } - static public int[] append(int array[], int value) { + static public int[] append(int[] array, int value) { array = expand(array, array.length + 1); array[array.length-1] = value; return array; } - static public float[] append(float array[], float value) { + static public float[] append(float[] array, float value) { array = expand(array, array.length + 1); array[array.length-1] = value; return array; } - static public String[] append(String array[], String value) { + static public String[] append(String[] array, String value) { array = expand(array, array.length + 1); array[array.length-1] = value; return array; @@ -8043,27 +8571,27 @@ static public Object append(Object array, Object value) { * @see PApplet#append(byte[], byte) * @see PApplet#expand(boolean[]) */ - static public boolean[] shorten(boolean list[]) { + static public boolean[] shorten(boolean[] list) { return subset(list, 0, list.length-1); } - static public byte[] shorten(byte list[]) { + static public byte[] shorten(byte[] list) { return subset(list, 0, list.length-1); } - static public char[] shorten(char list[]) { + static public char[] shorten(char[] list) { return subset(list, 0, list.length-1); } - static public int[] shorten(int list[]) { + static public int[] shorten(int[] list) { return subset(list, 0, list.length-1); } - static public float[] shorten(float list[]) { + static public float[] shorten(float[] list) { return subset(list, 0, list.length-1); } - static public String[] shorten(String list[]) { + static public String[] shorten(String[] list) { return subset(list, 0, list.length-1); } @@ -8093,9 +8621,9 @@ static public Object shorten(Object list) { * @see PApplet#concat(boolean[], boolean[]) * @see PApplet#subset(boolean[], int, int) */ - static final public boolean[] splice(boolean list[], + static final public boolean[] splice(boolean[] list, boolean value, int index) { - boolean outgoing[] = new boolean[list.length + 1]; + boolean[] outgoing = new boolean[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8103,9 +8631,9 @@ static final public boolean[] splice(boolean list[], return outgoing; } - static final public boolean[] splice(boolean list[], - boolean value[], int index) { - boolean outgoing[] = new boolean[list.length + value.length]; + static final public boolean[] splice(boolean[] list, + boolean[] value, int index) { + boolean[] outgoing = new boolean[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8113,9 +8641,9 @@ static final public boolean[] splice(boolean list[], return outgoing; } - static final public byte[] splice(byte list[], + static final public byte[] splice(byte[] list, byte value, int index) { - byte outgoing[] = new byte[list.length + 1]; + byte[] outgoing = new byte[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8123,9 +8651,9 @@ static final public byte[] splice(byte list[], return outgoing; } - static final public byte[] splice(byte list[], - byte value[], int index) { - byte outgoing[] = new byte[list.length + value.length]; + static final public byte[] splice(byte[] list, + byte[] value, int index) { + byte[] outgoing = new byte[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8134,9 +8662,9 @@ static final public byte[] splice(byte list[], } - static final public char[] splice(char list[], + static final public char[] splice(char[] list, char value, int index) { - char outgoing[] = new char[list.length + 1]; + char[] outgoing = new char[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8144,9 +8672,9 @@ static final public char[] splice(char list[], return outgoing; } - static final public char[] splice(char list[], - char value[], int index) { - char outgoing[] = new char[list.length + value.length]; + static final public char[] splice(char[] list, + char[] value, int index) { + char[] outgoing = new char[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8154,9 +8682,9 @@ static final public char[] splice(char list[], return outgoing; } - static final public int[] splice(int list[], + static final public int[] splice(int[] list, int value, int index) { - int outgoing[] = new int[list.length + 1]; + int[] outgoing = new int[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8164,9 +8692,9 @@ static final public int[] splice(int list[], return outgoing; } - static final public int[] splice(int list[], - int value[], int index) { - int outgoing[] = new int[list.length + value.length]; + static final public int[] splice(int[] list, + int[] value, int index) { + int[] outgoing = new int[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8174,9 +8702,9 @@ static final public int[] splice(int list[], return outgoing; } - static final public float[] splice(float list[], + static final public float[] splice(float[] list, float value, int index) { - float outgoing[] = new float[list.length + 1]; + float[] outgoing = new float[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8184,9 +8712,9 @@ static final public float[] splice(float list[], return outgoing; } - static final public float[] splice(float list[], - float value[], int index) { - float outgoing[] = new float[list.length + value.length]; + static final public float[] splice(float[] list, + float[] value, int index) { + float[] outgoing = new float[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8194,9 +8722,9 @@ static final public float[] splice(float list[], return outgoing; } - static final public String[] splice(String list[], + static final public String[] splice(String[] list, String value, int index) { - String outgoing[] = new String[list.length + 1]; + String[] outgoing = new String[list.length + 1]; System.arraycopy(list, 0, outgoing, 0, index); outgoing[index] = value; System.arraycopy(list, index, outgoing, index + 1, @@ -8204,9 +8732,9 @@ static final public String[] splice(String list[], return outgoing; } - static final public String[] splice(String list[], - String value[], int index) { - String outgoing[] = new String[list.length + value.length]; + static final public String[] splice(String[] list, + String[] value, int index) { + String[] outgoing = new String[list.length + value.length]; System.arraycopy(list, 0, outgoing, 0, index); System.arraycopy(value, 0, outgoing, index, value.length); System.arraycopy(list, index, outgoing, index + value.length, @@ -8236,10 +8764,12 @@ static final public Object splice(Object list, Object value, int index) { return outgoing; } - static public boolean[] subset(boolean list[], int start) { + + static public boolean[] subset(boolean[] list, int start) { return subset(list, start, list.length - start); } + /** * ( begin auto-generated from subset.xml ) * @@ -8262,60 +8792,92 @@ static public boolean[] subset(boolean list[], int start) { * @param count number of values to extract * @see PApplet#splice(boolean[], boolean, int) */ - static public boolean[] subset(boolean list[], int start, int count) { - boolean output[] = new boolean[count]; + static public boolean[] subset(boolean[] list, int start, int count) { + boolean[] output = new boolean[count]; + System.arraycopy(list, start, output, 0, count); + return output; + } + + + static public byte[] subset(byte[] list, int start) { + return subset(list, start, list.length - start); + } + + + static public byte[] subset(byte[] list, int start, int count) { + byte[] output = new byte[count]; + System.arraycopy(list, start, output, 0, count); + return output; + } + + + static public char[] subset(char[] list, int start) { + return subset(list, start, list.length - start); + } + + + static public char[] subset(char[] list, int start, int count) { + char[] output = new char[count]; System.arraycopy(list, start, output, 0, count); return output; } - static public byte[] subset(byte list[], int start) { + + static public int[] subset(int[] list, int start) { return subset(list, start, list.length - start); } - static public byte[] subset(byte list[], int start, int count) { - byte output[] = new byte[count]; + + static public int[] subset(int[] list, int start, int count) { + int[] output = new int[count]; System.arraycopy(list, start, output, 0, count); return output; } - static public char[] subset(char list[], int start) { + static public long[] subset(long[] list, int start) { return subset(list, start, list.length - start); } - static public char[] subset(char list[], int start, int count) { - char output[] = new char[count]; + + static public long[] subset(long[] list, int start, int count) { + long[] output = new long[count]; System.arraycopy(list, start, output, 0, count); return output; } - static public int[] subset(int list[], int start) { + + static public float[] subset(float[] list, int start) { return subset(list, start, list.length - start); } - static public int[] subset(int list[], int start, int count) { - int output[] = new int[count]; + + static public float[] subset(float[] list, int start, int count) { + float[] output = new float[count]; System.arraycopy(list, start, output, 0, count); return output; } - static public float[] subset(float list[], int start) { + + static public double[] subset(double[] list, int start) { return subset(list, start, list.length - start); } - static public float[] subset(float list[], int start, int count) { - float output[] = new float[count]; + + static public double[] subset(double[] list, int start, int count) { + double[] output = new double[count]; System.arraycopy(list, start, output, 0, count); return output; } - static public String[] subset(String list[], int start) { + static public String[] subset(String[] list, int start) { return subset(list, start, list.length - start); } - static public String[] subset(String list[], int start, int count) { - String output[] = new String[count]; + + static public String[] subset(String[] list, int start, int count) { + String[] output = new String[count]; System.arraycopy(list, start, output, 0, count); return output; } @@ -8326,6 +8888,7 @@ static public Object subset(Object list, int start) { return subset(list, start, length - start); } + static public Object subset(Object list, int start, int count) { Class type = list.getClass().getComponentType(); Object outgoing = Array.newInstance(type, count); @@ -8352,43 +8915,43 @@ static public Object subset(Object list, int start, int count) { * @see PApplet#splice(boolean[], boolean, int) * @see PApplet#arrayCopy(Object, int, Object, int, int) */ - static public boolean[] concat(boolean a[], boolean b[]) { - boolean c[] = new boolean[a.length + b.length]; + static public boolean[] concat(boolean[] a, boolean[] b) { + boolean[] c = new boolean[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } - static public byte[] concat(byte a[], byte b[]) { - byte c[] = new byte[a.length + b.length]; + static public byte[] concat(byte[] a, byte[] b) { + byte[] c = new byte[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } - static public char[] concat(char a[], char b[]) { - char c[] = new char[a.length + b.length]; + static public char[] concat(char[] a, char[] b) { + char[] c = new char[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } - static public int[] concat(int a[], int b[]) { - int c[] = new int[a.length + b.length]; + static public int[] concat(int[] a, int[] b) { + int[] c = new int[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } - static public float[] concat(float a[], float b[]) { - float c[] = new float[a.length + b.length]; + static public float[] concat(float[] a, float[] b) { + float[] c = new float[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } - static public String[] concat(String a[], String b[]) { - String c[] = new String[a.length + b.length]; + static public String[] concat(String[] a, String[] b) { + String[] c = new String[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; @@ -8417,8 +8980,8 @@ static public Object concat(Object a, Object b) { * @param list booleans[], bytes[], chars[], ints[], floats[], or Strings[] * @see PApplet#sort(String[], int) */ - static public boolean[] reverse(boolean list[]) { - boolean outgoing[] = new boolean[list.length]; + static public boolean[] reverse(boolean[] list) { + boolean[] outgoing = new boolean[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8426,8 +8989,8 @@ static public boolean[] reverse(boolean list[]) { return outgoing; } - static public byte[] reverse(byte list[]) { - byte outgoing[] = new byte[list.length]; + static public byte[] reverse(byte[] list) { + byte[] outgoing = new byte[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8435,8 +8998,8 @@ static public byte[] reverse(byte list[]) { return outgoing; } - static public char[] reverse(char list[]) { - char outgoing[] = new char[list.length]; + static public char[] reverse(char[] list) { + char[] outgoing = new char[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8444,8 +9007,8 @@ static public char[] reverse(char list[]) { return outgoing; } - static public int[] reverse(int list[]) { - int outgoing[] = new int[list.length]; + static public int[] reverse(int[] list) { + int[] outgoing = new int[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8453,8 +9016,8 @@ static public int[] reverse(int list[]) { return outgoing; } - static public float[] reverse(float list[]) { - float outgoing[] = new float[list.length]; + static public float[] reverse(float[] list) { + float[] outgoing = new float[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8462,8 +9025,8 @@ static public float[] reverse(float list[]) { return outgoing; } - static public String[] reverse(String list[]) { - String outgoing[] = new String[list.length]; + static public String[] reverse(String[] list) { + String[] outgoing = new String[list.length]; int length1 = list.length - 1; for (int i = 0; i < list.length; i++) { outgoing[i] = list[length1 - i]; @@ -8502,6 +9065,9 @@ static public Object reverse(Object list) { * @see PApplet#join(String[], char) */ static public String trim(String str) { + if (str == null) { + return null; + } return str.replace('\u00A0', ' ').trim(); } @@ -8510,10 +9076,13 @@ static public String trim(String str) { * @param array a String array */ static public String[] trim(String[] array) { + if (array == null) { + return null; + } String[] outgoing = new String[array.length]; for (int i = 0; i < array.length; i++) { if (array[i] != null) { - outgoing[i] = array[i].replace('\u00A0', ' ').trim(); + outgoing[i] = trim(array[i]); } } return outgoing; @@ -8580,7 +9149,7 @@ static public String[] splitTokens(String value) { */ static public String[] splitTokens(String value, String delim) { StringTokenizer toker = new StringTokenizer(value, delim); - String pieces[] = new String[toker.countTokens()]; + String[] pieces = new String[toker.countTokens()]; int index = 0; while (toker.hasMoreTokens()) { @@ -8630,7 +9199,7 @@ static public String[] split(String value, char delim) { if (value == null) return null; //return split(what, String.valueOf(delim)); // huh - char chars[] = value.toCharArray(); + char[] chars = value.toCharArray(); int splitCount = 0; //1; for (int i = 0; i < chars.length; i++) { if (chars[i] == delim) splitCount++; @@ -8642,12 +9211,12 @@ static public String[] split(String value, char delim) { // on second thought, i don't agree with this, will disable //} if (splitCount == 0) { - String splits[] = new String[1]; + String[] splits = new String[1]; splits[0] = value; return splits; } //int pieceCount = splitCount + 1; - String splits[] = new String[splitCount + 1]; + String[] splits = new String[splitCount + 1]; int splitIndex = 0; int startIndex = 0; for (int i = 0; i < chars.length; i++) { @@ -8666,7 +9235,7 @@ static public String[] split(String value, char delim) { static public String[] split(String value, String delim) { - ArrayList items = new ArrayList(); + List items = new ArrayList<>(); int index; int offset = 0; while ((index = value.indexOf(delim, offset)) != -1) { @@ -8791,7 +9360,7 @@ static public String[] match(String str, String regexp) { static public String[][] matchAll(String str, String regexp) { Pattern p = matchPattern(regexp); Matcher m = p.matcher(str); - ArrayList results = new ArrayList(); + List results = new ArrayList<>(); int count = m.groupCount() + 1; while (m.find()) { String[] groups = new String[count]; @@ -8888,8 +9457,8 @@ static final public boolean[] parseBoolean(byte what[]) { * to zero will return false, and any other value will return true. * @return array of boolean elements */ - static final public boolean[] parseBoolean(int what[]) { - boolean outgoing[] = new boolean[what.length]; + static final public boolean[] parseBoolean(int[] what) { + boolean[] outgoing = new boolean[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (what[i] != 0); } @@ -8907,8 +9476,8 @@ static final public boolean[] parseBoolean(float what[]) { } */ - static final public boolean[] parseBoolean(String what[]) { - boolean outgoing[] = new boolean[what.length]; + static final public boolean[] parseBoolean(String[] what) { + boolean[] outgoing = new boolean[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = Boolean.parseBoolean(what[i]); } @@ -8942,32 +9511,32 @@ static final public byte[] parseByte(String what) { // note: array[] // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - static final public byte[] parseByte(boolean what[]) { - byte outgoing[] = new byte[what.length]; + static final public byte[] parseByte(boolean[] what) { + byte[] outgoing = new byte[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = what[i] ? (byte)1 : 0; } return outgoing; } - static final public byte[] parseByte(char what[]) { - byte outgoing[] = new byte[what.length]; + static final public byte[] parseByte(char[] what) { + byte[] outgoing = new byte[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (byte) what[i]; } return outgoing; } - static final public byte[] parseByte(int what[]) { - byte outgoing[] = new byte[what.length]; + static final public byte[] parseByte(int[] what) { + byte[] outgoing = new byte[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (byte) what[i]; } return outgoing; } - static final public byte[] parseByte(float what[]) { - byte outgoing[] = new byte[what.length]; + static final public byte[] parseByte(float[] what) { + byte[] outgoing = new byte[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (byte) what[i]; } @@ -9022,8 +9591,8 @@ static final public char[] parseChar(boolean what[]) { // 0/1 or T/F ? } */ - static final public char[] parseChar(byte what[]) { - char outgoing[] = new char[what.length]; + static final public char[] parseChar(byte[] what) { + char[] outgoing = new char[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (char) (what[i] & 0xff); } @@ -9039,8 +9608,8 @@ static final public char[] parseChar(int what[]) { } /* - static final public char[] parseChar(float what[]) { // nonsensical - char outgoing[] = new char[what.length]; + static final public char[] parseChar(int[] what) { + char[] outgoing = new char[what.length]; for (int i = 0; i < what.length; i++) { outgoing[i] = (char) what[i]; } @@ -9110,32 +9679,32 @@ static final public int parseInt(String what, int otherwise) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - static final public int[] parseInt(boolean what[]) { - int list[] = new int[what.length]; + static final public int[] parseInt(boolean[] what) { + int[] list = new int[what.length]; for (int i = 0; i < what.length; i++) { list[i] = what[i] ? 1 : 0; } return list; } - static final public int[] parseInt(byte what[]) { // note this unsigns - int list[] = new int[what.length]; + static final public int[] parseInt(byte[] what) { // note this unsigns + int[] list = new int[what.length]; for (int i = 0; i < what.length; i++) { list[i] = (what[i] & 0xff); } return list; } - static final public int[] parseInt(char what[]) { - int list[] = new int[what.length]; + static final public int[] parseInt(char[] what) { + int[] list = new int[what.length]; for (int i = 0; i < what.length; i++) { list[i] = what[i]; } return list; } - static public int[] parseInt(float what[]) { - int inties[] = new int[what.length]; + static public int[] parseInt(float[] what) { + int[] inties = new int[what.length]; for (int i = 0; i < what.length; i++) { inties[i] = (int)what[i]; } @@ -9151,7 +9720,7 @@ static public int[] parseInt(float what[]) { * * numbers will contain { 1, 300, 44 } */ - static public int[] parseInt(String what[]) { + static public int[] parseInt(String[] what) { return parseInt(what, 0); } @@ -9165,8 +9734,8 @@ static public int[] parseInt(String what[]) { * * numbers will contain { 1, 300, 9999, 44 } */ - static public int[] parseInt(String what[], int missing) { - int output[] = new int[what.length]; + static public int[] parseInt(String[] what, int missing) { + int[] output = new int[what.length]; for (int i = 0; i < what.length; i++) { try { output[i] = Integer.parseInt(what[i]); @@ -9199,7 +9768,7 @@ static final public float parseFloat(String what) { static final public float parseFloat(String what, float otherwise) { try { - return new Float(what).floatValue(); + return Float.parseFloat(what); } catch (NumberFormatException e) { } return otherwise; @@ -9207,49 +9776,31 @@ static final public float parseFloat(String what, float otherwise) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - /* - static final public float[] parseFloat(boolean what[]) { - float floaties[] = new float[what.length]; - for (int i = 0; i < what.length; i++) { - floaties[i] = what[i] ? 1 : 0; - } - return floaties; - } - - static final public float[] parseFloat(char what[]) { - float floaties[] = new float[what.length]; - for (int i = 0; i < what.length; i++) { - floaties[i] = (char) what[i]; - } - return floaties; - } - */ - - static final public float[] parseFloat(byte what[]) { - float floaties[] = new float[what.length]; + static final public float[] parseFloat(byte[] what) { + float[] floaties = new float[what.length]; for (int i = 0; i < what.length; i++) { floaties[i] = what[i]; } return floaties; } - static final public float[] parseFloat(int what[]) { - float floaties[] = new float[what.length]; + static final public float[] parseFloat(int[] what) { + float[] floaties = new float[what.length]; for (int i = 0; i < what.length; i++) { floaties[i] = what[i]; } return floaties; } - static final public float[] parseFloat(String what[]) { + static final public float[] parseFloat(String[] what) { return parseFloat(what, Float.NaN); } - static final public float[] parseFloat(String what[], float missing) { - float output[] = new float[what.length]; + static final public float[] parseFloat(String[] what, float missing) { + float[] output = new float[what.length]; for (int i = 0; i < what.length; i++) { try { - output[i] = new Float(what[i]).floatValue(); + output[i] = Float.parseFloat(what[i]); } catch (NumberFormatException e) { output[i] = missing; } @@ -9281,32 +9832,32 @@ static final public String str(float x) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - static final public String[] str(boolean x[]) { - String s[] = new String[x.length]; + static final public String[] str(boolean[] x) { + String[] s = new String[x.length]; for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]); return s; } - static final public String[] str(byte x[]) { - String s[] = new String[x.length]; + static final public String[] str(byte[] x) { + String[] s = new String[x.length]; for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]); return s; } - static final public String[] str(char x[]) { - String s[] = new String[x.length]; + static final public String[] str(char[] x) { + String[] s = new String[x.length]; for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]); return s; } - static final public String[] str(int x[]) { - String s[] = new String[x.length]; + static final public String[] str(int[] x) { + String[] s = new String[x.length]; for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]); return s; } - static final public String[] str(float x[]) { - String s[] = new String[x.length]; + static final public String[] str(float[] x) { + String[] s = new String[x.length]; for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]); return s; } @@ -9316,7 +9867,6 @@ static final public String[] str(float x[]) { // INT NUMBER FORMATTING - static public String nf(float num) { int inum = (int) num; if (num == inum) { @@ -9325,31 +9875,22 @@ static public String nf(float num) { return str(num); } - - static public String[] nf(float[] num) { - String[] outgoing = new String[num.length]; - for (int i = 0; i < num.length; i++) { - outgoing[i] = nf(num[i]); + static public String[] nf(float[] nums) { + String[] outgoing = new String[nums.length]; + for (int i = 0; i < nums.length; i++) { + outgoing[i] = nf(nums[i]); } return outgoing; } - /** * Integer number formatter. */ + static private NumberFormat int_nf; static private int int_nf_digits; static private boolean int_nf_commas; - static public String[] nf(int num[], int digits) { - String formatted[] = new String[num.length]; - for (int i = 0; i < formatted.length; i++) { - formatted[i] = nf(num[i], digits); - } - return formatted; - } - /** * ( begin auto-generated from nf.xml ) * @@ -9365,13 +9906,25 @@ static public String[] nf(int num[], int digits) { * * ( end auto-generated ) * @webref data:string_functions - * @param num the number(s) to format + * @param nums the numbers to format * @param digits number of digits to pad with zero * @see PApplet#nfs(float, int, int) * @see PApplet#nfp(float, int, int) * @see PApplet#nfc(float, int) * @see int(float) */ + + static public String[] nf(int[] nums, int digits) { + String[] formatted = new String[nums.length]; + for (int i = 0; i < formatted.length; i++) { + formatted[i] = nf(nums[i], digits); + } + return formatted; + } + + /** + * @param num the number to format + */ static public String nf(int num, int digits) { if ((int_nf != null) && (int_nf_digits == digits) && @@ -9387,38 +9940,35 @@ static public String nf(int num, int digits) { return int_nf.format(num); } -/** + /** * ( begin auto-generated from nfc.xml ) * * Utility function for formatting numbers into strings and placing * appropriate commas to mark units of 1000. There are two versions, one * for formatting ints and one for formatting an array of ints. The value * for the digits parameter should always be a positive integer. - *

+ *

* For a non-US locale, this will insert periods instead of commas, or * whatever is apprioriate for that region. * * ( end auto-generated ) - * @webref data:string_functions - * @param num the number(s) to format - * @see PApplet#nf(float, int, int) - * @see PApplet#nfp(float, int, int) - * @see PApplet#nfs(float, int, int) - */ - static public String[] nfc(int num[]) { - String formatted[] = new String[num.length]; + * @webref data:string_functions + * @param nums the numbers to format + * @see PApplet#nf(float, int, int) + * @see PApplet#nfp(float, int, int) + * @see PApplet#nfs(float, int, int) + */ + static public String[] nfc(int[] nums) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfc(num[i]); + formatted[i] = nfc(nums[i]); } return formatted; } /** - * nfc() or "number format with commas". This is an unfortunate misnomer - * because in locales where a comma is not the separator for numbers, it - * won't actually be outputting a comma, it'll use whatever makes sense for - * the locale. + * @param num the number to format */ static public String nfc(int num) { if ((int_nf != null) && @@ -9455,7 +10005,7 @@ static public String nfc(int num) { * * ( end auto-generated ) * @webref data:string_functions - * @param num the number(s) to format + * @param num the number to format * @param digits number of digits to pad with zeroes * @see PApplet#nf(float, int, int) * @see PApplet#nfp(float, int, int) @@ -9465,10 +10015,13 @@ static public String nfs(int num, int digits) { return (num < 0) ? nf(num, digits) : (' ' + nf(num, digits)); } - static public String[] nfs(int num[], int digits) { - String formatted[] = new String[num.length]; + /** + * @param nums the numbers to format + */ + static public String[] nfs(int[] nums, int digits) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfs(num[i], digits); + formatted[i] = nfs(nums[i], digits); } return formatted; } @@ -9491,7 +10044,7 @@ static public String[] nfs(int num[], int digits) { * * ( end auto-generated ) * @webref data:string_functions - * @param num the number(s) to format + * @param num the number to format * @param digits number of digits to pad with zeroes * @see PApplet#nf(float, int, int) * @see PApplet#nfs(float, int, int) @@ -9500,11 +10053,13 @@ static public String[] nfs(int num[], int digits) { static public String nfp(int num, int digits) { return (num < 0) ? nf(num, digits) : ('+' + nf(num, digits)); } - - static public String[] nfp(int num[], int digits) { - String formatted[] = new String[num.length]; + /** + * @param nums the numbers to format + */ + static public String[] nfp(int[] nums, int digits) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfp(num[i], digits); + formatted[i] = nfp(nums[i], digits); } return formatted; } @@ -9515,23 +10070,22 @@ static public String[] nfp(int num[], int digits) { // FLOAT NUMBER FORMATTING - static private NumberFormat float_nf; static private int float_nf_left, float_nf_right; static private boolean float_nf_commas; - static public String[] nf(float num[], int left, int right) { - String formatted[] = new String[num.length]; + /** + * @param left number of digits to the left of the decimal point + * @param right number of digits to the right of the decimal point + */ + static public String[] nf(float[] nums, int left, int right) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nf(num[i], left, right); + formatted[i] = nf(nums[i], left, right); } return formatted; } -/** - * @param num[] the number(s) to format - * @param left number of digits to the left of the decimal point - * @param right number of digits to the right of the decimal point - */ + static public String nf(float num, int left, int right) { if ((float_nf != null) && (float_nf_left == left) && @@ -9554,19 +10108,17 @@ static public String nf(float num, int left, int right) { return float_nf.format(num); } -/** - * @param num[] the number(s) to format - * @param right number of digits to the right of the decimal point - */ - static public String[] nfc(float num[], int right) { - String formatted[] = new String[num.length]; + /** + * @param right number of digits to the right of the decimal point + */ + static public String[] nfc(float[] nums, int right) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfc(num[i], right); + formatted[i] = nfc(nums[i], right); } return formatted; } - static public String nfc(float num, int right) { if ((float_nf != null) && (float_nf_left == 0) && @@ -9590,14 +10142,13 @@ static public String nfc(float num, int right) { /** - * @param num[] the number(s) to format * @param left the number of digits to the left of the decimal point * @param right the number of digits to the right of the decimal point */ - static public String[] nfs(float num[], int left, int right) { - String formatted[] = new String[num.length]; + static public String[] nfs(float[] nums, int left, int right) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfs(num[i], left, right); + formatted[i] = nfs(nums[i], left, right); } return formatted; } @@ -9610,10 +10161,10 @@ static public String nfs(float num, int left, int right) { * @param left the number of digits to the left of the decimal point * @param right the number of digits to the right of the decimal point */ - static public String[] nfp(float num[], int left, int right) { - String formatted[] = new String[num.length]; + static public String[] nfp(float[] nums, int left, int right) { + String[] formatted = new String[nums.length]; for (int i = 0; i < formatted.length; i++) { - formatted[i] = nfp(num[i], left, right); + formatted[i] = nfp(nums[i], left, right); } return formatted; } @@ -10116,6 +10667,9 @@ static public void runSketch(final String[] args, // Remove 60fps limit on the JavaFX "pulse" timer System.setProperty("javafx.animation.fullspeed", "true"); + // Doesn't seem to do anything helpful here (that can't be done via Runner) + //System.setProperty("com.apple.mrj.application.apple.menu.about.name", "potato"); + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); @@ -10176,6 +10730,7 @@ public void uncaughtException(Thread t, Throwable e) { // boolean fullScreen = false; boolean present = false; // boolean spanDisplays = false; + int density = -1; String param = null, value = null; String folder = calcSketchPath(); @@ -10192,9 +10747,11 @@ public void uncaughtException(Thread t, Throwable e) { editorLocation = parseInt(split(value, ',')); } else if (param.equals(ARGS_DISPLAY)) { - displayNum = parseInt(value, -1); - if (displayNum == -1) { - System.err.println("Could not parse " + value + " for " + ARGS_DISPLAY); + displayNum = parseInt(value, -2); + if (displayNum == -2) { + // this means the display value couldn't be parsed properly + System.err.println(value + " is not a valid choice for " + ARGS_DISPLAY); + displayNum = -1; // use the default } } else if (param.equals(ARGS_WINDOW_COLOR)) { @@ -10218,6 +10775,15 @@ public void uncaughtException(Thread t, Throwable e) { } else if (param.equals(ARGS_LOCATION)) { location = parseInt(split(value, ',')); + + } else if (param.equals(ARGS_DENSITY)) { + density = parseInt(value, -1); + if (density == -1) { + System.err.println("Could not parse " + value + " for " + ARGS_DENSITY); + } else if (density != 1 && density != 2) { + density = -1; + System.err.println(ARGS_DENSITY + " should be 1 or 2"); + } } } else { @@ -10259,7 +10825,7 @@ public void uncaughtException(Thread t, Throwable e) { try { Class c = Thread.currentThread().getContextClassLoader().loadClass(name); - sketch = (PApplet) c.newInstance(); + sketch = (PApplet) c.getDeclaredConstructor().newInstance(); } catch (RuntimeException re) { // Don't re-package runtime exceptions throw re; @@ -10286,6 +10852,12 @@ public void uncaughtException(Thread t, Throwable e) { // (and most likely, from the PDE's preference setting). sketch.display = displayNum; + // Set the suggested density that is coming from command line + // (most likely set from the PDE based on a system DPI scaling) + sketch.suggestedDensity = density; + + sketch.present = present; + // For 3.0.1, moved this above handleSettings() so that loadImage() can be // used inside settings(). Sets a terrible precedent, but the alternative // of not being able to size a sketch to an image is driving people loopy. @@ -11390,6 +11962,7 @@ public void curveVertex(float x, float y, float z) { * @webref shape:2d_primitives * @param x x-coordinate of the point * @param y y-coordinate of the point + * @see PGraphics#stroke(int) */ public void point(float x, float y) { if (recorder != null) recorder.point(x, y); @@ -11575,6 +12148,31 @@ public void rect(float a, float b, float c, float d, } + /** + * ( begin auto-generated from square.xml ) + * + * Draws a square to the screen. A square is a four-sided shape with + * every angle at ninety degrees and each side is the same length. + * By default, the first two parameters set the location of the + * upper-left corner, the third sets the width and height. The way + * these parameters are interpreted, however, may be changed with the + * rectMode() function. + * + * ( end auto-generated ) + * + * @webref shape:2d_primitives + * @param x x-coordinate of the rectangle by default + * @param y y-coordinate of the rectangle by default + * @param extent width and height of the rectangle by default + * @see PGraphics#rect(float, float, float, float) + * @see PGraphics#rectMode(int) + */ + public void square(float x, float y, float extent) { + if (recorder != null) recorder.square(x, y, extent); + g.square(x, y, extent); + } + + /** * ( begin auto-generated from ellipseMode.xml ) * @@ -11663,6 +12261,28 @@ public void arc(float a, float b, float c, float d, } + /** + * ( begin auto-generated from circle.xml ) + * + * Draws a circle to the screen. By default, the first two parameters + * set the location of the center, and the third sets the shape's width + * and height. The origin may be changed with the ellipseMode() + * function. + * + * ( end auto-generated ) + * @webref shape:2d_primitives + * @param x x-coordinate of the ellipse + * @param y y-coordinate of the ellipse + * @param extent width and height of the ellipse by default + * @see PApplet#ellipse(float, float, float, float) + * @see PApplet#ellipseMode(int) + */ + public void circle(float x, float y, float extent) { + if (recorder != null) recorder.circle(x, y, extent); + g.circle(x, y, extent); + } + + /** * ( begin auto-generated from box.xml ) * @@ -11942,17 +12562,17 @@ public void bezier(float x1, float y1, float z1, * ( begin auto-generated from curvePoint.xml ) * * Evalutes the curve at point t for points a, b, c, d. The parameter t - * varies between 0 and 1, a and d are points on the curve, and b and c are - * the control points. This can be done once with the x coordinates and a + * varies between 0 and 1, a and d are the control points, and b and c are + * the points on the curve. This can be done once with the x coordinates and a * second time with the y coordinates to get the location of a curve at t. * * ( end auto-generated ) * * @webref shape:curves - * @param a coordinate of first point on the curve - * @param b coordinate of second point on the curve - * @param c coordinate of third point on the curve - * @param d coordinate of fourth point on the curve + * @param a coordinate of first control point + * @param b coordinate of first point on the curve + * @param c coordinate of second point on the curve + * @param d coordinate of second control point * @param t value between 0 and 1 * @see PGraphics#curve(float, float, float, float, float, float, float, float, float, float, float, float) * @see PGraphics#curveVertex(float, float) @@ -11976,10 +12596,10 @@ public float curvePoint(float a, float b, float c, float d, float t) { * Code thanks to Dave Bollinger (Bug #715) * * @webref shape:curves - * @param a coordinate of first point on the curve - * @param b coordinate of first control point - * @param c coordinate of second control point - * @param d coordinate of second point on the curve + * @param a coordinate of first control point on the curve + * @param b coordinate of first point + * @param c coordinate of first point + * @param d coordinate of second control point on the curve * @param t value between 0 and 1 * @see PGraphics#curve(float, float, float, float, float, float, float, float, float, float, float, float) * @see PGraphics#curveVertex(float, float) @@ -12161,8 +12781,8 @@ public void imageMode(int mode) { * * @webref image:loading_displaying * @param img the image to display - * @param a x-coordinate of the image - * @param b y-coordinate of the image + * @param a x-coordinate of the image by default + * @param b y-coordinate of the image by default * @see PApplet#loadImage(String, String) * @see PImage * @see PGraphics#imageMode(int) @@ -12177,8 +12797,8 @@ public void image(PImage img, float a, float b) { /** - * @param c width to display the image - * @param d height to display the image + * @param c width to display the image by default + * @param d height to display the image by default */ public void image(PImage img, float a, float b, float c, float d) { if (recorder != null) recorder.image(img, a, b, c, d); @@ -12685,6 +13305,82 @@ public void text(float num, float x, float y, float z) { } + /** + * ( begin auto-generated from push.xml ) + * + * The push() function saves the current drawing style + * settings and transformations, while pop() restores these + * settings. Note that these functions are always used together. + * They allow you to change the style and transformation settings + * and later return to what you had. When a new state is started + * with push(), it builds on the current style and transform + * information.
+ *
+ * push() stores information related to the current + * transformation state and style settings controlled by the + * following functions: rotate(), translate(), + * scale(), fill(), stroke(), tint(), + * strokeWeight(), strokeCap(), strokeJoin(), + * imageMode(), rectMode(), ellipseMode(), + * colorMode(), textAlign(), textFont(), + * textMode(), textSize(), textLeading().
+ *
+ * The push() and pop() functions were added with + * Processing 3.5. They can be used in place of pushMatrix(), + * popMatrix(), pushStyles(), and popStyles(). + * The difference is that push() and pop() control both the + * transformations (rotate, scale, translate) and the drawing styles + * at the same time. + * + * ( end auto-generated ) + * + * @webref structure + * @see PGraphics#pop() + */ + public void push() { + if (recorder != null) recorder.push(); + g.push(); + } + + + /** + * ( begin auto-generated from pop.xml ) + * + * The pop() function restores the previous drawing style + * settings and transformations after push() has changed them. + * Note that these functions are always used together. They allow + * you to change the style and transformation settings and later + * return to what you had. When a new state is started with push(), + * it builds on the current style and transform information.
+ *
+ *
+ * push() stores information related to the current + * transformation state and style settings controlled by the + * following functions: rotate(), translate(), + * scale(), fill(), stroke(), tint(), + * strokeWeight(), strokeCap(), strokeJoin(), + * imageMode(), rectMode(), ellipseMode(), + * colorMode(), textAlign(), textFont(), + * textMode(), textSize(), textLeading().
+ *
+ * The push() and pop() functions were added with + * Processing 3.5. They can be used in place of pushMatrix(), + * popMatrix(), pushStyles(), and popStyles(). + * The difference is that push() and pop() control both the + * transformations (rotate, scale, translate) and the drawing styles + * at the same time. + * + * ( end auto-generated ) + * + * @webref structure + * @see PGraphics#push() + */ + public void pop() { + if (recorder != null) recorder.pop(); + g.pop(); + } + + /** * ( begin auto-generated from pushMatrix.xml ) * @@ -14148,6 +14844,8 @@ public void specular(int rgb) { /** * gray number specifying value between white and black + * + * @param gray value between black and white, by default 0 to 255 */ public void specular(float gray) { if (recorder != null) recorder.specular(gray); @@ -14213,6 +14911,8 @@ public void emissive(int rgb) { /** * gray number specifying value between white and black + * + * @param gray value between black and white, by default 0 to 255 */ public void emissive(float gray) { if (recorder != null) recorder.emissive(gray); diff --git a/core/src/processing/core/PFont.java b/core/src/processing/core/PFont.java index 632cd7ec03..5c8d38c4b5 100644 --- a/core/src/processing/core/PFont.java +++ b/core/src/processing/core/PFont.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry & Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -145,29 +145,26 @@ public class PFont implements PConstants { /** True if already tried to find the native AWT version of this font. */ protected boolean fontSearched; + /** + * The name of the font that Java uses when a font isn't found. + * See {@link #findFont(String)} and {@link #loadFonts()} for more info. + */ + static protected String systemFontName; + /** * Array of the native system fonts. Used to lookup native fonts by their * PostScript name. This is a workaround for a several year old Apple Java * bug that they can't be bothered to fix. */ static protected Font[] fonts; - static protected HashMap fontDifferent; - -// /** -// * If not null, this font is set to load dynamically. This is the default -// * when createFont() method is called without a character set. Bitmap -// * versions of characters are only created when prompted by an index() call. -// */ -// protected Font lazyFont; + static protected HashMap fontDifferent; + protected BufferedImage lazyImage; protected Graphics2D lazyGraphics; protected FontMetrics lazyMetrics; protected int[] lazySamples; - /** for subclasses that need to store metadata about the font */ -// protected HashMap cacheMap; - /** * @nowebref */ @@ -207,7 +204,7 @@ public PFont(Font font, boolean smooth) { * @nowebref * @param charset array of all unicode chars that should be included */ - public PFont(Font font, boolean smooth, char charset[]) { + public PFont(Font font, boolean smooth, char[] charset) { // save this so that we can use the native version this.font = font; this.smooth = smooth; @@ -332,7 +329,7 @@ public PFont(Font font, boolean smooth, char charset[]) { * * @nowebref */ - public PFont(Font font, boolean smooth, char charset[], + public PFont(Font font, boolean smooth, char[] charset, boolean stream, int density) { this(font, smooth, charset); this.stream = stream; @@ -785,7 +782,7 @@ public PShape getShape(char ch, float detail) { case PathIterator.SEG_CUBICTO: // 3 points // System.out.println("cubicto"); // PApplet.println(iterPoints); - s.quadraticVertex(iterPoints[0], iterPoints[1], + s.bezierVertex(iterPoints[0], iterPoints[1], iterPoints[2], iterPoints[3], iterPoints[4], iterPoints[5]); break; @@ -868,7 +865,7 @@ public PShape getShape(char ch, float detail) { for (int i = 0; i < EXTRA_CHARS.length; i++) { CHARSET[index++] = EXTRA_CHARS[i]; } - }; + } /** @@ -888,7 +885,7 @@ public PShape getShape(char ch, float detail) { */ static public String[] list() { loadFonts(); - String list[] = new String[fonts.length]; + String[] list = new String[fonts.length]; for (int i = 0; i < list.length; i++) { list[i] = fonts[i].getName(); } @@ -896,17 +893,33 @@ static public String[] list() { } + /** + * Make an internal list of all installed fonts. + * + * This can take a while with a lot of fonts installed, but running it on + * a separate thread may not help much. As of the commit that's adding this + * note, loadFonts() will only be called by PFont.list() and when loading a + * font by name, both of which are occasions when we'd need to block until + * this was finished anyway. It's also possible that running getAllFonts() + * on a non-EDT thread could cause graphics system issues. Further, the first + * fonts are usually loaded at the beginning of a sketch, meaning that sketch + * startup time will still be affected, even with threading in place. + * + * Where we're getting killed on font performance is due to this bug: + * https://bugs.openjdk.java.net/browse/JDK-8179209 + */ static public void loadFonts() { if (fonts == null) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); fonts = ge.getAllFonts(); + if (PApplet.platform == PConstants.MACOSX) { - fontDifferent = new HashMap(); + fontDifferent = new HashMap<>(); for (Font font : fonts) { - // getName() returns the PostScript name on OS X 10.6 w/ Java 6. + // No need to use getPSName() anymore because getName() + // returns the PostScript name on OS X 10.6 w/ Java 6. fontDifferent.put(font.getName(), font); - //fontDifferent.put(font.getPSName(), font); } } } @@ -917,21 +930,35 @@ static public void loadFonts() { * Starting with Java 1.5, Apple broke the ability to specify most fonts. * This bug was filed years ago as #4769141 at bugreporter.apple.com. More: * Bug 407. + *
+ * This function displays a warning when the font is not found + * and Java's system font is used. + * See: issue #5481 */ static public Font findFont(String name) { - loadFonts(); if (PApplet.platform == PConstants.MACOSX) { + loadFonts(); Font maybe = fontDifferent.get(name); if (maybe != null) { return maybe; } -// for (int i = 0; i < fonts.length; i++) { -// if (name.equals(fonts[i].getName())) { -// return fonts[i]; -// } -// } } - return new Font(name, Font.PLAIN, 1); + Font font = new Font(name, Font.PLAIN, 1); + + // make sure we have the name of the system fallback font + if (systemFontName == null) { + // Figure out what the font is named when things fail + systemFontName = new Font("", Font.PLAIN, 1).getFontName(); + } + + // warn the user if they didn't get the font they want + if (!name.equals(systemFontName) && + font.getFontName().equals(systemFontName)) { + PGraphics.showWarning("\"" + name + "\" is not available, " + + "so another font will be used. " + + "Use PFont.list() to show available fonts."); + } + return font; } diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 9b2e18cdbc..d9b4be5192 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2013-15 The Processing Foundation + Copyright (c) 2013-20 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -227,7 +227,7 @@ public class PGraphics extends PImage implements PConstants { * images go out of scope, they will be properly garbage collected. */ protected WeakHashMap cacheMap = - new WeakHashMap(); + new WeakHashMap<>(); //////////////////////////////////////////////////////////// @@ -334,8 +334,11 @@ public class PGraphics extends PImage implements PConstants { /** True if colors are not in the range 0..1 */ boolean colorModeScale; // = true; - /** True if colorMode(RGB, 255) */ - boolean colorModeDefault; // = true; + /** + * True if colorMode(RGB, 255). Defaults to true so that color() + * used as part of a field declaration will properly assign values. + */ + boolean colorModeDefault = true; // ........................................................ @@ -567,7 +570,7 @@ public class PGraphics extends PImage implements PConstants { // vertices public static final int DEFAULT_VERTICES = 512; - protected float vertices[][] = + protected float[][] vertices = new float[DEFAULT_VERTICES][VERTEX_FIELD_COUNT]; protected int vertexCount; // total number of vertices @@ -602,7 +605,7 @@ public class PGraphics extends PImage implements PConstants { // spline vertices - protected float curveVertices[][]; + protected float[][] curveVertices; protected int curveVertexCount; // ........................................................ @@ -615,8 +618,8 @@ public class PGraphics extends PImage implements PConstants { // [toxi 031031] // changed table's precision to 0.5 degree steps // introduced new vars for more flexible code - static final protected float sinLUT[]; - static final protected float cosLUT[]; + static final protected float[] sinLUT; + static final protected float[] cosLUT; static final protected float SINCOS_PRECISION = 0.5f; static final protected int SINCOS_LENGTH = (int) (360f / SINCOS_PRECISION); static { @@ -699,7 +702,9 @@ public class PGraphics extends PImage implements PConstants { // [toxi031031] new & faster sphere code w/ support flexible resolutions // will be set by sphereDetail() or 1st call to sphere() - protected float sphereX[], sphereY[], sphereZ[]; + protected float[] sphereX; + protected float[] sphereY; + protected float[] sphereZ; /// Number of U steps (aka "theta") around longitudinally spanning 2*pi public int sphereDetailU = 0; @@ -1385,7 +1390,7 @@ public void noTexture() { protected void vertexCheck() { if (vertexCount == vertices.length) { - float temp[][] = new float[vertexCount << 1][VERTEX_FIELD_COUNT]; + float[][] temp = new float[vertexCount << 1][VERTEX_FIELD_COUNT]; System.arraycopy(vertices, 0, temp, 0, vertexCount); vertices = temp; } @@ -1477,7 +1482,7 @@ public void vertex(float x, float y, float z) { // http://dev.processing.org/bugs/show_bug.cgi?id=444 if (shape == POLYGON) { if (vertexCount > 0) { - float pvertex[] = vertices[vertexCount-1]; + float[] pvertex = vertices[vertexCount-1]; if ((Math.abs(pvertex[X] - x) < EPSILON) && (Math.abs(pvertex[Y] - y) < EPSILON) && (Math.abs(pvertex[Z] - z) < EPSILON)) { @@ -2013,6 +2018,7 @@ protected void clipImpl(float x1, float y1, float x2, float y2) { showMissingWarning("clip"); } + /** * ( begin auto-generated from noClip.xml ) * @@ -2266,9 +2272,9 @@ protected void curveVertexCheck(int shape) { */ public void curveVertex(float x, float y) { curveVertexCheck(); - float[] vertex = curveVertices[curveVertexCount]; - vertex[X] = x; - vertex[Y] = y; + float[] v = curveVertices[curveVertexCount]; + v[X] = x; + v[Y] = y; curveVertexCount++; // draw a segment if there are enough points @@ -2289,10 +2295,10 @@ public void curveVertex(float x, float y) { */ public void curveVertex(float x, float y, float z) { curveVertexCheck(); - float[] vertex = curveVertices[curveVertexCount]; - vertex[X] = x; - vertex[Y] = y; - vertex[Z] = z; + float[] v = curveVertices[curveVertexCount]; + v[X] = x; + v[Y] = y; + v[Z] = z; curveVertexCount++; // draw a segment if there are enough points @@ -2408,6 +2414,7 @@ protected void curveVertexSegment(float x1, float y1, float z1, * @webref shape:2d_primitives * @param x x-coordinate of the point * @param y y-coordinate of the point + * @see PGraphics#stroke(int) */ public void point(float x, float y) { beginShape(POINTS); @@ -2724,6 +2731,29 @@ protected void rectImpl(float x1, float y1, float x2, float y2, endShape(CLOSE); } + /** + * ( begin auto-generated from square.xml ) + * + * Draws a square to the screen. A square is a four-sided shape with + * every angle at ninety degrees and each side is the same length. + * By default, the first two parameters set the location of the + * upper-left corner, the third sets the width and height. The way + * these parameters are interpreted, however, may be changed with the + * rectMode() function. + * + * ( end auto-generated ) + * + * @webref shape:2d_primitives + * @param x x-coordinate of the rectangle by default + * @param y y-coordinate of the rectangle by default + * @param extent width and height of the rectangle by default + * @see PGraphics#rect(float, float, float, float) + * @see PGraphics#rectMode(int) + */ + public void square(float x, float y, float extent) { + rect(x, y, extent, extent); + } + ////////////////////////////////////////////////////////////// @@ -2900,6 +2930,26 @@ protected void arcImpl(float x, float y, float w, float h, showMissingWarning("arc"); } + /** + * ( begin auto-generated from circle.xml ) + * + * Draws a circle to the screen. By default, the first two parameters + * set the location of the center, and the third sets the shape's width + * and height. The origin may be changed with the ellipseMode() + * function. + * + * ( end auto-generated ) + * @webref shape:2d_primitives + * @param x x-coordinate of the ellipse + * @param y y-coordinate of the ellipse + * @param extent width and height of the ellipse by default + * @see PApplet#ellipse(float, float, float, float) + * @see PApplet#ellipseMode(int) + */ + public void circle(float x, float y, float extent) { + ellipse(x, y, extent, extent); + } + ////////////////////////////////////////////////////////////// @@ -3212,10 +3262,8 @@ public void sphere(float r) { */ public float bezierPoint(float a, float b, float c, float d, float t) { float t1 = 1.0f - t; - return a*t1*t1*t1 + 3*b*t*t1*t1 + 3*c*t*t*t1 + d*t*t*t; + return (a*t1 + 3*b*t)*t1*t1 + (3*c*t1 + d*t)*t*t; } - - /** * ( begin auto-generated from bezierTangent.xml ) * @@ -3378,17 +3426,17 @@ public void bezier(float x1, float y1, float z1, * ( begin auto-generated from curvePoint.xml ) * * Evalutes the curve at point t for points a, b, c, d. The parameter t - * varies between 0 and 1, a and d are points on the curve, and b and c are - * the control points. This can be done once with the x coordinates and a + * varies between 0 and 1, a and d are the control points, and b and c are + * the points on the curve. This can be done once with the x coordinates and a * second time with the y coordinates to get the location of a curve at t. * * ( end auto-generated ) * * @webref shape:curves - * @param a coordinate of first point on the curve - * @param b coordinate of second point on the curve - * @param c coordinate of third point on the curve - * @param d coordinate of fourth point on the curve + * @param a coordinate of first control point + * @param b coordinate of first point on the curve + * @param c coordinate of second point on the curve + * @param d coordinate of second control point * @param t value between 0 and 1 * @see PGraphics#curve(float, float, float, float, float, float, float, float, float, float, float, float) * @see PGraphics#curveVertex(float, float) @@ -3422,10 +3470,10 @@ public float curvePoint(float a, float b, float c, float d, float t) { * Code thanks to Dave Bollinger (Bug #715) * * @webref shape:curves - * @param a coordinate of first point on the curve - * @param b coordinate of first control point - * @param c coordinate of second control point - * @param d coordinate of second point on the curve + * @param a coordinate of first control point on the curve + * @param b coordinate of first point + * @param c coordinate of first point + * @param d coordinate of second control point on the curve * @param t value between 0 and 1 * @see PGraphics#curve(float, float, float, float, float, float, float, float, float, float, float, float) * @see PGraphics#curveVertex(float, float) @@ -3753,8 +3801,8 @@ public void imageMode(int mode) { * * @webref image:loading_displaying * @param img the image to display - * @param a x-coordinate of the image - * @param b y-coordinate of the image + * @param a x-coordinate of the image by default + * @param b y-coordinate of the image by default * @see PApplet#loadImage(String, String) * @see PImage * @see PGraphics#imageMode(int) @@ -3782,8 +3830,8 @@ public void image(PImage img, float a, float b) { } /** - * @param c width to display the image - * @param d height to display the image + * @param c width to display the image by default + * @param d height to display the image by default */ public void image(PImage img, float a, float b, float c, float d) { image(img, a, b, c, d, 0, 0, img.width, img.height); @@ -3878,6 +3926,11 @@ protected void imageImpl(PImage img, // fillA = 1; // } + u1 *= img.pixelDensity; + u2 *= img.pixelDensity; + v1 *= img.pixelDensity; + v2 *= img.pixelDensity; + beginShape(QUADS); texture(img); vertex(x1, y1, u1, v1); @@ -3897,6 +3950,7 @@ protected void imageImpl(PImage img, } + ////////////////////////////////////////////////////////////// // SHAPE @@ -3950,7 +4004,6 @@ public void shape(PShape shape) { } - /** * ( begin auto-generated from shape.xml ) * @@ -4048,13 +4101,23 @@ protected void shape(PShape shape, float x, float y, float z, float c, float d, } + ////////////////////////////////////////////////////////////// // TEXT/FONTS + /** + * Used by PGraphics to remove the requirement for loading a font. + */ + protected PFont createDefaultFont(float size) { + Font baseFont = new Font("Lucida Sans", Font.PLAIN, 1); + return createFont(baseFont, size, true, null, false); + } + + protected PFont createFont(String name, float size, - boolean smooth, char[] charset) { + boolean smooth, char[] charset) { String lowerName = name.toLowerCase(); Font baseFont = null; @@ -4064,9 +4127,9 @@ protected PFont createFont(String name, float size, stream = parent.createInput(name); if (stream == null) { System.err.println("The font \"" + name + "\" " + - "is missing or inaccessible, make sure " + - "the URL is valid or that the file has been " + - "added to your sketch and is readable."); + "is missing or inaccessible, make sure " + + "the URL is valid or that the file has been " + + "added to your sketch and is readable."); return null; } baseFont = Font.createFont(Font.TRUETYPE_FONT, parent.createInput(name)); @@ -4074,9 +4137,7 @@ protected PFont createFont(String name, float size, } else { baseFont = PFont.findFont(name); } - return new PFont(baseFont.deriveFont(size * parent.pixelDensity), - smooth, charset, stream != null, - parent.pixelDensity); + return createFont(baseFont, size, smooth, charset, stream != null); } catch (Exception e) { System.err.println("Problem with createFont(\"" + name + "\")"); @@ -4086,6 +4147,14 @@ protected PFont createFont(String name, float size, } + private PFont createFont(Font baseFont, float size, + boolean smooth, char[] charset, boolean stream) { + return new PFont(baseFont.deriveFont(size * parent.pixelDensity), + smooth, charset, stream, + parent.pixelDensity); + } + + public void textAlign(int alignX) { textAlign(alignX, BASELINE); } @@ -4484,7 +4553,7 @@ public float textWidth(char[] chars, int start, int length) { * Unlike the previous version that was inside PFont, this will * return the size not of a 1 pixel font, but the actual current size. */ - protected float textWidthImpl(char buffer[], int start, int stop) { + protected float textWidthImpl(char[] buffer, int start, int stop) { float wide = 0; for (int i = start; i < stop; i++) { // could add kerning here, but it just ain't implemented @@ -4911,16 +4980,6 @@ protected void textSentenceBreak(int start, int stop) { } -// public void text(String s, float a, float b, float c, float d, float z) { -// if (z != 0) translate(0, 0, z); // slowness, badness -// -// text(s, a, b, c, d); -// textZ = z; -// -// if (z != 0) translate(0, 0, -z); // TEMPORARY HACK! SLOW! -// } - - public void text(int num, float x, float y) { text(String.valueOf(num), x, y); } @@ -4962,7 +5021,7 @@ public void text(float num, float x, float y, float z) { * Handles placement of a text line, then calls textLineImpl * to actually render at the specific point. */ - protected void textLineAlignImpl(char buffer[], int start, int stop, + protected void textLineAlignImpl(char[] buffer, int start, int stop, float x, float y) { if (textAlign == CENTER) { x -= textWidthImpl(buffer, start, stop) / 2f; @@ -4978,7 +5037,7 @@ protected void textLineAlignImpl(char buffer[], int start, int stop, /** * Implementation of actual drawing for a line of text. */ - protected void textLineImpl(char buffer[], int start, int stop, + protected void textLineImpl(char[] buffer, int start, int stop, float x, float y) { for (int index = start; index < stop; index++) { textCharImpl(buffer[index], x, y); @@ -5102,27 +5161,84 @@ protected void textCharScreenImpl(PImage glyph, */ -// /** -// * Convenience method to get a legit FontMetrics object. Where possible, -// * override this any renderer subclass so that you're not using what's -// * returned by getDefaultToolkit() to get your metrics. -// */ -// @SuppressWarnings("deprecation") -// public FontMetrics getFontMetrics(Font font) { // ignore -// Frame frame = parent.frame; -// if (frame != null) { -// return frame.getToolkit().getFontMetrics(font); -// } -// return Toolkit.getDefaultToolkit().getFontMetrics(font); -// } -// -// -// /** -// * Convenience method to jump through some Java2D hoops and get an FRC. -// */ -// public FontRenderContext getFontRenderContext(Font font) { // ignore -// return getFontMetrics(font).getFontRenderContext(); -// } + + ////////////////////////////////////////////////////////////// + + // PARITY WITH P5.JS + + /** + * ( begin auto-generated from push.xml ) + * + * The push() function saves the current drawing style + * settings and transformations, while pop() restores these + * settings. Note that these functions are always used together. + * They allow you to change the style and transformation settings + * and later return to what you had. When a new state is started + * with push(), it builds on the current style and transform + * information.
+ *
+ * push() stores information related to the current + * transformation state and style settings controlled by the + * following functions: rotate(), translate(), + * scale(), fill(), stroke(), tint(), + * strokeWeight(), strokeCap(), strokeJoin(), + * imageMode(), rectMode(), ellipseMode(), + * colorMode(), textAlign(), textFont(), + * textMode(), textSize(), textLeading().
+ *
+ * The push() and pop() functions were added with + * Processing 3.5. They can be used in place of pushMatrix(), + * popMatrix(), pushStyles(), and popStyles(). + * The difference is that push() and pop() control both the + * transformations (rotate, scale, translate) and the drawing styles + * at the same time. + * + * ( end auto-generated ) + * + * @webref structure + * @see PGraphics#pop() + */ + public void push() { + pushStyle(); + pushMatrix(); + } + + /** + * ( begin auto-generated from pop.xml ) + * + * The pop() function restores the previous drawing style + * settings and transformations after push() has changed them. + * Note that these functions are always used together. They allow + * you to change the style and transformation settings and later + * return to what you had. When a new state is started with push(), + * it builds on the current style and transform information.
+ *
+ *
+ * push() stores information related to the current + * transformation state and style settings controlled by the + * following functions: rotate(), translate(), + * scale(), fill(), stroke(), tint(), + * strokeWeight(), strokeCap(), strokeJoin(), + * imageMode(), rectMode(), ellipseMode(), + * colorMode(), textAlign(), textFont(), + * textMode(), textSize(), textLeading().
+ *
+ * The push() and pop() functions were added with + * Processing 3.5. They can be used in place of pushMatrix(), + * popMatrix(), pushStyles(), and popStyles(). + * The difference is that push() and pop() control both the + * transformations (rotate, scale, translate) and the drawing styles + * at the same time. + * + * ( end auto-generated ) + * + * @webref structure + * @see PGraphics#push() + */ + public void pop() { + popStyle(); + popMatrix(); + } @@ -6162,7 +6278,9 @@ public void style(PStyle s) { ellipseMode(s.ellipseMode); shapeMode(s.shapeMode); - blendMode(s.blendMode); + if (blendMode != s.blendMode) { + blendMode(s.blendMode); + } if (s.tint) { tint(s.tintColor); @@ -6824,6 +6942,8 @@ public void specular(int rgb) { /** * gray number specifying value between white and black + * + * @param gray value between black and white, by default 0 to 255 */ public void specular(float gray) { colorCalc(gray); @@ -6901,6 +7021,8 @@ public void emissive(int rgb) { /** * gray number specifying value between white and black + * + * @param gray value between black and white, by default 0 to 255 */ public void emissive(float gray) { colorCalc(gray); @@ -7346,7 +7468,7 @@ protected void backgroundFromCalc() { * @param image PImage to set as background (must be same size as the sketch window) */ public void background(PImage image) { - if ((image.width != width) || (image.height != height)) { + if ((image.pixelWidth != pixelWidth) || (image.pixelHeight != pixelHeight)) { throw new RuntimeException(ERROR_BACKGROUND_IMAGE_SIZE); } if ((image.format != RGB) && (image.format != ARGB)) { @@ -7377,6 +7499,7 @@ protected void backgroundImpl() { pushStyle(); pushMatrix(); resetMatrix(); + noStroke(); fill(backgroundColor); rect(0, 0, width, height); popMatrix(); @@ -8121,7 +8244,7 @@ public PGraphics getRaw() { // ignore */ static public void showWarning(String msg) { // ignore if (warnings == null) { - warnings = new HashMap(); + warnings = new HashMap<>(); } if (!warnings.containsKey(msg)) { System.err.println(msg); @@ -8215,7 +8338,7 @@ protected void defaultFontOrDeath(String method) { */ protected void defaultFontOrDeath(String method, float size) { if (parent != null) { - textFont = parent.createDefaultFont(size); + textFont = createDefaultFont(size); } else { throw new RuntimeException("Use textFont() before " + method + "()"); } diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index cc1105322f..d83b1da5d0 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -90,7 +90,7 @@ public class PImage implements PConstants, Cloneable { * * @webref image:pixels * @usage web_application - * @brief Array containing the color of every pixel in the image + * @brief Array containing the color of every pixel in the image */ public int[] pixels; @@ -936,12 +936,11 @@ protected void setImpl(PImage sourceImage, // ALPHA CHANNEL - @Deprecated /** * @param maskArray array of integers used as the alpha channel, needs to be * the same length as the image's pixel array. */ - public void mask(int maskArray[]) { // ignore + public void mask(int[] maskArray) { // ignore loadPixels(); // don't execute if mask image is different size if (maskArray.length != pixels.length) { @@ -1240,7 +1239,7 @@ protected void buildBlurKernel(float r) { protected void blurAlpha(float r) { int sum, cb; int read, ri, ym, ymi, bk0; - int b2[] = new int[pixels.length]; + int[] b2 = new int[pixels.length]; int yi = 0; buildBlurKernel(r); @@ -1311,9 +1310,9 @@ protected void blurAlpha(float r) { protected void blurRGB(float r) { int sum, cr, cg, cb; //, k; int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0; - int r2[] = new int[pixels.length]; - int g2[] = new int[pixels.length]; - int b2[] = new int[pixels.length]; + int[] r2 = new int[pixels.length]; + int[] g2 = new int[pixels.length]; + int[] b2 = new int[pixels.length]; int yi = 0; buildBlurKernel(r); @@ -1394,10 +1393,10 @@ protected void blurARGB(float r) { int sum, cr, cg, cb, ca; int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0; int wh = pixels.length; - int r2[] = new int[wh]; - int g2[] = new int[wh]; - int b2[] = new int[wh]; - int a2[] = new int[wh]; + int[] r2 = new int[wh]; + int[] g2 = new int[wh]; + int[] b2 = new int[wh]; + int[] a2 = new int[wh]; int yi = 0; buildBlurKernel(r); @@ -2949,7 +2948,7 @@ private static int blend_burn(int dst, int src) { // FILE I/O - static byte TIFF_HEADER[] = { + static byte[] TIFF_HEADER = { 77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0, @@ -2962,7 +2961,7 @@ private static int blend_burn(int dst, int src) { static final String TIFF_ERROR = "Error: Processing can only read its own TIFF files."; - static protected PImage loadTIFF(byte tiff[]) { + static protected PImage loadTIFF(byte[] tiff) { if ((tiff[42] != tiff[102]) || // width/height in both places (tiff[43] != tiff[103])) { System.err.println(TIFF_ERROR); @@ -3019,7 +3018,7 @@ protected boolean saveTIFF(OutputStream output) { } */ try { - byte tiff[] = new byte[768]; + byte[] tiff = new byte[768]; System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length); tiff[30] = (byte) ((pixelWidth >> 8) & 0xff); @@ -3070,7 +3069,7 @@ protected boolean saveTIFF(OutputStream output) { * specification */ protected boolean saveTGA(OutputStream output) { - byte header[] = new byte[18]; + byte[] header = new byte[18]; if (format == ALPHA) { // save ALPHA images as 8bit grayscale header[2] = 0x0B; @@ -3329,15 +3328,13 @@ private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double /** * ( begin auto-generated from PImage_save.xml ) * - * Saves the image into a file. Images are saved in TIFF, TARGA, JPEG, and - * PNG format depending on the extension within the filename - * parameter. For example, "image.tif" will have a TIFF image and - * "image.png" will save a PNG image. If no extension is included in the - * filename, the image will save in TIFF format and .tif will be - * added to the name. These files are saved to the sketch's folder, which + * Saves the image into a file. Append a file extension to the name of + * the file, to indicate the file format to be used: either TIFF (.tif), + * TARGA (.tga), JPEG (.jpg), or PNG (.png). If no extension is included + * in the filename, the image will save in TIFF format and .tif will be + * added to the name. These files are saved to the sketch's folder, which * may be opened by selecting "Show sketch folder" from the "Sketch" menu. - * It is not possible to use save() while running the program in a - * web browser.

To save an image created within the code, rather + *

To save an image created within the code, rather * than through loading, it's necessary to make the image with the * createImage() function so it is aware of the location of the * program and can therefore save the file to the right place. See the diff --git a/core/src/processing/core/PMatrix2D.java b/core/src/processing/core/PMatrix2D.java index 38f82bdfd3..c30a3504e3 100644 --- a/core/src/processing/core/PMatrix2D.java +++ b/core/src/processing/core/PMatrix2D.java @@ -381,7 +381,7 @@ public PVector mult(PVector source, PVector target) { * If out is null or not length four, a new float array will be returned. * The values for vec and out can be the same (though that's less efficient). */ - public float[] mult(float vec[], float out[]) { + public float[] mult(float[] vec, float[] out) { if (out == null || out.length != 2) { out = new float[2]; } diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index 05bc4e18a4..0c622d18b8 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -22,10 +22,14 @@ package processing.core; +import java.awt.Image; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; -import processing.core.PApplet; +import javax.swing.ImageIcon; +import javax.xml.bind.DatatypeConverter; /** @@ -106,6 +110,7 @@ public class PShape implements PConstants { /** Texture or image data associated with this shape. */ protected PImage image; + protected String imagePath = null; public static final String OUTSIDE_BEGIN_END_ERROR = "%1$s can only be called between beginShape() and endShape()"; @@ -1604,9 +1609,9 @@ protected void drawImpl(PGraphics g) { } else if (family == PRIMITIVE) { drawPrimitive(g); } else if (family == GEOMETRY) { - // same as path - drawPath(g); -// drawGeometry(g); + // Not same as path: `kind` matters. +// drawPath(g); + drawGeometry(g); } else if (family == PATH) { drawPath(g); } @@ -1645,6 +1650,10 @@ protected void drawPrimitive(PGraphics g) { params[6], params[7]); } else if (kind == RECT) { + + if (imagePath != null){ + loadImage(g); + } if (image != null) { int oldMode = g.imageMode; g.imageMode(CORNER); @@ -1879,6 +1888,63 @@ protected void drawPath(PGraphics g) { g.endShape(close ? CLOSE : OPEN); } + private void loadImage(PGraphics g){ + + if(this.imagePath.startsWith("data:image")){ + loadBase64Image(); + } + + if(this.imagePath.startsWith("file://")){ + loadFileSystemImage(g); + } + this.imagePath = null; + } + + private void loadFileSystemImage(PGraphics g){ + imagePath = imagePath.substring(7); + PImage loadedImage = g.parent.loadImage(imagePath); + if(loadedImage == null){ + System.err.println("Error loading image file: " + imagePath); + }else{ + setTexture(loadedImage); + } + } + + private void loadBase64Image(){ + String[] parts = this.imagePath.split(";base64,"); + String extension = parts[0].substring(11); + String encodedData = parts[1]; + + byte[] decodedBytes = DatatypeConverter.parseBase64Binary(encodedData); + + if(decodedBytes == null){ + System.err.println("Decode Error on image: " + imagePath.substring(0, 20)); + return; + } + + Image awtImage = new ImageIcon(decodedBytes).getImage(); + + if (awtImage instanceof BufferedImage) { + BufferedImage buffImage = (BufferedImage) awtImage; + int space = buffImage.getColorModel().getColorSpace().getType(); + if (space == ColorSpace.TYPE_CMYK) { + return; + } + } + + PImage loadedImage = new PImage(awtImage); + if (loadedImage.width == -1) { + // error... + } + + // if it's a .gif image, test to see if it has transparency + if (extension.equals("gif") || extension.equals("png") || + extension.equals("unknown")) { + loadedImage.checkAlpha(); + } + + setTexture(loadedImage); + } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -2040,7 +2106,7 @@ public void addName(String nom, PShape shape) { parent.addName(nom, shape); } else { if (nameTable == null) { - nameTable = new HashMap(); + nameTable = new HashMap<>(); } nameTable.put(nom, shape); } @@ -2387,14 +2453,14 @@ public void setFill(boolean fill) { /** * ( begin auto-generated from PShape_setFill.xml ) * - * The setFill() method defines the fill color of a PShape. - * This method is used after shapes are created or when a shape is defined explicitly - * (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in the above example. - * When a shape is created with beginShape() and endShape(), its - * attributes may be changed with fill() and stroke() within - * beginShape() and endShape(). However, after the shape is - * created, only the setFill() method can define a new fill value for - * the PShape. + * The setFill() method defines the fill color of a PShape. + * This method is used after shapes are created or when a shape is defined explicitly + * (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in the above example. + * When a shape is created with beginShape() and endShape(), its + * attributes may be changed with fill() and stroke() within + * beginShape() and endShape(). However, after the shape is + * created, only the setFill() method can define a new fill value for + * the PShape. * * ( end auto-generated ) * @@ -2543,14 +2609,14 @@ public void setStroke(boolean stroke) { /** * ( begin auto-generated from PShape_setStroke.xml ) * - * The setStroke() method defines the outline color of a PShape. - * This method is used after shapes are created or when a shape is defined - * explicitly (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in - * the above example. When a shape is created with beginShape() and - * endShape(), its attributes may be changed with fill() and - * stroke() within beginShape() and endShape(). - * However, after the shape is created, only the setStroke() method - * can define a new stroke value for the PShape. + * The setStroke() method defines the outline color of a PShape. + * This method is used after shapes are created or when a shape is defined + * explicitly (e.g. createShape(RECT, 20, 20, 80, 80)) as shown in + * the above example. When a shape is created with beginShape() and + * endShape(), its attributes may be changed with fill() and + * stroke() within beginShape() and endShape(). + * However, after the shape is created, only the setStroke() method + * can define a new stroke value for the PShape. * * ( end auto-generated ) * @@ -2891,13 +2957,28 @@ public boolean isClosed() { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html + /** + * Return true if this x, y coordinate is part of this shape. Only works + * with PATH shapes or GROUP shapes that contain other GROUPs or PATHs. + */ public boolean contains(float x, float y) { if (family == PATH) { + PVector p = new PVector(x, y); + if (matrix != null) { + // apply the inverse transformation matrix to the point coordinates + PMatrix inverseCoords = matrix.get(); + // TODO why is this called twice? [fry 190724] + // commit was https://github.com/processing/processing/commit/027fc7a4f8e8d0a435366eae754304eea282512a + inverseCoords.invert(); // maybe cache this? + inverseCoords.invert(); // maybe cache this? + inverseCoords.mult(new PVector(x, y), p); + } + + // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html boolean c = false; for (int i = 0, j = vertexCount-1; i < vertexCount; j = i++) { - if (((vertices[i][Y] > y) != (vertices[j][Y] > y)) && - (x < + if (((vertices[i][Y] > p.y) != (vertices[j][Y] > p.y)) && + (p.x < (vertices[j][X]-vertices[i][X]) * (y-vertices[i][Y]) / (vertices[j][1]-vertices[i][Y]) + @@ -2906,7 +2987,18 @@ public boolean contains(float x, float y) { } } return c; + + } else if (family == GROUP) { + // If this is a group, loop through children until we find one that + // contains the supplied coordinates. If a child does not support + // contains() throw a warning and continue. + for (int i = 0; i < childCount; i++) { + if (children[i].contains(x, y)) return true; + } + return false; + } else { + // https://github.com/processing/processing/issues/1280 throw new IllegalArgumentException("The contains() method is only implemented for paths."); } } @@ -3442,4 +3534,4 @@ protected void colorCalcARGB(int argb, float alpha) { calcAlpha = (calcAi != 255); } -} \ No newline at end of file +} diff --git a/core/src/processing/core/PShapeOBJ.java b/core/src/processing/core/PShapeOBJ.java index a46e6ab8a8..5ae8c9d1e9 100644 --- a/core/src/processing/core/PShapeOBJ.java +++ b/core/src/processing/core/PShapeOBJ.java @@ -327,7 +327,7 @@ static protected void parseMTL(PApplet parent, String mtlfn, String path, while ((line = reader.readLine()) != null) { // Parse the line line = line.trim(); - String parts[] = line.split("\\s+"); + String[] parts = line.split("\\s+"); if (parts.length > 0) { // Extract the material data. if (parts[0].equals("newmtl")) { diff --git a/core/src/processing/core/PShapeSVG.java b/core/src/processing/core/PShapeSVG.java index bf5cdc2f1f..f572406ebc 100644 --- a/core/src/processing/core/PShapeSVG.java +++ b/core/src/processing/core/PShapeSVG.java @@ -24,6 +24,9 @@ package processing.core; +import static java.awt.Font.BOLD; +import static java.awt.Font.ITALIC; +import static java.awt.Font.PLAIN; import processing.data.*; // TODO replace these with PMatrix2D @@ -32,6 +35,8 @@ import java.util.Map; import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** @@ -330,6 +335,10 @@ protected PShape parseChild(XML elem) { shape = createShape(this, elem, true); shape.parseRect(); + } else if (name.equals("image")) { + shape = createShape(this, elem, true); + shape.parseImage(); + } else if (name.equals("polygon")) { shape = createShape(this, elem, true); shape.parsePoly(true); @@ -358,8 +367,10 @@ protected PShape parseChild(XML elem) { // return new FontGlyph(this, elem); } else if (name.equals("text")) { // || name.equals("font")) { - PGraphics.showWarning("Text and fonts in SVG files are " + - "not currently supported, convert text to outlines instead."); + return new Text(this, elem); + + } else if (name.equals("tspan")) { + return new LineOfText(this, elem); } else if (name.equals("filter")) { PGraphics.showWarning("Filters are not supported."); @@ -441,6 +452,21 @@ protected void parseRect() { } + protected void parseImage() { + kind = RECT; + textureMode = NORMAL; + + family = PRIMITIVE; + params = new float[] { + getFloatWithUnit(element, "x", svgWidth), + getFloatWithUnit(element, "y", svgHeight), + getFloatWithUnit(element, "width", svgWidth), + getFloatWithUnit(element, "height", svgHeight) + }; + + this.imagePath = element.getString("xlink:href"); + } + /** * Parse a polyline or polygon from an SVG file. * Syntax defined at http://www.w3.org/TR/SVG/shapes.html#PointsBNF @@ -452,14 +478,27 @@ protected void parsePoly(boolean close) { String pointsAttr = element.getString("points"); if (pointsAttr != null) { - String[] pointsBuffer = PApplet.splitTokens(pointsAttr); - vertexCount = pointsBuffer.length; + Pattern pattern = Pattern.compile("([+-]?[\\d]+(\\.[\\d]+)?([eE][+-][\\d]+)?)(,?\\s*)([+-]?[\\d]+(\\.[\\d]+)?([eE][+-][\\d]+)?)"); + Matcher matcher = pattern.matcher(pointsAttr); + vertexCount = 0; + while (matcher.find()) { + vertexCount++; + } + matcher.reset(); vertices = new float[vertexCount][2]; for (int i = 0; i < vertexCount; i++) { - String pb[] = PApplet.splitTokens(pointsBuffer[i], ", \t\r\n"); - vertices[i][X] = Float.parseFloat(pb[0]); - vertices[i][Y] = Float.parseFloat(pb[1]); + matcher.find(); + vertices[i][X] = Float.parseFloat(matcher.group(1)); + vertices[i][Y] = Float.parseFloat(matcher.group(5)); } +// String[] pointsBuffer = PApplet.splitTokens(pointsAttr); +// vertexCount = pointsBuffer.length; +// vertices = new float[vertexCount][2]; +// for (int i = 0; i < vertexCount; i++) { +// String pb[] = PApplet.splitTokens(pointsBuffer[i], ", \t\r\n"); +// vertices[i][X] = Float.parseFloat(pb[0]); +// vertices[i][Y] = Float.parseFloat(pb[1]); +// } } } @@ -1460,7 +1499,7 @@ static public class Gradient extends PShapeSVG { public Gradient(PShapeSVG parent, XML properties) { super(parent, properties, true); - XML elements[] = properties.getChildren(); + XML[] elements = properties.getChildren(); offset = new float[elements.length]; color = new int[elements.length]; @@ -1498,7 +1537,10 @@ public Gradient(PShapeSVG parent, XML properties) { } - public class LinearGradient extends Gradient { + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public class LinearGradient extends Gradient { public float x1, y1, x2, y2; public LinearGradient(PShapeSVG parent, XML properties) { @@ -1513,7 +1555,7 @@ public LinearGradient(PShapeSVG parent, XML properties) { properties.getString("gradientTransform"); if (transformStr != null) { - float t[] = parseTransform(transformStr).get(null); + float[] t = parseTransform(transformStr).get(null); this.transform = new AffineTransform(t[0], t[3], t[1], t[4], t[2], t[5]); Point2D t1 = transform.transform(new Point2D.Float(x1, y1), null); @@ -1528,7 +1570,10 @@ public LinearGradient(PShapeSVG parent, XML properties) { } - public class RadialGradient extends Gradient { + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public class RadialGradient extends Gradient { public float cx, cy, r; public RadialGradient(PShapeSVG parent, XML properties) { @@ -1542,7 +1587,7 @@ public RadialGradient(PShapeSVG parent, XML properties) { properties.getString("gradientTransform"); if (transformStr != null) { - float t[] = parseTransform(transformStr).get(null); + float[] t = parseTransform(transformStr).get(null); this.transform = new AffineTransform(t[0], t[3], t[1], t[4], t[2], t[5]); Point2D t1 = transform.transform(new Point2D.Float(cx, cy), null); @@ -1559,7 +1604,179 @@ public RadialGradient(PShapeSVG parent, XML properties) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - public static class Font extends PShapeSVG { +// static private float TEXT_QUALITY = 1; + + static private PFont parseFont(XML properties) { + String fontFamily = null; + float size = 10; + int weight = PLAIN; // 0 + int italic = 0; + + if (properties.hasAttribute("style")) { + String styleText = properties.getString("style"); + String[] styleTokens = PApplet.splitTokens(styleText, ";"); + + //PApplet.println(styleTokens); + for (int i = 0; i < styleTokens.length; i++) { + String[] tokens = PApplet.splitTokens(styleTokens[i], ":"); + //PApplet.println(tokens); + + tokens[0] = PApplet.trim(tokens[0]); + + if (tokens[0].equals("font-style")) { + // PApplet.println("font-style: " + tokens[1]); + if (tokens[1].contains("italic")) { + italic = ITALIC; + } + } else if (tokens[0].equals("font-variant")) { + // PApplet.println("font-variant: " + tokens[1]); + // setFillOpacity(tokens[1]); + + } else if (tokens[0].equals("font-weight")) { + // PApplet.println("font-weight: " + tokens[1]); + + if (tokens[1].contains("bold")) { + weight = BOLD; + // PApplet.println("Bold weight ! "); + } + + + } else if (tokens[0].equals("font-stretch")) { + // not supported. + + } else if (tokens[0].equals("font-size")) { + // PApplet.println("font-size: " + tokens[1]); + size = Float.parseFloat(tokens[1].split("px")[0]); + // PApplet.println("font-size-parsed: " + size); + } else if (tokens[0].equals("line-height")) { + // not supported + + } else if (tokens[0].equals("font-family")) { + // PApplet.println("Font-family: " + tokens[1]); + fontFamily = tokens[1]; + + } else if (tokens[0].equals("text-align")) { + // not supported + + } else if (tokens[0].equals("letter-spacing")) { + // not supported + + } else if (tokens[0].equals("word-spacing")) { + // not supported + + } else if (tokens[0].equals("writing-mode")) { + // not supported + + } else if (tokens[0].equals("text-anchor")) { + // not supported + + } else { + // Other attributes are not yet implemented + } + } + } + if (fontFamily == null) { + return null; + } +// size = size * TEXT_QUALITY; + + return createFont(fontFamily, weight | italic, size, true); + } + + + static protected PFont createFont(String name, int weight, + float size, boolean smooth) { + //System.out.println("Try to create a font of " + name + " family, " + weight); + java.awt.Font baseFont = new java.awt.Font(name, weight, (int) size); + + //System.out.println("Resulting family : " + baseFont.getFamily() + " " + baseFont.getStyle()); + return new PFont(baseFont.deriveFont(size), smooth, null); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public class Text extends PShapeSVG { + protected PFont font; + + public Text(PShapeSVG parent, XML properties) { + super(parent, properties, true); + + // get location + float x = Float.parseFloat(properties.getString("x")); + float y = Float.parseFloat(properties.getString("y")); + + if (matrix == null) { + matrix = new PMatrix2D(); + } + matrix.translate(x, y); + + family = GROUP; + + font = parseFont(properties); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public class LineOfText extends PShapeSVG { + String textToDisplay; + PFont font; + + public LineOfText(PShapeSVG parent, XML properties) { + // TODO: child should ideally be parsed too for inline content. + super(parent, properties, false); + + //get location + float x = Float.parseFloat(properties.getString("x")); + float y = Float.parseFloat(properties.getString("y")); + + float parentX = Float.parseFloat(parent.element.getString("x")); + float parentY = Float.parseFloat(parent.element.getString("y")); + + if (matrix == null) matrix = new PMatrix2D(); + matrix.translate(x - parentX, (y - parentY) / 2f); + + // get the first properties + parseColors(properties); + font = parseFont(properties); + + // cleaned up syntax but removing b/c unused [fry 190118] + //boolean isLine = properties.getString("role").equals("line"); + + if (this.childCount > 0) { + // no inline content yet. + } + + String text = properties.getContent(); + textToDisplay = text; + } + + @Override + public void drawImpl(PGraphics g) { + if (font == null) { + font = ((Text) parent).font; + if (font == null) { + return; + } + } + + pre(g); +// g.textFont(font, font.size / TEXT_QUALITY); + g.textFont(font, font.size); + g.text(textToDisplay, 0, 0); + post(g); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + static public class Font extends PShapeSVG { public FontFace face; public Map namedGlyphs; @@ -1580,8 +1797,8 @@ public Font(PShapeSVG parent, XML properties) { horizAdvX = properties.getInt("horiz-adv-x", 0); - namedGlyphs = new HashMap(); - unicodeGlyphs = new HashMap(); + namedGlyphs = new HashMap<>(); + unicodeGlyphs = new HashMap<>(); glyphCount = 0; glyphs = new FontGlyph[elements.length]; @@ -1710,7 +1927,7 @@ protected void drawShape() { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - public static class FontGlyph extends PShapeSVG { // extends Path + static public class FontGlyph extends PShapeSVG { // extends Path public String name; char unicode; int horizAdvX; diff --git a/core/src/processing/core/PSurfaceNone.java b/core/src/processing/core/PSurfaceNone.java index 7b5a17f570..f86ac0cde9 100644 --- a/core/src/processing/core/PSurfaceNone.java +++ b/core/src/processing/core/PSurfaceNone.java @@ -58,10 +58,7 @@ public void initOffscreen(PApplet sketch) { @Override - public void initFrame(PApplet sketch) {/*, int backgroundColor, - int deviceIndex, boolean fullScreen, - boolean spanDisplays) {*/ - //this.sketch = sketch; + public void initFrame(PApplet sketch) { throw new IllegalStateException("initFrame() not available with " + getClass().getSimpleName()); } @@ -207,7 +204,7 @@ public boolean stopThread() { public boolean isStopped() { - return thread == null; + return thread == null || !thread.isAlive(); } diff --git a/core/src/processing/core/PVector.java b/core/src/processing/core/PVector.java index b4382de89a..9c0b65e841 100644 --- a/core/src/processing/core/PVector.java +++ b/core/src/processing/core/PVector.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2012-17 The Processing Foundation Copyright (c) 2008-12 Ben Fry and Casey Reas Copyright (c) 2008 Dan Shiffman @@ -26,8 +26,6 @@ import java.io.Serializable; -import processing.core.PApplet; -import processing.core.PConstants; /** * ( begin auto-generated from PVector.xml ) @@ -142,7 +140,6 @@ public PVector(float x, float y, float z) { public PVector(float x, float y) { this.x = x; this.y = y; - this.z = 0; } @@ -175,6 +172,7 @@ public PVector set(float x, float y, float z) { public PVector set(float x, float y) { this.x = x; this.y = y; + this.z = 0; return this; } @@ -201,6 +199,8 @@ public PVector set(float[] source) { } if (source.length >= 3) { z = source[2]; + } else { + z = 0; } return this; } diff --git a/core/src/processing/core/ThinkDifferent.java b/core/src/processing/core/ThinkDifferent.java index 38637c559d..8596696198 100644 --- a/core/src/processing/core/ThinkDifferent.java +++ b/core/src/processing/core/ThinkDifferent.java @@ -71,6 +71,12 @@ public void handleQuitRequestWith(QuitEvent event, QuitResponse response) { }); } + static public void cleanup() { + if (application == null) { + application = Application.getApplication(); + } + application.setQuitHandler(null); + } // Called via reflection from PSurfaceAWT and others static public void setIconImage(Image image) { diff --git a/core/src/processing/data/DoubleDict.java b/core/src/processing/data/DoubleDict.java new file mode 100644 index 0000000000..5cec4d6e18 --- /dev/null +++ b/core/src/processing/data/DoubleDict.java @@ -0,0 +1,850 @@ +package processing.data; + +import java.io.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import processing.core.PApplet; + + +/** + * A simple table class to use a String as a lookup for an double value. + * + * @nowebref + * @see IntDict + * @see StringDict + */ +public class DoubleDict { + + /** Number of elements in the table */ + protected int count; + + protected String[] keys; + protected double[] values; + + /** Internal implementation for faster lookups */ + private HashMap indices = new HashMap<>(); + + + public DoubleDict() { + count = 0; + keys = new String[10]; + values = new double[10]; + } + + + /** + * Create a new lookup with a specific size. This is more efficient than not + * specifying a size. Use it when you know the rough size of the thing you're creating. + * + * @nowebref + */ + public DoubleDict(int length) { + count = 0; + keys = new String[length]; + values = new double[length]; + } + + + /** + * Read a set of entries from a Reader that has each key/value pair on + * a single line, separated by a tab. + * + * @nowebref + */ + public DoubleDict(BufferedReader reader) { + String[] lines = PApplet.loadStrings(reader); + keys = new String[lines.length]; + values = new double[lines.length]; + + for (int i = 0; i < lines.length; i++) { + String[] pieces = PApplet.split(lines[i], '\t'); + if (pieces.length == 2) { + keys[count] = pieces[0]; + values[count] = PApplet.parseFloat(pieces[1]); + indices.put(pieces[0], count); + count++; + } + } + } + + + /** + * @nowebref + */ + public DoubleDict(String[] keys, double[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException("key and value arrays must be the same length"); + } + this.keys = keys; + this.values = values; + count = keys.length; + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + /** + * Constructor to allow (more intuitive) inline initialization, e.g.: + *
+   * new FloatDict(new Object[][] {
+   *   { "key1", 1 },
+   *   { "key2", 2 }
+   * });
+   * 
+ */ + public DoubleDict(Object[][] pairs) { + count = pairs.length; + this.keys = new String[count]; + this.values = new double[count]; + for (int i = 0; i < count; i++) { + keys[i] = (String) pairs[i][0]; + values[i] = (Float) pairs[i][1]; + indices.put(keys[i], i); + } + } + + + public DoubleDict(Map incoming) { + count = incoming.size(); + keys = new String[count]; + values = new double[count]; + int index = 0; + for (Map.Entry e : incoming.entrySet()) { + keys[index] = e.getKey(); + values[index] = e.getValue(); + indices.put(keys[index], index); + index++; + } + } + + + /** + * @webref doubledict:method + * @brief Returns the number of key/value pairs + */ + public int size() { + return count; + } + + + /** + * Resize the internal data, this can only be used to shrink the list. + * Helpful for situations like sorting and then grabbing the top 50 entries. + */ + public void resize(int length) { + if (length == count) return; + + if (length > count) { + throw new IllegalArgumentException("resize() can only be used to shrink the dictionary"); + } + if (length < 1) { + throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher"); + } + + String[] newKeys = new String[length]; + double[] newValues = new double[length]; + PApplet.arrayCopy(keys, newKeys, length); + PApplet.arrayCopy(values, newValues, length); + keys = newKeys; + values = newValues; + count = length; + resetIndices(); + } + + + /** + * Remove all entries. + * + * @webref doubledict:method + * @brief Remove all entries + */ + public void clear() { + count = 0; + indices = new HashMap<>(); + } + + + private void resetIndices() { + indices = new HashMap<>(count); + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public class Entry { + public String key; + public double value; + + Entry(String key, double value) { + this.key = key; + this.value = value; + } + } + + + public Iterable entries() { + return new Iterable() { + + public Iterator iterator() { + return entryIterator(); + } + }; + } + + + public Iterator entryIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Entry next() { + ++index; + Entry e = new Entry(keys[index], values[index]); + return e; + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public String key(int index) { + return keys[index]; + } + + + protected void crop() { + if (count != keys.length) { + keys = PApplet.subset(keys, 0, count); + values = PApplet.subset(values, 0, count); + } + } + + + public Iterable keys() { + return new Iterable() { + + @Override + public Iterator iterator() { + return keyIterator(); + } + }; + } + + + // Use this to iterate when you want to be able to remove elements along the way + public Iterator keyIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public String next() { + return key(++index); + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + /** + * Return a copy of the internal keys array. This array can be modified. + * + * @webref doubledict:method + * @brief Return a copy of the internal keys array + */ + public String[] keyArray() { + crop(); + return keyArray(null); + } + + + public String[] keyArray(String[] outgoing) { + if (outgoing == null || outgoing.length != count) { + outgoing = new String[count]; + } + System.arraycopy(keys, 0, outgoing, 0, count); + return outgoing; + } + + + public double value(int index) { + return values[index]; + } + + + /** + * @webref doubledict:method + * @brief Return the internal array being used to store the values + */ + public Iterable values() { + return new Iterable() { + + @Override + public Iterator iterator() { + return valueIterator(); + } + }; + } + + + public Iterator valueIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Double next() { + return value(++index); + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + /** + * Create a new array and copy each of the values into it. + * + * @webref doubledict:method + * @brief Create a new array and copy each of the values into it + */ + public double[] valueArray() { + crop(); + return valueArray(null); + } + + + /** + * Fill an already-allocated array with the values (more efficient than + * creating a new array each time). If 'array' is null, or not the same + * size as the number of values, a new array will be allocated and returned. + */ + public double[] valueArray(double[] array) { + if (array == null || array.length != size()) { + array = new double[count]; + } + System.arraycopy(values, 0, array, 0, count); + return array; + } + + + /** + * Return a value for the specified key. + * + * @webref doubledict:method + * @brief Return a value for the specified key + */ + public double get(String key) { + int index = index(key); + if (index == -1) { + throw new IllegalArgumentException("No key named '" + key + "'"); + } + return values[index]; + } + + + public double get(String key, double alternate) { + int index = index(key); + if (index == -1) { + return alternate; + } + return values[index]; + } + + + /** + * @webref doubledict:method + * @brief Create a new key/value pair or change the value of one + */ + public void set(String key, double amount) { + int index = index(key); + if (index == -1) { + create(key, amount); + } else { + values[index] = amount; + } + } + + + public void setIndex(int index, String key, double value) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + keys[index] = key; + values[index] = value; + } + + + /** + * @webref doubledict:method + * @brief Check if a key is a part of the data structure + */ + public boolean hasKey(String key) { + return index(key) != -1; + } + + + /** + * @webref doubledict:method + * @brief Add to a value + */ + public void add(String key, double amount) { + int index = index(key); + if (index == -1) { + create(key, amount); + } else { + values[index] += amount; + } + } + + + /** + * @webref doubledict:method + * @brief Subtract from a value + */ + public void sub(String key, double amount) { + add(key, -amount); + } + + + /** + * @webref doubledict:method + * @brief Multiply a value + */ + public void mult(String key, double amount) { + int index = index(key); + if (index != -1) { + values[index] *= amount; + } + } + + + /** + * @webref doubledict:method + * @brief Divide a value + */ + public void div(String key, double amount) { + int index = index(key); + if (index != -1) { + values[index] /= amount; + } + } + + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + /** + * @webref doublelist:method + * @brief Return the smallest value + */ + public int minIndex() { + //checkMinMax("minIndex"); + if (count == 0) return -1; + + // Will still return NaN if there are 1 or more entries, and they're all NaN + double m = Float.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (values[i] == values[i]) { + m = values[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + double d = values[j]; + if ((d == d) && (d < m)) { + m = values[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + // return the key for the minimum value + public String minKey() { + checkMinMax("minKey"); + int index = minIndex(); + if (index == -1) { + return null; + } + return keys[index]; + } + + + // return the minimum value, or throw an error if there are no values + public double minValue() { + checkMinMax("minValue"); + int index = minIndex(); + if (index == -1) { + return Float.NaN; + } + return values[index]; + } + + + /** + * @webref doublelist:method + * @brief Return the largest value + */ + // The index of the entry that has the max value. Reference above is incorrect. + public int maxIndex() { + //checkMinMax("maxIndex"); + if (count == 0) { + return -1; + } + // Will still return NaN if there is 1 or more entries, and they're all NaN + double m = Double.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (values[i] == values[i]) { + m = values[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + double d = values[j]; + if (!Double.isNaN(d) && (d > m)) { + m = values[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + /** The key for a max value; null if empty or everything is NaN (no max). */ + public String maxKey() { + //checkMinMax("maxKey"); + int index = maxIndex(); + if (index == -1) { + return null; + } + return keys[index]; + } + + + /** The max value. (Or NaN if no entries or they're all NaN.) */ + public double maxValue() { + //checkMinMax("maxValue"); + int index = maxIndex(); + if (index == -1) { + return Float.NaN; + } + return values[index]; + } + + + public double sum() { + double sum = 0; + for (int i = 0; i < count; i++) { + sum += values[i]; + } + return sum; + } + + + public int index(String what) { + Integer found = indices.get(what); + return (found == null) ? -1 : found.intValue(); + } + + + protected void create(String what, double much) { + if (count == keys.length) { + keys = PApplet.expand(keys); + values = PApplet.expand(values); + } + indices.put(what, Integer.valueOf(count)); + keys[count] = what; + values[count] = much; + count++; + } + + + /** + * @webref doubledict:method + * @brief Remove a key/value pair + */ + public double remove(String key) { + int index = index(key); + if (index == -1) { + throw new NoSuchElementException("'" + key + "' not found"); + } + double value = values[index]; + removeIndex(index); + return value; + } + + + public double removeIndex(int index) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + double value = values[index]; + indices.remove(keys[index]); + for (int i = index; i < count-1; i++) { + keys[i] = keys[i+1]; + values[i] = values[i+1]; + indices.put(keys[i], i); + } + count--; + keys[count] = null; + values[count] = 0; + return value; + } + + + public void swap(int a, int b) { + String tkey = keys[a]; + double tvalue = values[a]; + keys[a] = keys[b]; + values[a] = values[b]; + keys[b] = tkey; + values[b] = tvalue; + +// indices.put(keys[a], Integer.valueOf(a)); +// indices.put(keys[b], Integer.valueOf(b)); + } + + + /** + * Sort the keys alphabetically (ignoring case). Uses the value as a + * tie-breaker (only really possible with a key that has a case change). + * + * @webref doubledict:method + * @brief Sort the keys alphabetically + */ + public void sortKeys() { + sortImpl(true, false, true); + } + + + /** + * @webref doubledict:method + * @brief Sort the keys alphabetically in reverse + */ + public void sortKeysReverse() { + sortImpl(true, true, true); + } + + + /** + * Sort by values in descending order (largest value will be at [0]). + * + * @webref doubledict:method + * @brief Sort by values in ascending order + */ + public void sortValues() { + sortValues(true); + } + + + /** + * Set true to ensure that the order returned is identical. Slightly + * slower because the tie-breaker for identical values compares the keys. + * @param stable + */ + public void sortValues(boolean stable) { + sortImpl(false, false, stable); + } + + + /** + * @webref doubledict:method + * @brief Sort by values in descending order + */ + public void sortValuesReverse() { + sortValuesReverse(true); + } + + + public void sortValuesReverse(boolean stable) { + sortImpl(false, true, stable); + } + + + protected void sortImpl(final boolean useKeys, final boolean reverse, + final boolean stable) { + Sort s = new Sort() { + @Override + public int size() { + if (useKeys) { + return count; // don't worry about NaN values + + } else if (count == 0) { // skip the NaN check, it'll AIOOBE + return 0; + + } else { // first move NaN values to the end of the list + int right = count - 1; + while (values[right] != values[right]) { + right--; + if (right == -1) { + return 0; // all values are NaN + } + } + for (int i = right; i >= 0; --i) { + if (Double.isNaN(values[i])) { + swap(i, right); + --right; + } + } + return right + 1; + } + } + + @Override + public int compare(int a, int b) { + double diff = 0; + if (useKeys) { + diff = keys[a].compareToIgnoreCase(keys[b]); + if (diff == 0) { + diff = values[a] - values[b]; + } + } else { // sort values + diff = values[a] - values[b]; + if (diff == 0 && stable) { + diff = keys[a].compareToIgnoreCase(keys[b]); + } + } + if (diff == 0) { + return 0; + } else if (reverse) { + return diff < 0 ? 1 : -1; + } else { + return diff < 0 ? -1 : 1; + } + } + + @Override + public void swap(int a, int b) { + DoubleDict.this.swap(a, b); + } + }; + s.run(); + + // Set the indices after sort/swaps (performance fix 160411) + resetIndices(); + } + + + /** + * Sum all of the values in this dictionary, then return a new FloatDict of + * each key, divided by the total sum. The total for all values will be ~1.0. + * @return a FloatDict with the original keys, mapped to their pct of the total + */ + public DoubleDict getPercent() { + double sum = sum(); + DoubleDict outgoing = new DoubleDict(); + for (int i = 0; i < size(); i++) { + double percent = value(i) / sum; + outgoing.set(key(i), percent); + } + return outgoing; + } + + + /** Returns a duplicate copy of this object. */ + public DoubleDict copy() { + DoubleDict outgoing = new DoubleDict(count); + System.arraycopy(keys, 0, outgoing.keys, 0, count); + System.arraycopy(values, 0, outgoing.values, 0, count); + for (int i = 0; i < count; i++) { + outgoing.indices.put(keys[i], i); + } + outgoing.count = count; + return outgoing; + } + + + public void print() { + for (int i = 0; i < size(); i++) { + System.out.println(keys[i] + " = " + values[i]); + } + } + + + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write tab-delimited entries out to + * @param writer + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(keys[i] + "\t" + values[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + StringList items = new StringList(); + for (int i = 0; i < count; i++) { + items.append(JSONObject.quote(keys[i])+ ": " + values[i]); + } + return "{ " + items.join(", ") + " }"; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); + } +} diff --git a/core/src/processing/data/DoubleList.java b/core/src/processing/data/DoubleList.java new file mode 100644 index 0000000000..6c364130c9 --- /dev/null +++ b/core/src/processing/data/DoubleList.java @@ -0,0 +1,928 @@ +package processing.data; + +import java.io.File; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Random; + +import processing.core.PApplet; + + +/** + * Helper class for a list of floats. Lists are designed to have some of the + * features of ArrayLists, but to maintain the simplicity and efficiency of + * working with arrays. + * + * Functions like sort() and shuffle() always act on the list itself. To get + * a sorted copy, use list.copy().sort(). + * + * @nowebref + * @see IntList + * @see StringList + */ +public class DoubleList implements Iterable { + int count; + double[] data; + + + public DoubleList() { + data = new double[10]; + } + + + /** + * @nowebref + */ + public DoubleList(int length) { + data = new double[length]; + } + + + /** + * @nowebref + */ + public DoubleList(double[] list) { + count = list.length; + data = new double[count]; + System.arraycopy(list, 0, data, 0, count); + } + + + /** + * Construct an FloatList from an iterable pile of objects. + * For instance, a double array, an array of strings, who knows). + * Un-parseable or null values will be set to NaN. + * @nowebref + */ + public DoubleList(Iterable iter) { + this(10); + for (Object o : iter) { + if (o == null) { + append(Double.NaN); + } else if (o instanceof Number) { + append(((Number) o).doubleValue()); + } else { + append(PApplet.parseFloat(o.toString().trim())); + } + } + crop(); + } + + + /** + * Construct an FloatList from a random pile of objects. + * Un-parseable or null values will be set to NaN. + */ + public DoubleList(Object... items) { + // nuts, no good way to pass missingValue to this fn (varargs must be last) + final double missingValue = Double.NaN; + + count = items.length; + data = new double[count]; + int index = 0; + for (Object o : items) { + double value = missingValue; + if (o != null) { + if (o instanceof Number) { + value = ((Number) o).doubleValue(); + } else { + try { + value = Double.parseDouble(o.toString().trim()); + } catch (NumberFormatException nfe) { + value = missingValue; + } + } + } + data[index++] = value; + } + } + + + /** + * Improve efficiency by removing allocated but unused entries from the + * internal array used to store the data. Set to private, though it could + * be useful to have this public if lists are frequently making drastic + * size changes (from very large to very small). + */ + private void crop() { + if (count != data.length) { + data = PApplet.subset(data, 0, count); + } + } + + + /** + * Get the length of the list. + * + * @webref doublelist:method + * @brief Get the length of the list + */ + public int size() { + return count; + } + + + public void resize(int length) { + if (length > data.length) { + double[] temp = new double[length]; + System.arraycopy(data, 0, temp, 0, count); + data = temp; + + } else if (length > count) { + Arrays.fill(data, count, length, 0); + } + count = length; + } + + + /** + * Remove all entries from the list. + * + * @webref doublelist:method + * @brief Remove all entries from the list + */ + public void clear() { + count = 0; + } + + + /** + * Get an entry at a particular index. + * + * @webref doublelist:method + * @brief Get an entry at a particular index + */ + public double get(int index) { + if (index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + return data[index]; + } + + + /** + * Set the entry at a particular index. If the index is past the length of + * the list, it'll expand the list to accommodate, and fill the intermediate + * entries with 0s. + * + * @webref doublelist:method + * @brief Set the entry at a particular index + */ + public void set(int index, double what) { + if (index >= count) { + data = PApplet.expand(data, index+1); + for (int i = count; i < index; i++) { + data[i] = 0; + } + count = index+1; + } + data[index] = what; + } + + + /** Just an alias for append(), but matches pop() */ + public void push(double value) { + append(value); + } + + + public double pop() { + if (count == 0) { + throw new RuntimeException("Can't call pop() on an empty list"); + } + double value = get(count-1); + count--; + return value; + } + + + /** + * Remove an element from the specified index. + * + * @webref doublelist:method + * @brief Remove an element from the specified index + */ + public double remove(int index) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + double entry = data[index]; +// int[] outgoing = new int[count - 1]; +// System.arraycopy(data, 0, outgoing, 0, index); +// count--; +// System.arraycopy(data, index + 1, outgoing, 0, count - index); +// data = outgoing; + // For most cases, this actually appears to be faster + // than arraycopy() on an array copying into itself. + for (int i = index; i < count-1; i++) { + data[i] = data[i+1]; + } + count--; + return entry; + } + + + // Remove the first instance of a particular value, + // and return the index at which it was found. + public int removeValue(int value) { + int index = index(value); + if (index != -1) { + remove(index); + return index; + } + return -1; + } + + + // Remove all instances of a particular value, + // and return the number of values found and removed + public int removeValues(int value) { + int ii = 0; + if (Double.isNaN(value)) { + for (int i = 0; i < count; i++) { + if (!Double.isNaN(data[i])) { + data[ii++] = data[i]; + } + } + } else { + for (int i = 0; i < count; i++) { + if (data[i] != value) { + data[ii++] = data[i]; + } + } + } + int removed = count - ii; + count = ii; + return removed; + } + + + /** Replace the first instance of a particular value */ + public boolean replaceValue(double value, double newValue) { + if (Double.isNaN(value)) { + for (int i = 0; i < count; i++) { + if (Double.isNaN(data[i])) { + data[i] = newValue; + return true; + } + } + } else { + int index = index(value); + if (index != -1) { + data[index] = newValue; + return true; + } + } + return false; + } + + + /** Replace all instances of a particular value */ + public boolean replaceValues(double value, double newValue) { + boolean changed = false; + if (Double.isNaN(value)) { + for (int i = 0; i < count; i++) { + if (Double.isNaN(data[i])) { + data[i] = newValue; + changed = true; + } + } + } else { + for (int i = 0; i < count; i++) { + if (data[i] == value) { + data[i] = newValue; + changed = true; + } + } + } + return changed; + } + + + + /** + * Add a new entry to the list. + * + * @webref doublelist:method + * @brief Add a new entry to the list + */ + public void append(double value) { + if (count == data.length) { + data = PApplet.expand(data); + } + data[count++] = value; + } + + + public void append(double[] values) { + for (double v : values) { + append(v); + } + } + + + public void append(DoubleList list) { + for (double v : list.values()) { // will concat the list... + append(v); + } + } + + + /** Add this value, but only if it's not already in the list. */ + public void appendUnique(double value) { + if (!hasValue(value)) { + append(value); + } + } + + +// public void insert(int index, int value) { +// if (index+1 > count) { +// if (index+1 < data.length) { +// } +// } +// if (index >= data.length) { +// data = PApplet.expand(data, index+1); +// data[index] = value; +// count = index+1; +// +// } else if (count == data.length) { +// if (index >= count) { +// //int[] temp = new int[count << 1]; +// System.arraycopy(data, 0, temp, 0, index); +// temp[index] = value; +// System.arraycopy(data, index, temp, index+1, count - index); +// data = temp; +// +// } else { +// // data[] has room to grow +// // for() loop believed to be faster than System.arraycopy over itself +// for (int i = count; i > index; --i) { +// data[i] = data[i-1]; +// } +// data[index] = value; +// count++; +// } +// } + + + public void insert(int index, double value) { + insert(index, new double[] { value }); + } + + + // same as splice + public void insert(int index, double[] values) { + if (index < 0) { + throw new IllegalArgumentException("insert() index cannot be negative: it was " + index); + } + if (index >= data.length) { + throw new IllegalArgumentException("insert() index " + index + " is past the end of this list"); + } + + double[] temp = new double[count + values.length]; + + // Copy the old values, but not more than already exist + System.arraycopy(data, 0, temp, 0, Math.min(count, index)); + + // Copy the new values into the proper place + System.arraycopy(values, 0, temp, index, values.length); + +// if (index < count) { + // The index was inside count, so it's a true splice/insert + System.arraycopy(data, index, temp, index+values.length, count - index); + count = count + values.length; +// } else { +// // The index was past 'count', so the new count is weirder +// count = index + values.length; +// } + data = temp; + } + + + public void insert(int index, DoubleList list) { + insert(index, list.values()); + } + + + // below are aborted attempts at more optimized versions of the code + // that are harder to read and debug... + +// if (index + values.length >= count) { +// // We're past the current 'count', check to see if we're still allocated +// // index 9, data.length = 10, values.length = 1 +// if (index + values.length < data.length) { +// // There's still room for these entries, even though it's past 'count'. +// // First clear out the entries leading up to it, however. +// for (int i = count; i < index; i++) { +// data[i] = 0; +// } +// data[index] = +// } +// if (index >= data.length) { +// int length = index + values.length; +// int[] temp = new int[length]; +// System.arraycopy(data, 0, temp, 0, count); +// System.arraycopy(values, 0, temp, index, values.length); +// data = temp; +// count = data.length; +// } else { +// +// } +// +// } else if (count == data.length) { +// int[] temp = new int[count << 1]; +// System.arraycopy(data, 0, temp, 0, index); +// temp[index] = value; +// System.arraycopy(data, index, temp, index+1, count - index); +// data = temp; +// +// } else { +// // data[] has room to grow +// // for() loop believed to be faster than System.arraycopy over itself +// for (int i = count; i > index; --i) { +// data[i] = data[i-1]; +// } +// data[index] = value; +// count++; +// } + + + /** Return the first index of a particular value. */ + public int index(double what) { + /* + if (indexCache != null) { + try { + return indexCache.get(what); + } catch (Exception e) { // not there + return -1; + } + } + */ + for (int i = 0; i < count; i++) { + if (data[i] == what) { + return i; + } + } + return -1; + } + + + /** + * @webref doublelist:method + * @brief Check if a number is a part of the list + */ + public boolean hasValue(double value) { + if (Double.isNaN(value)) { + for (int i = 0; i < count; i++) { + if (Double.isNaN(data[i])) { + return true; + } + } + } else { + for (int i = 0; i < count; i++) { + if (data[i] == value) { + return true; + } + } + } + return false; + } + + + private void boundsProblem(int index, String method) { + final String msg = String.format("The list size is %d. " + + "You cannot %s() to element %d.", count, method, index); + throw new ArrayIndexOutOfBoundsException(msg); + } + + + /** + * @webref doublelist:method + * @brief Add to a value + */ + public void add(int index, double amount) { + if (index < count) { + data[index] += amount; + } else { + boundsProblem(index, "add"); + } + } + + + /** + * @webref doublelist:method + * @brief Subtract from a value + */ + public void sub(int index, double amount) { + if (index < count) { + data[index] -= amount; + } else { + boundsProblem(index, "sub"); + } + } + + + /** + * @webref doublelist:method + * @brief Multiply a value + */ + public void mult(int index, double amount) { + if (index < count) { + data[index] *= amount; + } else { + boundsProblem(index, "mult"); + } + } + + + /** + * @webref doublelist:method + * @brief Divide a value + */ + public void div(int index, double amount) { + if (index < count) { + data[index] /= amount; + } else { + boundsProblem(index, "div"); + } + } + + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + /** + * @webref doublelist:method + * @brief Return the smallest value + */ + public double min() { + checkMinMax("min"); + int index = minIndex(); + return index == -1 ? Double.NaN : data[index]; + } + + + public int minIndex() { + checkMinMax("minIndex"); + double m = Double.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (data[i] == data[i]) { + m = data[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + double d = data[j]; + if (!Double.isNaN(d) && (d < m)) { + m = data[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + /** + * @webref doublelist:method + * @brief Return the largest value + */ + public double max() { + checkMinMax("max"); + int index = maxIndex(); + return index == -1 ? Double.NaN : data[index]; + } + + + public int maxIndex() { + checkMinMax("maxIndex"); + double m = Double.NaN; + int mi = -1; + for (int i = 0; i < count; i++) { + // find one good value to start + if (data[i] == data[i]) { + m = data[i]; + mi = i; + + // calculate the rest + for (int j = i+1; j < count; j++) { + double d = data[j]; + if (!Double.isNaN(d) && (d > m)) { + m = data[j]; + mi = j; + } + } + break; + } + } + return mi; + } + + + public double sum() { + double sum = 0; + for (int i = 0; i < count; i++) { + sum += data[i]; + } + return sum; + } + + + /** + * Sorts the array in place. + * + * @webref doublelist:method + * @brief Sorts an array, lowest to highest + */ + public void sort() { + Arrays.sort(data, 0, count); + } + + + /** + * Reverse sort, orders values from highest to lowest + * + * @webref doublelist:method + * @brief Reverse sort, orders values from highest to lowest + */ + public void sortReverse() { + new Sort() { + @Override + public int size() { + // if empty, don't even mess with the NaN check, it'll AIOOBE + if (count == 0) { + return 0; + } + // move NaN values to the end of the list and don't sort them + int right = count - 1; + while (data[right] != data[right]) { + right--; + if (right == -1) { // all values are NaN + return 0; + } + } + for (int i = right; i >= 0; --i) { + double v = data[i]; + if (v != v) { + data[i] = data[right]; + data[right] = v; + --right; + } + } + return right + 1; + } + + @Override + public int compare(int a, int b) { + double diff = data[b] - data[a]; + return diff == 0 ? 0 : (diff < 0 ? -1 : 1); + } + + @Override + public void swap(int a, int b) { + double temp = data[a]; + data[a] = data[b]; + data[b] = temp; + } + }.run(); + } + + + // use insert() +// public void splice(int index, int value) { +// } + + +// public void subset(int start) { +// subset(start, count - start); +// } + + +// public void subset(int start, int num) { +// for (int i = 0; i < num; i++) { +// data[i] = data[i+start]; +// } +// count = num; +// } + + + /** + * @webref doublelist:method + * @brief Reverse the order of the list elements + */ + public void reverse() { + int ii = count - 1; + for (int i = 0; i < count/2; i++) { + double t = data[i]; + data[i] = data[ii]; + data[ii] = t; + --ii; + } + } + + + /** + * Randomize the order of the list elements. Note that this does not + * obey the randomSeed() function in PApplet. + * + * @webref doublelist:method + * @brief Randomize the order of the list elements + */ + public void shuffle() { + Random r = new Random(); + int num = count; + while (num > 1) { + int value = r.nextInt(num); + num--; + double temp = data[num]; + data[num] = data[value]; + data[value] = temp; + } + } + + + /** + * Randomize the list order using the random() function from the specified + * sketch, allowing shuffle() to use its current randomSeed() setting. + */ + public void shuffle(PApplet sketch) { + int num = count; + while (num > 1) { + int value = (int) sketch.random(num); + num--; + double temp = data[num]; + data[num] = data[value]; + data[value] = temp; + } + } + + + public DoubleList copy() { + DoubleList outgoing = new DoubleList(data); + outgoing.count = count; + return outgoing; + } + + + /** + * Returns the actual array being used to store the data. For advanced users, + * this is the fastest way to access a large list. Suitable for iterating + * with a for() loop, but modifying the list will have terrible consequences. + */ + public double[] values() { + crop(); + return data; + } + + + /** Implemented this way so that we can use a FloatList in a for loop. */ + @Override + public Iterator iterator() { +// } +// +// +// public Iterator valueIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + DoubleList.this.remove(index); + index--; + } + + public Double next() { + return data[++index]; + } + + public boolean hasNext() { + return index+1 < count; + } + }; + } + + + /** + * Create a new array with a copy of all the values. + * @return an array sized by the length of the list with each of the values. + * @webref doublelist:method + * @brief Create a new array with a copy of all the values + */ + public double[] array() { + return array(null); + } + + + /** + * Copy values into the specified array. If the specified array is null or + * not the same size, a new array will be allocated. + * @param array + */ + public double[] array(double[] array) { + if (array == null || array.length != count) { + array = new double[count]; + } + System.arraycopy(data, 0, array, 0, count); + return array; + } + + + /** + * Returns a normalized version of this array. Called getPercent() for + * consistency with the Dict classes. It's a getter method because it needs + * to returns a new list (because IntList/Dict can't do percentages or + * normalization in place on int values). + */ + public DoubleList getPercent() { + double sum = 0; + for (double value : array()) { + sum += value; + } + DoubleList outgoing = new DoubleList(count); + for (int i = 0; i < count; i++) { + double percent = data[i] / sum; + outgoing.set(i, percent); + } + return outgoing; + } + + + public DoubleList getSubset(int start) { + return getSubset(start, count - start); + } + + + public DoubleList getSubset(int start, int num) { + double[] subset = new double[num]; + System.arraycopy(data, start, subset, 0, num); + return new DoubleList(subset); + } + + + public String join(String separator) { + if (count == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(); + sb.append(data[0]); + for (int i = 1; i < count; i++) { + sb.append(separator); + sb.append(data[i]); + } + return sb.toString(); + } + + + public void print() { + for (int i = 0; i < count; i++) { + System.out.format("[%d] %f%n", i, data[i]); + } + } + + + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write entries to a PrintWriter, one per line + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(data[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + return "[ " + join(", ") + " ]"; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); + } +} diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java index cfb9adc996..9495563ad0 100644 --- a/core/src/processing/data/FloatDict.java +++ b/core/src/processing/data/FloatDict.java @@ -3,6 +3,7 @@ import java.io.*; import java.util.HashMap; import java.util.Iterator; +import java.util.NoSuchElementException; import processing.core.PApplet; @@ -23,7 +24,7 @@ public class FloatDict { protected float[] values; /** Internal implementation for faster lookups */ - private HashMap indices = new HashMap(); + private HashMap indices = new HashMap<>(); public FloatDict() { @@ -115,6 +116,31 @@ public int size() { } + /** + * Resize the internal data, this can only be used to shrink the list. + * Helpful for situations like sorting and then grabbing the top 50 entries. + */ + public void resize(int length) { + if (length == count) return; + + if (length > count) { + throw new IllegalArgumentException("resize() can only be used to shrink the dictionary"); + } + if (length < 1) { + throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher"); + } + + String[] newKeys = new String[length]; + float[] newValues = new float[length]; + PApplet.arrayCopy(keys, newKeys, length); + PApplet.arrayCopy(values, newValues, length); + keys = newKeys; + values = newValues; + count = length; + resetIndices(); + } + + /** * Remove all entries. * @@ -123,10 +149,67 @@ public int size() { */ public void clear() { count = 0; - indices = new HashMap(); + indices = new HashMap<>(); + } + + + private void resetIndices() { + indices = new HashMap<>(count); + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public class Entry { + public String key; + public float value; + + Entry(String key, float value) { + this.key = key; + this.value = value; + } + } + + + public Iterable entries() { + return new Iterable() { + + public Iterator iterator() { + return entryIterator(); + } + }; + } + + + public Iterator entryIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Entry next() { + ++index; + Entry e = new Entry(keys[index], values[index]); + return e; + } + + public boolean hasNext() { + return index+1 < size(); + } + }; } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + public String key(int index) { return keys[index]; } @@ -149,8 +232,8 @@ public Iterator iterator() { } }; } - - + + // Use this to iterate when you want to be able to remove elements along the way public Iterator keyIterator() { return new Iterator() { @@ -211,8 +294,8 @@ public Iterator iterator() { } }; } - - + + public Iterator valueIterator() { return new Iterator() { int index = -1; @@ -297,6 +380,15 @@ public void set(String key, float amount) { } + public void setIndex(int index, String key, float value) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + keys[index] = key; + values[index] = value; + } + + /** * @webref floatdict:method * @brief Check if a key is a part of the data structure @@ -370,7 +462,7 @@ private void checkMinMax(String functionName) { public int minIndex() { //checkMinMax("minIndex"); if (count == 0) return -1; - + // Will still return NaN if there are 1 or more entries, and they're all NaN float m = Float.NaN; int mi = -1; @@ -473,6 +565,27 @@ public float maxValue() { } + public float sum() { + double amount = sumDouble(); + if (amount > Float.MAX_VALUE) { + throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()"); + } + if (amount < -Float.MAX_VALUE) { + throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()"); + } + return (float) amount; + } + + + public double sumDouble() { + double sum = 0; + for (int i = 0; i < count; i++) { + sum += values[i]; + } + return sum; + } + + public int index(String what) { Integer found = indices.get(what); return (found == null) ? -1 : found.intValue(); @@ -495,21 +608,22 @@ protected void create(String what, float much) { * @webref floatdict:method * @brief Remove a key/value pair */ - public int remove(String key) { + public float remove(String key) { int index = index(key); - if (index != -1) { - removeIndex(index); + if (index == -1) { + throw new NoSuchElementException("'" + key + "' not found"); } - return index; + float value = values[index]; + removeIndex(index); + return value; } - public String removeIndex(int index) { + public float removeIndex(int index) { if (index < 0 || index >= count) { throw new ArrayIndexOutOfBoundsException(index); } - String key = keys[index]; - //System.out.println("index is " + which + " and " + keys[which]); + float value = values[index]; indices.remove(keys[index]); for (int i = index; i < count-1; i++) { keys[i] = keys[i+1]; @@ -519,7 +633,7 @@ public String removeIndex(int index) { count--; keys[count] = null; values[count] = 0; - return key; + return value; } @@ -592,7 +706,7 @@ public void sortValuesReverse(boolean stable) { } - protected void sortImpl(final boolean useKeys, final boolean reverse, + protected void sortImpl(final boolean useKeys, final boolean reverse, final boolean stable) { Sort s = new Sort() { @Override @@ -622,7 +736,7 @@ public int size() { } @Override - public float compare(int a, int b) { + public int compare(int a, int b) { float diff = 0; if (useKeys) { diff = keys[a].compareToIgnoreCase(keys[b]); @@ -635,7 +749,13 @@ public float compare(int a, int b) { diff = keys[a].compareToIgnoreCase(keys[b]); } } - return reverse ? -diff : diff; + if (diff == 0) { + return 0; + } else if (reverse) { + return diff < 0 ? 1 : -1; + } else { + return diff < 0 ? -1 : 1; + } } @Override @@ -646,10 +766,7 @@ public void swap(int a, int b) { s.run(); // Set the indices after sort/swaps (performance fix 160411) - indices = new HashMap(); - for (int i = 0; i < count; i++) { - indices.put(keys[i], i); - } + resetIndices(); } @@ -659,10 +776,7 @@ public void swap(int a, int b) { * @return a FloatDict with the original keys, mapped to their pct of the total */ public FloatDict getPercent() { - double sum = 0; - for (int i = 0; i < count; i++) { - sum += values[i]; - } + double sum = sum(); FloatDict outgoing = new FloatDict(); for (int i = 0; i < size(); i++) { double percent = value(i) / sum; @@ -692,6 +806,16 @@ public void print() { } + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + /** * Write tab-delimited entries out to * @param writer @@ -704,17 +828,20 @@ public void write(PrintWriter writer) { } + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + StringList items = new StringList(); + for (int i = 0; i < count; i++) { + items.append(JSONObject.quote(keys[i])+ ": " + values[i]); + } + return "{ " + items.join(", ") + " }"; + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " { "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append("\"" + keys[i] + "\": " + values[i]); - } - sb.append(" }"); - return sb.toString(); + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); } } diff --git a/core/src/processing/data/FloatList.java b/core/src/processing/data/FloatList.java index daf01cbfe4..863b056587 100644 --- a/core/src/processing/data/FloatList.java +++ b/core/src/processing/data/FloatList.java @@ -1,5 +1,7 @@ package processing.data; +import java.io.File; +import java.io.PrintWriter; import java.util.Arrays; import java.util.Iterator; import java.util.Random; @@ -627,11 +629,23 @@ public int maxIndex() { public float sum() { - double outgoing = 0; + double amount = sumDouble(); + if (amount > Float.MAX_VALUE) { + throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()"); + } + if (amount < -Float.MAX_VALUE) { + throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()"); + } + return (float) amount; + } + + + public double sumDouble() { + double sum = 0; for (int i = 0; i < count; i++) { - outgoing += data[i]; + sum += data[i]; } - return (float) outgoing; + return sum; } @@ -680,8 +694,9 @@ public int size() { } @Override - public float compare(int a, int b) { - return data[b] - data[a]; + public int compare(int a, int b) { + float diff = data[b] - data[a]; + return diff == 0 ? 0 : (diff < 0 ? -1 : 1); } @Override @@ -879,23 +894,43 @@ public String join(String separator) { public void print() { - for (int i = 0; i < size(); i++) { + for (int i = 0; i < count; i++) { System.out.format("[%d] %f%n", i, data[i]); } } + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write entries to a PrintWriter, one per line + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(data[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + return "[ " + join(", ") + " ]"; + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " [ "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(i + ": " + data[i]); - } - sb.append(" ]"); - return sb.toString(); + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); } } diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java index 965fedb4df..96913591fa 100644 --- a/core/src/processing/data/IntDict.java +++ b/core/src/processing/data/IntDict.java @@ -3,6 +3,7 @@ import java.io.*; import java.util.HashMap; import java.util.Iterator; +import java.util.NoSuchElementException; import processing.core.PApplet; @@ -23,7 +24,7 @@ public class IntDict { protected int[] values; /** Internal implementation for faster lookups */ - private HashMap indices = new HashMap(); + private HashMap indices = new HashMap<>(); public IntDict() { @@ -116,6 +117,29 @@ public int size() { } + /** + * Resize the internal data, this can only be used to shrink the list. + * Helpful for situations like sorting and then grabbing the top 50 entries. + */ + public void resize(int length) { + if (length > count) { + throw new IllegalArgumentException("resize() can only be used to shrink the dictionary"); + } + if (length < 1) { + throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher"); + } + + String[] newKeys = new String[length]; + int[] newValues = new int[length]; + PApplet.arrayCopy(keys, newKeys, length); + PApplet.arrayCopy(values, newValues, length); + keys = newKeys; + values = newValues; + count = length; + resetIndices(); + } + + /** * Remove all entries. * @@ -124,10 +148,67 @@ public int size() { */ public void clear() { count = 0; - indices = new HashMap(); + indices = new HashMap<>(); + } + + + private void resetIndices() { + indices = new HashMap<>(count); + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public class Entry { + public String key; + public int value; + + Entry(String key, int value) { + this.key = key; + this.value = value; + } + } + + + public Iterable entries() { + return new Iterable() { + + public Iterator iterator() { + return entryIterator(); + } + }; + } + + + public Iterator entryIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Entry next() { + ++index; + Entry e = new Entry(keys[index], values[index]); + return e; + } + + public boolean hasNext() { + return index+1 < size(); + } + }; } + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + public String key(int index) { return keys[index]; } @@ -299,6 +380,16 @@ public void set(String key, int amount) { } } + + public void setIndex(int index, String key, int value) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + keys[index] = key; + values[index] = value; + } + + /** * @webref intdict:method * @brief Check if a key is a part of the data structure @@ -319,6 +410,18 @@ public void increment(String key) { } + /** + * Merge another dictionary into this one. Calling this increment() + * since it doesn't make sense in practice for the other dictionary types, + * even though it's technically an add(). + */ + public void increment(IntDict dict) { + for (int i = 0; i < dict.count; i++) { + add(dict.key(i), dict.value(i)); + } + } + + /** * @webref intdict:method * @brief Add to a value @@ -447,6 +550,27 @@ public int maxValue() { } + public int sum() { + long amount = sumLong(); + if (amount > Integer.MAX_VALUE) { + throw new RuntimeException("sum() exceeds " + Integer.MAX_VALUE + ", use sumLong()"); + } + if (amount < Integer.MIN_VALUE) { + throw new RuntimeException("sum() less than " + Integer.MIN_VALUE + ", use sumLong()"); + } + return (int) amount; + } + + + public long sumLong() { + long sum = 0; + for (int i = 0; i < count; i++) { + sum += values[i]; + } + return sum; + } + + public int index(String what) { Integer found = indices.get(what); return (found == null) ? -1 : found.intValue(); @@ -470,19 +594,20 @@ protected void create(String what, int much) { */ public int remove(String key) { int index = index(key); - if (index != -1) { - removeIndex(index); + if (index == -1) { + throw new NoSuchElementException("'" + key + "' not found"); } - return index; + int value = values[index]; + removeIndex(index); + return value; } - public String removeIndex(int index) { + public int removeIndex(int index) { if (index < 0 || index >= count) { throw new ArrayIndexOutOfBoundsException(index); } - //System.out.println("index is " + which + " and " + keys[which]); - String key = keys[index]; + int value = values[index]; indices.remove(keys[index]); for (int i = index; i < count-1; i++) { keys[i] = keys[i+1]; @@ -492,7 +617,7 @@ public String removeIndex(int index) { count--; keys[count] = null; values[count] = 0; - return key; + return value; } @@ -578,7 +703,7 @@ public int size() { } @Override - public float compare(int a, int b) { + public int compare(int a, int b) { int diff = 0; if (useKeys) { diff = keys[a].compareToIgnoreCase(keys[b]); @@ -602,10 +727,7 @@ public void swap(int a, int b) { s.run(); // Set the indices after sort/swaps (performance fix 160411) - indices = new HashMap(); - for (int i = 0; i < count; i++) { - indices.put(keys[i], i); - } + resetIndices(); } @@ -615,10 +737,7 @@ public void swap(int a, int b) { * @return an IntDict with the original keys, mapped to their pct of the total */ public FloatDict getPercent() { - double sum = 0; - for (int i = 0; i < count; i++) { - sum += values[i]; - } + double sum = sum(); // a little more accuracy FloatDict outgoing = new FloatDict(); for (int i = 0; i < size(); i++) { double percent = value(i) / sum; @@ -649,8 +768,17 @@ public void print() { /** - * Write tab-delimited entries out to - * @param writer + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write tab-delimited entries to a PrintWriter */ public void write(PrintWriter writer) { for (int i = 0; i < count; i++) { @@ -665,8 +793,8 @@ public void write(PrintWriter writer) { */ public String toJSON() { StringList items = new StringList(); - for (int i = 0; i < size(); i++) { - items.append("\"" + JSONObject.quote(keys[i]) + "\": " + values[i]); + for (int i = 0; i < count; i++) { + items.append(JSONObject.quote(keys[i])+ ": " + values[i]); } return "{ " + items.join(", ") + " }"; } @@ -675,17 +803,5 @@ public String toJSON() { @Override public String toString() { return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); - /* - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " { "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append("\"" + keys[i] + "\": " + values[i]); - } - sb.append(" }"); - return sb.toString(); - */ } } diff --git a/core/src/processing/data/IntList.java b/core/src/processing/data/IntList.java index 5147d75691..dc2c899166 100644 --- a/core/src/processing/data/IntList.java +++ b/core/src/processing/data/IntList.java @@ -1,5 +1,7 @@ package processing.data; +import java.io.File; +import java.io.PrintWriter; import java.util.Arrays; import java.util.Iterator; import java.util.Random; @@ -596,11 +598,23 @@ public int maxIndex() { public int sum() { - int outgoing = 0; + long amount = sumLong(); + if (amount > Integer.MAX_VALUE) { + throw new RuntimeException("sum() exceeds " + Integer.MAX_VALUE + ", use sumLong()"); + } + if (amount < Integer.MIN_VALUE) { + throw new RuntimeException("sum() less than " + Integer.MIN_VALUE + ", use sumLong()"); + } + return (int) amount; + } + + + public long sumLong() { + long sum = 0; for (int i = 0; i < count; i++) { - outgoing += data[i]; + sum += data[i]; } - return outgoing; + return sum; } @@ -629,7 +643,7 @@ public int size() { } @Override - public float compare(int a, int b) { + public int compare(int a, int b) { return data[b] - data[a]; } @@ -840,6 +854,19 @@ public FloatList getPercent() { } +// /** +// * Count the number of times each entry is found in this list. +// * Converts each entry to a String so it can be used as a key. +// */ +// public IntDict getTally() { +// IntDict outgoing = new IntDict(); +// for (int i = 0; i < count; i++) { +// outgoing.increment(String.valueOf(data[i])); +// } +// return outgoing; +// } + + public IntList getSubset(int start) { return getSubset(start, count - start); } @@ -867,23 +894,43 @@ public String join(String separator) { public void print() { - for (int i = 0; i < size(); i++) { + for (int i = 0; i < count; i++) { System.out.format("[%d] %d%n", i, data[i]); } } + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write entries to a PrintWriter, one per line + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(data[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + return "[ " + join(", ") + " ]"; + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " [ "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(i + ": " + data[i]); - } - sb.append(" ]"); - return sb.toString(); + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); } } diff --git a/core/src/processing/data/JSONArray.java b/core/src/processing/data/JSONArray.java index e959140fb1..ea8276bd8b 100644 --- a/core/src/processing/data/JSONArray.java +++ b/core/src/processing/data/JSONArray.java @@ -109,7 +109,7 @@ public class JSONArray { * Construct an empty JSONArray. */ public JSONArray() { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); } @@ -165,7 +165,7 @@ protected JSONArray(JSONTokener x) { * @nowebref */ public JSONArray(IntList list) { - myArrayList = new ArrayList(); + myArrayList = new ArrayList<>(); for (int item : list.values()) { myArrayList.add(Integer.valueOf(item)); } @@ -176,9 +176,9 @@ public JSONArray(IntList list) { * @nowebref */ public JSONArray(FloatList list) { - myArrayList = new ArrayList(); + myArrayList = new ArrayList<>(); for (float item : list.values()) { - myArrayList.add(new Float(item)); + myArrayList.add(Float.valueOf(item)); } } @@ -187,7 +187,7 @@ public JSONArray(FloatList list) { * @nowebref */ public JSONArray(StringList list) { - myArrayList = new ArrayList(); + myArrayList = new ArrayList<>(); for (String item : list.values()) { myArrayList.add(item); } @@ -263,7 +263,7 @@ private Object opt(int index) { * @return An object value. * @throws RuntimeException If there is no value for the index. */ - private Object get(int index) { + public Object get(int index) { Object object = opt(index); if (object == null) { throw new RuntimeException("JSONArray[" + index + "] not found."); diff --git a/core/src/processing/data/JSONObject.java b/core/src/processing/data/JSONObject.java index 466f22fbf9..cc7a22de08 100644 --- a/core/src/processing/data/JSONObject.java +++ b/core/src/processing/data/JSONObject.java @@ -123,7 +123,7 @@ public class JSONObject { * string objects. This is used by JSONObject.put(string, object). */ private static HashMap keyPool = - new HashMap(keyPoolSize); + new HashMap<>(keyPoolSize); // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -197,7 +197,7 @@ public int hashCode() { * @nowebref */ public JSONObject() { - this.map = new HashMap(); + this.map = new HashMap<>(); } @@ -291,7 +291,7 @@ protected JSONObject(JSONTokener x) { * the JSONObject. */ protected JSONObject(HashMap map) { - this.map = new HashMap(); + this.map = new HashMap<>(); if (map != null) { Iterator i = map.entrySet().iterator(); while (i.hasNext()) { @@ -309,7 +309,7 @@ protected JSONObject(HashMap map) { * @nowebref */ public JSONObject(IntDict dict) { - map = new HashMap(); + map = new HashMap<>(); for (int i = 0; i < dict.size(); i++) { setInt(dict.key(i), dict.value(i)); } @@ -320,7 +320,7 @@ public JSONObject(IntDict dict) { * @nowebref */ public JSONObject(FloatDict dict) { - map = new HashMap(); + map = new HashMap<>(); for (int i = 0; i < dict.size(); i++) { setFloat(dict.key(i), dict.value(i)); } @@ -331,7 +331,7 @@ public JSONObject(FloatDict dict) { * @nowebref */ public JSONObject(StringDict dict) { - map = new HashMap(); + map = new HashMap<>(); for (int i = 0; i < dict.size(); i++) { setString(dict.key(i), dict.value(i)); } @@ -537,13 +537,17 @@ static protected String doubleToString(double d) { * @return The object associated with the key. * @throws RuntimeException if the key is not found. */ - private Object get(String key) { + public Object get(String key) { if (key == null) { - throw new RuntimeException("Null key."); + throw new RuntimeException("JSONObject.get(null) called"); } Object object = this.opt(key); if (object == null) { - throw new RuntimeException("JSONObject[" + quote(key) + "] not found."); + // Adding for rev 0257 in line with other p5 api + return null; + } + if (object == null) { + throw new RuntimeException("JSONObject[" + quote(key) + "] not found"); } return object; } @@ -563,10 +567,14 @@ private Object get(String key) { */ public String getString(String key) { Object object = this.get(key); + if (object == null) { + // Adding for rev 0257 in line with other p5 api + return null; + } if (object instanceof String) { return (String)object; } - throw new RuntimeException("JSONObject[" + quote(key) + "] not a string."); + throw new RuntimeException("JSONObject[" + quote(key) + "] is not a string"); } @@ -599,10 +607,12 @@ public String getString(String key, String defaultValue) { */ public int getInt(String key) { Object object = this.get(key); + if (object == null) { + throw new RuntimeException("JSONObject[" + quote(key) + "] not found"); + } try { - return object instanceof Number - ? ((Number)object).intValue() - : Integer.parseInt((String)object); + return object instanceof Number ? + ((Number)object).intValue() : Integer.parseInt((String)object); } catch (Exception e) { throw new RuntimeException("JSONObject[" + quote(key) + "] is not an int."); } @@ -778,14 +788,17 @@ public boolean getBoolean(String key, boolean defaultValue) { * @webref jsonobject:method * @brief Gets the JSONArray value associated with a key * @param key a key string - * @return A JSONArray which is the value. - * @throws RuntimeException if the key is not found or if the value is not a JSONArray. + * @return A JSONArray which is the value, or null if not present + * @throws RuntimeException if the value is not a JSONArray. * @see JSONObject#getJSONObject(String) * @see JSONObject#setJSONObject(String, JSONObject) * @see JSONObject#setJSONArray(String, JSONArray) */ public JSONArray getJSONArray(String key) { Object object = this.get(key); + if (object == null) { + return null; + } if (object instanceof JSONArray) { return (JSONArray)object; } @@ -799,14 +812,17 @@ public JSONArray getJSONArray(String key) { * @webref jsonobject:method * @brief Gets the JSONObject value associated with a key * @param key a key string - * @return A JSONObject which is the value. - * @throws RuntimeException if the key is not found or if the value is not a JSONObject. + * @return A JSONObject which is the value or null if not available. + * @throws RuntimeException if the value is not a JSONObject. * @see JSONObject#getJSONArray(String) * @see JSONObject#setJSONObject(String, JSONObject) * @see JSONObject#setJSONArray(String, JSONArray) */ public JSONObject getJSONObject(String key) { Object object = this.get(key); + if (object == null) { + return null; + } if (object instanceof JSONObject) { return (JSONObject)object; } @@ -864,7 +880,7 @@ public JSONObject getJSONObject(String key) { * @return true if the key exists in the JSONObject. */ public boolean hasKey(String key) { - return this.map.containsKey(key); + return map.containsKey(key); } @@ -897,9 +913,9 @@ public boolean hasKey(String key) { /** - * Determine if the value associated with the key is null or if there is + * Determine if the value associated with the key is null or if there is * no value. - * + * * @webref * @param key A key string. * @return true if there is no value associated with the key or if @@ -1196,7 +1212,7 @@ public JSONObject setLong(String key, long value) { * @see JSONObject#setBoolean(String, boolean) */ public JSONObject setFloat(String key, float value) { - this.put(key, new Double(value)); + this.put(key, Double.valueOf(value)); return this; } @@ -1210,7 +1226,7 @@ public JSONObject setFloat(String key, float value) { * @throws RuntimeException If the key is null or if the number is NaN or infinite. */ public JSONObject setDouble(String key, double value) { - this.put(key, new Double(value)); + this.put(key, Double.valueOf(value)); return this; } @@ -1300,7 +1316,7 @@ public JSONObject setJSONArray(String key, JSONArray value) { * @throws RuntimeException If the value is non-finite number * or if the key is null. */ - private JSONObject put(String key, Object value) { + public JSONObject put(String key, Object value) { String pooled; if (key == null) { throw new RuntimeException("Null key."); @@ -1310,7 +1326,7 @@ private JSONObject put(String key, Object value) { pooled = (String)keyPool.get(key); if (pooled == null) { if (keyPool.size() >= keyPoolSize) { - keyPool = new HashMap(keyPoolSize); + keyPool = new HashMap<>(keyPoolSize); } keyPool.put(key, key); } else { @@ -1371,7 +1387,7 @@ private JSONObject putOnce(String key, Object value) { * @param string A String * @return A String correctly formatted for insertion in a JSON text. */ - static protected String quote(String string) { + static public String quote(String string) { StringWriter sw = new StringWriter(); synchronized (sw.getBuffer()) { try { @@ -1383,7 +1399,7 @@ static protected String quote(String string) { } } - static protected Writer quote(String string, Writer w) throws IOException { + static public Writer quote(String string, Writer w) throws IOException { if (string == null || string.length() == 0) { w.write("\"\""); return w; diff --git a/core/src/processing/data/LongDict.java b/core/src/processing/data/LongDict.java new file mode 100644 index 0000000000..c9bf408216 --- /dev/null +++ b/core/src/processing/data/LongDict.java @@ -0,0 +1,802 @@ +package processing.data; + +import java.io.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import processing.core.PApplet; + + +/** + * A simple class to use a String as a lookup for an int value. + * + * @nowebref + * @see FloatDict + * @see StringDict + */ +public class LongDict { + + /** Number of elements in the table */ + protected int count; + + protected String[] keys; + protected long[] values; + + /** Internal implementation for faster lookups */ + private HashMap indices = new HashMap<>(); + + + public LongDict() { + count = 0; + keys = new String[10]; + values = new long[10]; + } + + + /** + * Create a new lookup with a specific size. This is more efficient than not + * specifying a size. Use it when you know the rough size of the thing you're creating. + * + * @nowebref + */ + public LongDict(int length) { + count = 0; + keys = new String[length]; + values = new long[length]; + } + + + /** + * Read a set of entries from a Reader that has each key/value pair on + * a single line, separated by a tab. + * + * @nowebref + */ + public LongDict(BufferedReader reader) { + String[] lines = PApplet.loadStrings(reader); + keys = new String[lines.length]; + values = new long[lines.length]; + + for (int i = 0; i < lines.length; i++) { + String[] pieces = PApplet.split(lines[i], '\t'); + if (pieces.length == 2) { + keys[count] = pieces[0]; + values[count] = PApplet.parseInt(pieces[1]); + indices.put(pieces[0], count); + count++; + } + } + } + + /** + * @nowebref + */ + public LongDict(String[] keys, long[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException("key and value arrays must be the same length"); + } + this.keys = keys; + this.values = values; + count = keys.length; + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + /** + * Constructor to allow (more intuitive) inline initialization, e.g.: + *
+   * new FloatDict(new Object[][] {
+   *   { "key1", 1 },
+   *   { "key2", 2 }
+   * });
+   * 
+ */ + public LongDict(Object[][] pairs) { + count = pairs.length; + this.keys = new String[count]; + this.values = new long[count]; + for (int i = 0; i < count; i++) { + keys[i] = (String) pairs[i][0]; + values[i] = (Integer) pairs[i][1]; + indices.put(keys[i], i); + } + } + + + /** + * Returns the number of key/value pairs + * + * @webref intdict:method + * @brief Returns the number of key/value pairs + */ + public int size() { + return count; + } + + + /** + * Resize the internal data, this can only be used to shrink the list. + * Helpful for situations like sorting and then grabbing the top 50 entries. + */ + public void resize(int length) { + if (length > count) { + throw new IllegalArgumentException("resize() can only be used to shrink the dictionary"); + } + if (length < 1) { + throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher"); + } + + String[] newKeys = new String[length]; + long[] newValues = new long[length]; + PApplet.arrayCopy(keys, newKeys, length); + PApplet.arrayCopy(values, newValues, length); + keys = newKeys; + values = newValues; + count = length; + resetIndices(); + } + + + /** + * Remove all entries. + * + * @webref intdict:method + * @brief Remove all entries + */ + public void clear() { + count = 0; + indices = new HashMap<>(); + } + + + private void resetIndices() { + indices = new HashMap<>(count); + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public class Entry { + public String key; + public long value; + + Entry(String key, long value) { + this.key = key; + this.value = value; + } + } + + + public Iterable entries() { + return new Iterable() { + + public Iterator iterator() { + return entryIterator(); + } + }; + } + + + public Iterator entryIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Entry next() { + ++index; + Entry e = new Entry(keys[index], values[index]); + return e; + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public String key(int index) { + return keys[index]; + } + + + protected void crop() { + if (count != keys.length) { + keys = PApplet.subset(keys, 0, count); + values = PApplet.subset(values, 0, count); + } + } + + + public Iterable keys() { + return new Iterable() { + + @Override + public Iterator iterator() { + return keyIterator(); + } + }; + } + + + // Use this to iterate when you want to be able to remove elements along the way + public Iterator keyIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public String next() { + return key(++index); + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + /** + * Return a copy of the internal keys array. This array can be modified. + * + * @webref intdict:method + * @brief Return a copy of the internal keys array + */ + public String[] keyArray() { + crop(); + return keyArray(null); + } + + + public String[] keyArray(String[] outgoing) { + if (outgoing == null || outgoing.length != count) { + outgoing = new String[count]; + } + System.arraycopy(keys, 0, outgoing, 0, count); + return outgoing; + } + + + public long value(int index) { + return values[index]; + } + + + /** + * @webref intdict:method + * @brief Return the internal array being used to store the values + */ + public Iterable values() { + return new Iterable() { + + @Override + public Iterator iterator() { + return valueIterator(); + } + }; + } + + + public Iterator valueIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Long next() { + return value(++index); + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + /** + * Create a new array and copy each of the values into it. + * + * @webref intdict:method + * @brief Create a new array and copy each of the values into it + */ + public int[] valueArray() { + crop(); + return valueArray(null); + } + + + /** + * Fill an already-allocated array with the values (more efficient than + * creating a new array each time). If 'array' is null, or not the same + * size as the number of values, a new array will be allocated and returned. + * + * @param array values to copy into the array + */ + public int[] valueArray(int[] array) { + if (array == null || array.length != size()) { + array = new int[count]; + } + System.arraycopy(values, 0, array, 0, count); + return array; + } + + + /** + * Return a value for the specified key. + * + * @webref intdict:method + * @brief Return a value for the specified key + */ + public long get(String key) { + int index = index(key); + if (index == -1) { + throw new IllegalArgumentException("No key named '" + key + "'"); + } + return values[index]; + } + + + public long get(String key, long alternate) { + int index = index(key); + if (index == -1) return alternate; + return values[index]; + } + + + /** + * Create a new key/value pair or change the value of one. + * + * @webref intdict:method + * @brief Create a new key/value pair or change the value of one + */ + public void set(String key, long amount) { + int index = index(key); + if (index == -1) { + create(key, amount); + } else { + values[index] = amount; + } + } + + + public void setIndex(int index, String key, long value) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + keys[index] = key; + values[index] = value; + } + + + /** + * @webref intdict:method + * @brief Check if a key is a part of the data structure + */ + public boolean hasKey(String key) { + return index(key) != -1; + } + + + /** + * Increase the value associated with a specific key by 1. + * + * @webref intdict:method + * @brief Increase the value of a specific key value by 1 + */ + public void increment(String key) { + add(key, 1); + } + + + /** + * Merge another dictionary into this one. Calling this increment() + * since it doesn't make sense in practice for the other dictionary types, + * even though it's technically an add(). + */ + public void increment(LongDict dict) { + for (int i = 0; i < dict.count; i++) { + add(dict.key(i), dict.value(i)); + } + } + + + /** + * @webref intdict:method + * @brief Add to a value + */ + public void add(String key, long amount) { + int index = index(key); + if (index == -1) { + create(key, amount); + } else { + values[index] += amount; + } + } + + + /** + * @webref intdict:method + * @brief Subtract from a value + */ + public void sub(String key, long amount) { + add(key, -amount); + } + + + /** + * @webref intdict:method + * @brief Multiply a value + */ + public void mult(String key, long amount) { + int index = index(key); + if (index != -1) { + values[index] *= amount; + } + } + + + /** + * @webref intdict:method + * @brief Divide a value + */ + public void div(String key, long amount) { + int index = index(key); + if (index != -1) { + values[index] /= amount; + } + } + + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + // return the index of the minimum value + public int minIndex() { + //checkMinMax("minIndex"); + if (count == 0) return -1; + + int index = 0; + long value = values[0]; + for (int i = 1; i < count; i++) { + if (values[i] < value) { + index = i; + value = values[i]; + } + } + return index; + } + + + // return the key for the minimum value + public String minKey() { + checkMinMax("minKey"); + int index = minIndex(); + if (index == -1) { + return null; + } + return keys[index]; + } + + + // return the minimum value, or throw an error if there are no values + public long minValue() { + checkMinMax("minValue"); + return values[minIndex()]; + } + + + // return the index of the max value + public int maxIndex() { + //checkMinMax("maxIndex"); + if (count == 0) { + return -1; + } + int index = 0; + long value = values[0]; + for (int i = 1; i < count; i++) { + if (values[i] > value) { + index = i; + value = values[i]; + } + } + return index; + } + + + /** return the key corresponding to the maximum value or null if no entries */ + public String maxKey() { + //checkMinMax("maxKey"); + int index = maxIndex(); + if (index == -1) { + return null; + } + return keys[index]; + } + + + // return the maximum value or throw an error if zero length + public long maxValue() { + checkMinMax("maxIndex"); + return values[maxIndex()]; + } + + + public long sum() { + long sum = 0; + for (int i = 0; i < count; i++) { + sum += values[i]; + } + return sum; + } + + + public int index(String what) { + Integer found = indices.get(what); + return (found == null) ? -1 : found.intValue(); + } + + + protected void create(String what, long much) { + if (count == keys.length) { + keys = PApplet.expand(keys); + values = PApplet.expand(values); + } + indices.put(what, Integer.valueOf(count)); + keys[count] = what; + values[count] = much; + count++; + } + + + /** + * @webref intdict:method + * @brief Remove a key/value pair + */ + public long remove(String key) { + int index = index(key); + if (index == -1) { + throw new NoSuchElementException("'" + key + "' not found"); + } + long value = values[index]; + removeIndex(index); + return value; + } + + + public long removeIndex(int index) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + long value = values[index]; + indices.remove(keys[index]); + for (int i = index; i < count-1; i++) { + keys[i] = keys[i+1]; + values[i] = values[i+1]; + indices.put(keys[i], i); + } + count--; + keys[count] = null; + values[count] = 0; + return value; + } + + + public void swap(int a, int b) { + String tkey = keys[a]; + long tvalue = values[a]; + keys[a] = keys[b]; + values[a] = values[b]; + keys[b] = tkey; + values[b] = tvalue; + +// indices.put(keys[a], Integer.valueOf(a)); +// indices.put(keys[b], Integer.valueOf(b)); + } + + + /** + * Sort the keys alphabetically (ignoring case). Uses the value as a + * tie-breaker (only really possible with a key that has a case change). + * + * @webref intdict:method + * @brief Sort the keys alphabetically + */ + public void sortKeys() { + sortImpl(true, false, true); + } + + /** + * Sort the keys alphabetically in reverse (ignoring case). Uses the value as a + * tie-breaker (only really possible with a key that has a case change). + * + * @webref intdict:method + * @brief Sort the keys alphabetically in reverse + */ + public void sortKeysReverse() { + sortImpl(true, true, true); + } + + + /** + * Sort by values in ascending order. The smallest value will be at [0]. + * + * @webref intdict:method + * @brief Sort by values in ascending order + */ + public void sortValues() { + sortValues(true); + } + + + /** + * Set true to ensure that the order returned is identical. Slightly + * slower because the tie-breaker for identical values compares the keys. + * @param stable + */ + public void sortValues(boolean stable) { + sortImpl(false, false, stable); + } + + + /** + * Sort by values in descending order. The largest value will be at [0]. + * + * @webref intdict:method + * @brief Sort by values in descending order + */ + public void sortValuesReverse() { + sortValuesReverse(true); + } + + + public void sortValuesReverse(boolean stable) { + sortImpl(false, true, stable); + } + + + protected void sortImpl(final boolean useKeys, final boolean reverse, + final boolean stable) { + Sort s = new Sort() { + @Override + public int size() { + return count; + } + + @Override + public int compare(int a, int b) { + long diff = 0; + if (useKeys) { + diff = keys[a].compareToIgnoreCase(keys[b]); + if (diff == 0) { + diff = values[a] - values[b]; + } + } else { // sort values + diff = values[a] - values[b]; + if (diff == 0 && stable) { + diff = keys[a].compareToIgnoreCase(keys[b]); + } + } + if (diff == 0) { + return 0; + } else if (reverse) { + return diff < 0 ? 1 : -1; + } else { + return diff < 0 ? -1 : 1; + } + } + + @Override + public void swap(int a, int b) { + LongDict.this.swap(a, b); + } + }; + s.run(); + + // Set the indices after sort/swaps (performance fix 160411) + resetIndices(); + } + + + /** + * Sum all of the values in this dictionary, then return a new FloatDict of + * each key, divided by the total sum. The total for all values will be ~1.0. + * @return an IntDict with the original keys, mapped to their pct of the total + */ + public FloatDict getPercent() { + double sum = sum(); // a little more accuracy + FloatDict outgoing = new FloatDict(); + for (int i = 0; i < size(); i++) { + double percent = value(i) / sum; + outgoing.set(key(i), (float) percent); + } + return outgoing; + } + + + /** Returns a duplicate copy of this object. */ + public LongDict copy() { + LongDict outgoing = new LongDict(count); + System.arraycopy(keys, 0, outgoing.keys, 0, count); + System.arraycopy(values, 0, outgoing.values, 0, count); + for (int i = 0; i < count; i++) { + outgoing.indices.put(keys[i], i); + } + outgoing.count = count; + return outgoing; + } + + + public void print() { + for (int i = 0; i < size(); i++) { + System.out.println(keys[i] + " = " + values[i]); + } + } + + + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write tab-delimited entries to a PrintWriter + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(keys[i] + "\t" + values[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + StringList items = new StringList(); + for (int i = 0; i < count; i++) { + items.append(JSONObject.quote(keys[i])+ ": " + values[i]); + } + return "{ " + items.join(", ") + " }"; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); + } +} diff --git a/core/src/processing/data/LongList.java b/core/src/processing/data/LongList.java new file mode 100644 index 0000000000..adfb1ea83c --- /dev/null +++ b/core/src/processing/data/LongList.java @@ -0,0 +1,937 @@ +package processing.data; + +import java.io.File; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Random; + +import processing.core.PApplet; + + +// splice, slice, subset, concat, reverse + +// trim, join for String versions + + +/** + * Helper class for a list of ints. Lists are designed to have some of the + * features of ArrayLists, but to maintain the simplicity and efficiency of + * working with arrays. + * + * Functions like sort() and shuffle() always act on the list itself. To get + * a sorted copy, use list.copy().sort(). + * + * @nowebref + * @see FloatList + * @see StringList + */ +public class LongList implements Iterable { + protected int count; + protected long[] data; + + + public LongList() { + data = new long[10]; + } + + + /** + * @nowebref + */ + public LongList(int length) { + data = new long[length]; + } + + + /** + * @nowebref + */ + public LongList(int[] source) { + count = source.length; + data = new long[count]; + System.arraycopy(source, 0, data, 0, count); + } + + + /** + * Construct an IntList from an iterable pile of objects. + * For instance, a float array, an array of strings, who knows). + * Un-parseable or null values will be set to 0. + * @nowebref + */ + public LongList(Iterable iter) { + this(10); + for (Object o : iter) { + if (o == null) { + append(0); // missing value default + } else if (o instanceof Number) { + append(((Number) o).intValue()); + } else { + append(PApplet.parseInt(o.toString().trim())); + } + } + crop(); + } + + + /** + * Construct an IntList from a random pile of objects. + * Un-parseable or null values will be set to zero. + */ + public LongList(Object... items) { + final int missingValue = 0; // nuts, can't be last/final/second arg + + count = items.length; + data = new long[count]; + int index = 0; + for (Object o : items) { + int value = missingValue; + if (o != null) { + if (o instanceof Number) { + value = ((Number) o).intValue(); + } else { + value = PApplet.parseInt(o.toString().trim(), missingValue); + } + } + data[index++] = value; + } + } + + + static public LongList fromRange(int stop) { + return fromRange(0, stop); + } + + + static public LongList fromRange(int start, int stop) { + int count = stop - start; + LongList newbie = new LongList(count); + for (int i = 0; i < count; i++) { + newbie.set(i, start+i); + } + return newbie; + } + + + /** + * Improve efficiency by removing allocated but unused entries from the + * internal array used to store the data. Set to private, though it could + * be useful to have this public if lists are frequently making drastic + * size changes (from very large to very small). + */ + private void crop() { + if (count != data.length) { + data = PApplet.subset(data, 0, count); + } + } + + + /** + * Get the length of the list. + * + * @webref intlist:method + * @brief Get the length of the list + */ + public int size() { + return count; + } + + + public void resize(int length) { + if (length > data.length) { + long[] temp = new long[length]; + System.arraycopy(data, 0, temp, 0, count); + data = temp; + + } else if (length > count) { + Arrays.fill(data, count, length, 0); + } + count = length; + } + + + /** + * Remove all entries from the list. + * + * @webref intlist:method + * @brief Remove all entries from the list + */ + public void clear() { + count = 0; + } + + + /** + * Get an entry at a particular index. + * + * @webref intlist:method + * @brief Get an entry at a particular index + */ + public long get(int index) { + if (index >= this.count) { + throw new ArrayIndexOutOfBoundsException(index); + } + return data[index]; + } + + + /** + * Set the entry at a particular index. If the index is past the length of + * the list, it'll expand the list to accommodate, and fill the intermediate + * entries with 0s. + * + * @webref intlist:method + * @brief Set the entry at a particular index + */ + public void set(int index, int what) { + if (index >= count) { + data = PApplet.expand(data, index+1); + for (int i = count; i < index; i++) { + data[i] = 0; + } + count = index+1; + } + data[index] = what; + } + + + /** Just an alias for append(), but matches pop() */ + public void push(int value) { + append(value); + } + + + public long pop() { + if (count == 0) { + throw new RuntimeException("Can't call pop() on an empty list"); + } + long value = get(count-1); + count--; + return value; + } + + + /** + * Remove an element from the specified index + * + * @webref intlist:method + * @brief Remove an element from the specified index + */ + public long remove(int index) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + long entry = data[index]; +// int[] outgoing = new int[count - 1]; +// System.arraycopy(data, 0, outgoing, 0, index); +// count--; +// System.arraycopy(data, index + 1, outgoing, 0, count - index); +// data = outgoing; + // For most cases, this actually appears to be faster + // than arraycopy() on an array copying into itself. + for (int i = index; i < count-1; i++) { + data[i] = data[i+1]; + } + count--; + return entry; + } + + + // Remove the first instance of a particular value, + // and return the index at which it was found. + public int removeValue(int value) { + int index = index(value); + if (index != -1) { + remove(index); + return index; + } + return -1; + } + + + // Remove all instances of a particular value, + // and return the number of values found and removed + public int removeValues(int value) { + int ii = 0; + for (int i = 0; i < count; i++) { + if (data[i] != value) { + data[ii++] = data[i]; + } + } + int removed = count - ii; + count = ii; + return removed; + } + + + /** + * Add a new entry to the list. + * + * @webref intlist:method + * @brief Add a new entry to the list + */ + public void append(long value) { + if (count == data.length) { + data = PApplet.expand(data); + } + data[count++] = value; + } + + + public void append(int[] values) { + for (int v : values) { + append(v); + } + } + + + public void append(LongList list) { + for (long v : list.values()) { // will concat the list... + append(v); + } + } + + + /** Add this value, but only if it's not already in the list. */ + public void appendUnique(int value) { + if (!hasValue(value)) { + append(value); + } + } + + +// public void insert(int index, int value) { +// if (index+1 > count) { +// if (index+1 < data.length) { +// } +// } +// if (index >= data.length) { +// data = PApplet.expand(data, index+1); +// data[index] = value; +// count = index+1; +// +// } else if (count == data.length) { +// if (index >= count) { +// //int[] temp = new int[count << 1]; +// System.arraycopy(data, 0, temp, 0, index); +// temp[index] = value; +// System.arraycopy(data, index, temp, index+1, count - index); +// data = temp; +// +// } else { +// // data[] has room to grow +// // for() loop believed to be faster than System.arraycopy over itself +// for (int i = count; i > index; --i) { +// data[i] = data[i-1]; +// } +// data[index] = value; +// count++; +// } +// } + + + public void insert(int index, long value) { + insert(index, new long[] { value }); + } + + + // same as splice + public void insert(int index, long[] values) { + if (index < 0) { + throw new IllegalArgumentException("insert() index cannot be negative: it was " + index); + } + if (index >= data.length) { + throw new IllegalArgumentException("insert() index " + index + " is past the end of this list"); + } + + long[] temp = new long[count + values.length]; + + // Copy the old values, but not more than already exist + System.arraycopy(data, 0, temp, 0, Math.min(count, index)); + + // Copy the new values into the proper place + System.arraycopy(values, 0, temp, index, values.length); + +// if (index < count) { + // The index was inside count, so it's a true splice/insert + System.arraycopy(data, index, temp, index+values.length, count - index); + count = count + values.length; +// } else { +// // The index was past 'count', so the new count is weirder +// count = index + values.length; +// } + data = temp; + } + + + public void insert(int index, LongList list) { + insert(index, list.values()); + } + + + // below are aborted attempts at more optimized versions of the code + // that are harder to read and debug... + +// if (index + values.length >= count) { +// // We're past the current 'count', check to see if we're still allocated +// // index 9, data.length = 10, values.length = 1 +// if (index + values.length < data.length) { +// // There's still room for these entries, even though it's past 'count'. +// // First clear out the entries leading up to it, however. +// for (int i = count; i < index; i++) { +// data[i] = 0; +// } +// data[index] = +// } +// if (index >= data.length) { +// int length = index + values.length; +// int[] temp = new int[length]; +// System.arraycopy(data, 0, temp, 0, count); +// System.arraycopy(values, 0, temp, index, values.length); +// data = temp; +// count = data.length; +// } else { +// +// } +// +// } else if (count == data.length) { +// int[] temp = new int[count << 1]; +// System.arraycopy(data, 0, temp, 0, index); +// temp[index] = value; +// System.arraycopy(data, index, temp, index+1, count - index); +// data = temp; +// +// } else { +// // data[] has room to grow +// // for() loop believed to be faster than System.arraycopy over itself +// for (int i = count; i > index; --i) { +// data[i] = data[i-1]; +// } +// data[index] = value; +// count++; +// } + + + /** Return the first index of a particular value. */ + public int index(int what) { + /* + if (indexCache != null) { + try { + return indexCache.get(what); + } catch (Exception e) { // not there + return -1; + } + } + */ + for (int i = 0; i < count; i++) { + if (data[i] == what) { + return i; + } + } + return -1; + } + + + // !!! TODO this is not yet correct, because it's not being reset when + // the rest of the entries are changed +// protected void cacheIndices() { +// indexCache = new HashMap(); +// for (int i = 0; i < count; i++) { +// indexCache.put(data[i], i); +// } +// } + + /** + * @webref intlist:method + * @brief Check if a number is a part of the list + */ + public boolean hasValue(int value) { +// if (indexCache == null) { +// cacheIndices(); +// } +// return index(what) != -1; + for (int i = 0; i < count; i++) { + if (data[i] == value) { + return true; + } + } + return false; + } + + /** + * @webref intlist:method + * @brief Add one to a value + */ + public void increment(int index) { + if (count <= index) { + resize(index + 1); + } + data[index]++; + } + + + private void boundsProblem(int index, String method) { + final String msg = String.format("The list size is %d. " + + "You cannot %s() to element %d.", count, method, index); + throw new ArrayIndexOutOfBoundsException(msg); + } + + + /** + * @webref intlist:method + * @brief Add to a value + */ + public void add(int index, int amount) { + if (index < count) { + data[index] += amount; + } else { + boundsProblem(index, "add"); + } + } + + /** + * @webref intlist:method + * @brief Subtract from a value + */ + public void sub(int index, int amount) { + if (index < count) { + data[index] -= amount; + } else { + boundsProblem(index, "sub"); + } + } + + /** + * @webref intlist:method + * @brief Multiply a value + */ + public void mult(int index, int amount) { + if (index < count) { + data[index] *= amount; + } else { + boundsProblem(index, "mult"); + } + } + + /** + * @webref intlist:method + * @brief Divide a value + */ + public void div(int index, int amount) { + if (index < count) { + data[index] /= amount; + } else { + boundsProblem(index, "div"); + } + } + + + private void checkMinMax(String functionName) { + if (count == 0) { + String msg = + String.format("Cannot use %s() on an empty %s.", + functionName, getClass().getSimpleName()); + throw new RuntimeException(msg); + } + } + + + /** + * @webref intlist:method + * @brief Return the smallest value + */ + public long min() { + checkMinMax("min"); + long outgoing = data[0]; + for (int i = 1; i < count; i++) { + if (data[i] < outgoing) outgoing = data[i]; + } + return outgoing; + } + + + // returns the index of the minimum value. + // if there are ties, it returns the first one found. + public int minIndex() { + checkMinMax("minIndex"); + long value = data[0]; + int index = 0; + for (int i = 1; i < count; i++) { + if (data[i] < value) { + value = data[i]; + index = i; + } + } + return index; + } + + + /** + * @webref intlist:method + * @brief Return the largest value + */ + public long max() { + checkMinMax("max"); + long outgoing = data[0]; + for (int i = 1; i < count; i++) { + if (data[i] > outgoing) outgoing = data[i]; + } + return outgoing; + } + + + // returns the index of the maximum value. + // if there are ties, it returns the first one found. + public int maxIndex() { + checkMinMax("maxIndex"); + long value = data[0]; + int index = 0; + for (int i = 1; i < count; i++) { + if (data[i] > value) { + value = data[i]; + index = i; + } + } + return index; + } + + + public int sum() { + long amount = sumLong(); + if (amount > Integer.MAX_VALUE) { + throw new RuntimeException("sum() exceeds " + Integer.MAX_VALUE + ", use sumLong()"); + } + if (amount < Integer.MIN_VALUE) { + throw new RuntimeException("sum() less than " + Integer.MIN_VALUE + ", use sumLong()"); + } + return (int) amount; + } + + + public long sumLong() { + long sum = 0; + for (int i = 0; i < count; i++) { + sum += data[i]; + } + return sum; + } + + + /** + * Sorts the array in place. + * + * @webref intlist:method + * @brief Sorts the array, lowest to highest + */ + public void sort() { + Arrays.sort(data, 0, count); + } + + + /** + * Reverse sort, orders values from highest to lowest. + * + * @webref intlist:method + * @brief Reverse sort, orders values from highest to lowest + */ + public void sortReverse() { + new Sort() { + @Override + public int size() { + return count; + } + + @Override + public int compare(int a, int b) { + long diff = data[b] - data[a]; + return diff == 0 ? 0 : (diff < 0 ? -1 : 1); + } + + @Override + public void swap(int a, int b) { + long temp = data[a]; + data[a] = data[b]; + data[b] = temp; + } + }.run(); + } + + + // use insert() +// public void splice(int index, int value) { +// } + + +// public void subset(int start) { +// subset(start, count - start); +// } +// +// +// public void subset(int start, int num) { +// for (int i = 0; i < num; i++) { +// data[i] = data[i+start]; +// } +// count = num; +// } + + /** + * @webref intlist:method + * @brief Reverse the order of the list elements + */ + public void reverse() { + int ii = count - 1; + for (int i = 0; i < count/2; i++) { + long t = data[i]; + data[i] = data[ii]; + data[ii] = t; + --ii; + } + } + + + /** + * Randomize the order of the list elements. Note that this does not + * obey the randomSeed() function in PApplet. + * + * @webref intlist:method + * @brief Randomize the order of the list elements + */ + public void shuffle() { + Random r = new Random(); + int num = count; + while (num > 1) { + int value = r.nextInt(num); + num--; + long temp = data[num]; + data[num] = data[value]; + data[value] = temp; + } + } + + + /** + * Randomize the list order using the random() function from the specified + * sketch, allowing shuffle() to use its current randomSeed() setting. + */ + public void shuffle(PApplet sketch) { + int num = count; + while (num > 1) { + int value = (int) sketch.random(num); + num--; + long temp = data[num]; + data[num] = data[value]; + data[value] = temp; + } + } + + + public LongList copy() { + LongList outgoing = new LongList(data); + outgoing.count = count; + return outgoing; + } + + + /** + * Returns the actual array being used to store the data. For advanced users, + * this is the fastest way to access a large list. Suitable for iterating + * with a for() loop, but modifying the list will have terrible consequences. + */ + public long[] values() { + crop(); + return data; + } + + + @Override + public Iterator iterator() { +// public Iterator valueIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + LongList.this.remove(index); + index--; + } + + public Long next() { + return data[++index]; + } + + public boolean hasNext() { + return index+1 < count; + } + }; + } + + + /** + * Create a new array with a copy of all the values. + * + * @return an array sized by the length of the list with each of the values. + * @webref intlist:method + * @brief Create a new array with a copy of all the values + */ + public int[] array() { + return array(null); + } + + + /** + * Copy values into the specified array. If the specified array is null or + * not the same size, a new array will be allocated. + * @param array + */ + public int[] array(int[] array) { + if (array == null || array.length != count) { + array = new int[count]; + } + System.arraycopy(data, 0, array, 0, count); + return array; + } + + +// public int[] toIntArray() { +// int[] outgoing = new int[count]; +// for (int i = 0; i < count; i++) { +// outgoing[i] = (int) data[i]; +// } +// return outgoing; +// } + + +// public long[] toLongArray() { +// long[] outgoing = new long[count]; +// for (int i = 0; i < count; i++) { +// outgoing[i] = (long) data[i]; +// } +// return outgoing; +// } + + +// public float[] toFloatArray() { +// float[] outgoing = new float[count]; +// System.arraycopy(data, 0, outgoing, 0, count); +// return outgoing; +// } + + +// public double[] toDoubleArray() { +// double[] outgoing = new double[count]; +// for (int i = 0; i < count; i++) { +// outgoing[i] = data[i]; +// } +// return outgoing; +// } + + +// public String[] toStringArray() { +// String[] outgoing = new String[count]; +// for (int i = 0; i < count; i++) { +// outgoing[i] = String.valueOf(data[i]); +// } +// return outgoing; +// } + + + /** + * Returns a normalized version of this array. Called getPercent() for + * consistency with the Dict classes. It's a getter method because it needs + * to returns a new list (because IntList/Dict can't do percentages or + * normalization in place on int values). + */ + public FloatList getPercent() { + double sum = 0; + for (float value : array()) { + sum += value; + } + FloatList outgoing = new FloatList(count); + for (int i = 0; i < count; i++) { + double percent = data[i] / sum; + outgoing.set(i, (float) percent); + } + return outgoing; + } + + +// /** +// * Count the number of times each entry is found in this list. +// * Converts each entry to a String so it can be used as a key. +// */ +// public IntDict getTally() { +// IntDict outgoing = new IntDict(); +// for (int i = 0; i < count; i++) { +// outgoing.increment(String.valueOf(data[i])); +// } +// return outgoing; +// } + + + public LongList getSubset(int start) { + return getSubset(start, count - start); + } + + + public LongList getSubset(int start, int num) { + int[] subset = new int[num]; + System.arraycopy(data, start, subset, 0, num); + return new LongList(subset); + } + + + public String join(String separator) { + if (count == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(); + sb.append(data[0]); + for (int i = 1; i < count; i++) { + sb.append(separator); + sb.append(data[i]); + } + return sb.toString(); + } + + + public void print() { + for (int i = 0; i < count; i++) { + System.out.format("[%d] %d%n", i, data[i]); + } + } + + + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write entries to a PrintWriter, one per line + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(data[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + return "[ " + join(", ") + " ]"; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); + } +} diff --git a/core/src/processing/data/Sort.java b/core/src/processing/data/Sort.java index b42e0f141c..a83fea5514 100644 --- a/core/src/processing/data/Sort.java +++ b/core/src/processing/data/Sort.java @@ -41,6 +41,6 @@ protected int partition(int left, int right) { abstract public int size(); - abstract public float compare(int a, int b); + abstract public int compare(int a, int b); abstract public void swap(int a, int b); } \ No newline at end of file diff --git a/core/src/processing/data/StringDict.java b/core/src/processing/data/StringDict.java index 1e2128a121..c66a61e4df 100644 --- a/core/src/processing/data/StringDict.java +++ b/core/src/processing/data/StringDict.java @@ -3,6 +3,7 @@ import java.io.*; import java.util.HashMap; import java.util.Iterator; +import java.util.NoSuchElementException; import processing.core.PApplet; @@ -23,7 +24,7 @@ public class StringDict { protected String[] values; /** Internal implementation for faster lookups */ - private HashMap indices = new HashMap(); + private HashMap indices = new HashMap<>(); public StringDict() { @@ -108,6 +109,26 @@ public StringDict(String[][] pairs) { } + /** + * Create a dictionary that maps between column titles and cell entries + * in a TableRow. If two columns have the same name, the later column's + * values will override the earlier values. + */ + public StringDict(TableRow row) { + this(row.getColumnCount()); + + String[] titles = row.getColumnTitles(); + if (titles == null) { + titles = new StringList(IntList.fromRange(row.getColumnCount())).array(); + } + for (int col = 0; col < row.getColumnCount(); col++) { + set(titles[col], row.getString(col)); + } + // remove unused and overwritten entries + crop(); + } + + /** * @webref stringdict:method * @brief Returns the number of key/value pairs @@ -117,6 +138,29 @@ public int size() { } + /** + * Resize the internal data, this can only be used to shrink the list. + * Helpful for situations like sorting and then grabbing the top 50 entries. + */ + public void resize(int length) { + if (length > count) { + throw new IllegalArgumentException("resize() can only be used to shrink the dictionary"); + } + if (length < 1) { + throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher"); + } + + String[] newKeys = new String[length]; + String[] newValues = new String[length]; + PApplet.arrayCopy(keys, newKeys, length); + PApplet.arrayCopy(values, newValues, length); + keys = newKeys; + values = newValues; + count = length; + resetIndices(); + } + + /** * Remove all entries. * @@ -125,10 +169,67 @@ public int size() { */ public void clear() { count = 0; - indices = new HashMap(); + indices = new HashMap<>(); } + private void resetIndices() { + indices = new HashMap<>(count); + for (int i = 0; i < count; i++) { + indices.put(keys[i], i); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + public class Entry { + public String key; + public String value; + + Entry(String key, String value) { + this.key = key; + this.value = value; + } + } + + + public Iterable entries() { + return new Iterable() { + + public Iterator iterator() { + return entryIterator(); + } + }; + } + + + public Iterator entryIterator() { + return new Iterator() { + int index = -1; + + public void remove() { + removeIndex(index); + index--; + } + + public Entry next() { + ++index; + Entry e = new Entry(keys[index], values[index]); + return e; + } + + public boolean hasNext() { + return index+1 < size(); + } + }; + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + public String key(int index) { return keys[index]; } @@ -294,11 +395,21 @@ public void set(String key, String value) { } + public void setIndex(int index, String key, String value) { + if (index < 0 || index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } + keys[index] = key; + values[index] = value; + } + + public int index(String what) { Integer found = indices.get(what); return (found == null) ? -1 : found.intValue(); } + /** * @webref stringdict:method * @brief Check if a key is a part of the data structure @@ -323,12 +434,14 @@ protected void create(String key, String value) { * @webref stringdict:method * @brief Remove a key/value pair */ - public int remove(String key) { + public String remove(String key) { int index = index(key); - if (index != -1) { - removeIndex(index); + if (index == -1) { + throw new NoSuchElementException("'" + key + "' not found"); } - return index; + String value = values[index]; + removeIndex(index); + return value; } @@ -336,9 +449,8 @@ public String removeIndex(int index) { if (index < 0 || index >= count) { throw new ArrayIndexOutOfBoundsException(index); } - //System.out.println("index is " + which + " and " + keys[which]); - String key = keys[index]; - indices.remove(key); + String value = values[index]; + indices.remove(keys[index]); for (int i = index; i < count-1; i++) { keys[i] = keys[i+1]; values[i] = values[i+1]; @@ -347,10 +459,11 @@ public String removeIndex(int index) { count--; keys[count] = null; values[count] = null; - return key; + return value; } + public void swap(int a, int b) { String tkey = keys[a]; String tvalue = values[a]; @@ -412,7 +525,7 @@ public int size() { } @Override - public float compare(int a, int b) { + public int compare(int a, int b) { int diff = 0; if (useKeys) { diff = keys[a].compareToIgnoreCase(keys[b]); @@ -436,10 +549,7 @@ public void swap(int a, int b) { s.run(); // Set the indices after sort/swaps (performance fix 160411) - indices = new HashMap(); - for (int i = 0; i < count; i++) { - indices.put(keys[i], i); - } + resetIndices(); } @@ -464,8 +574,17 @@ public void print() { /** - * Write tab-delimited entries out to - * @param writer + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write tab-delimited entries to a PrintWriter */ public void write(PrintWriter writer) { for (int i = 0; i < count; i++) { @@ -475,17 +594,20 @@ public void write(PrintWriter writer) { } + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + StringList items = new StringList(); + for (int i = 0; i < count; i++) { + items.append(JSONObject.quote(keys[i])+ ": " + JSONObject.quote(values[i])); + } + return "{ " + items.join(", ") + " }"; + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " { "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append("\"" + keys[i] + "\": \"" + values[i] + "\""); - } - sb.append(" }"); - return sb.toString(); + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); } } diff --git a/core/src/processing/data/StringList.java b/core/src/processing/data/StringList.java index 215bc7adb2..2123a61432 100644 --- a/core/src/processing/data/StringList.java +++ b/core/src/processing/data/StringList.java @@ -1,5 +1,7 @@ package processing.data; +import java.io.File; +import java.io.PrintWriter; import java.util.Arrays; import java.util.Iterator; import java.util.Random; @@ -47,6 +49,8 @@ public StringList(String[] list) { /** * Construct a StringList from a random pile of objects. Null values will * stay null, but all the others will be converted to String values. + * + * @nowebref */ public StringList(Object... items) { count = items.length; @@ -514,8 +518,8 @@ public int size() { } @Override - public float compare(int a, int b) { - float diff = data[a].compareToIgnoreCase(data[b]); + public int compare(int a, int b) { + int diff = data[a].compareToIgnoreCase(data[b]); return reverse ? -diff : diff; } @@ -750,23 +754,47 @@ public String join(String separator) { public void print() { - for (int i = 0; i < size(); i++) { + for (int i = 0; i < count; i++) { System.out.format("[%d] %s%n", i, data[i]); } } + /** + * Save tab-delimited entries to a file (TSV format, UTF-8 encoding) + */ + public void save(File file) { + PrintWriter writer = PApplet.createWriter(file); + write(writer); + writer.close(); + } + + + /** + * Write entries to a PrintWriter, one per line + */ + public void write(PrintWriter writer) { + for (int i = 0; i < count; i++) { + writer.println(data[i]); + } + writer.flush(); + } + + + /** + * Return this dictionary as a String in JSON format. + */ + public String toJSON() { + StringList temp = new StringList(); + for (String item : this) { + temp.append(JSONObject.quote(item)); + } + return "[ " + temp.join(", ") + " ]"; + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName() + " size=" + size() + " [ "); - for (int i = 0; i < size(); i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(i + ": \"" + data[i] + "\""); - } - sb.append(" ]"); - return sb.toString(); + return getClass().getSimpleName() + " size=" + size() + " " + toJSON(); } } diff --git a/core/src/processing/data/Table.java b/core/src/processing/data/Table.java index 5d86e45bbe..e0684b4c1e 100644 --- a/core/src/processing/data/Table.java +++ b/core/src/processing/data/Table.java @@ -378,6 +378,15 @@ protected void parse(InputStream input, String options) throws IOException { } else { InputStreamReader isr = new InputStreamReader(input, encoding); BufferedReader reader = new BufferedReader(isr); + + // strip out the Unicode BOM, if present + reader.mark(1); + int c = reader.read(); + // if not the BOM, back up to the beginning again + if (c != '\uFEFF') { + reader.reset(); + } + /* if (awfulCSV) { parseAwfulCSV(reader, header); @@ -671,6 +680,12 @@ protected boolean ingest() { addPiece(start, i, hasEscapedQuotes); start = i+2; return true; + + } else { + // This is a lone-wolf quote, occasionally seen in exports. + // It's a single quote in the middle of some other text, + // and not escaped properly. Pray for the best! + i++; } } else { // not a quoted line @@ -1061,7 +1076,7 @@ public void parseInto(Object enclosingObject, String fieldName) { } Field[] fields = target.getDeclaredFields(); - ArrayList inuse = new ArrayList(); + ArrayList inuse = new ArrayList<>(); for (Field field : fields) { String name = field.getName(); if (getColumnIndex(name, false) != -1) { @@ -1697,19 +1712,19 @@ protected void loadBinary(InputStream is) throws IOException { columns[column] = new int[rowCount]; break; case LONG: - columns[column] = new long[rowCount];; + columns[column] = new long[rowCount]; break; case FLOAT: - columns[column] = new float[rowCount];; + columns[column] = new float[rowCount]; break; case DOUBLE: - columns[column] = new double[rowCount];; + columns[column] = new double[rowCount]; break; case STRING: - columns[column] = new String[rowCount];; + columns[column] = new String[rowCount]; break; case CATEGORY: - columns[column] = new int[rowCount];; + columns[column] = new int[rowCount]; break; default: throw new IllegalArgumentException(newType + " is not a valid column type."); @@ -1790,7 +1805,7 @@ public void addColumn(String title) { /** - * @param type the type to be used for the new column: INT, LONG, FLOAT, DOUBLE, STRING, or CATEGORY + * @param type the type to be used for the new column: INT, LONG, FLOAT, DOUBLE, or STRING */ public void addColumn(String title, int type) { insertColumn(columns.length, title, type); @@ -2200,7 +2215,7 @@ protected int getColumnIndex(String name, boolean report) { // only create this on first get(). subsequent calls to set the title will // also update this array, but only if it exists. if (columnIndices == null) { - columnIndices = new HashMap(); + columnIndices = new HashMap<>(); for (int col = 0; col < columns.length; col++) { columnIndices.put(columnTitles[col], col); } @@ -2413,10 +2428,13 @@ public void insertRow(int insert, Object[] columnData) { } } } + // Need to increment before setRow(), because it calls ensureBounds() + // https://github.com/processing/processing/issues/5406 + ++rowCount; setRow(insert, columnData); - rowCount++; } + /** * @webref table:method * @brief Removes a row from a table @@ -4033,17 +4051,78 @@ public void removeTokens(String tokens, String columnName) { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** * @webref table:method * @brief Trims whitespace from values * @see Table#removeTokens(String) */ public void trim() { + columnTitles = PApplet.trim(columnTitles); for (int col = 0; col < getColumnCount(); col++) { trim(col); } + // remove empty columns + int lastColumn = getColumnCount() - 1; + //while (isEmptyColumn(lastColumn) && lastColumn >= 0) { + while (isEmptyArray(getStringColumn(lastColumn)) && lastColumn >= 0) { + lastColumn--; + } + setColumnCount(lastColumn + 1); + + // trim() works from both sides + while (getColumnCount() > 0 && isEmptyArray(getStringColumn(0))) { + removeColumn(0); + } + + // remove empty rows (starting from the end) + int lastRow = lastRowIndex(); + //while (isEmptyRow(lastRow) && lastRow >= 0) { + while (isEmptyArray(getStringRow(lastRow)) && lastRow >= 0) { + lastRow--; + } + setRowCount(lastRow + 1); + + while (getRowCount() > 0 && isEmptyArray(getStringRow(0))) { + removeRow(0); + } } + + protected boolean isEmptyArray(String[] contents) { + for (String entry : contents) { + if (entry != null && entry.length() > 0) { + return false; + } + } + return true; + } + + + /* + protected boolean isEmptyColumn(int column) { + String[] contents = getStringColumn(column); + for (String entry : contents) { + if (entry != null && entry.length() > 0) { + return false; + } + } + return true; + } + + + protected boolean isEmptyRow(int row) { + String[] contents = getStringRow(row); + for (String entry : contents) { + if (entry != null && entry.length() > 0) { + return false; + } + } + return true; + } + */ + + /** * @param column ID number of the column to trim */ @@ -4119,8 +4198,8 @@ protected void checkBounds(int row, int column) { static class HashMapBlows { - HashMap dataToIndex = new HashMap(); - ArrayList indexToData = new ArrayList(); + HashMap dataToIndex = new HashMap<>(); + ArrayList indexToData = new ArrayList<>(); HashMapBlows() { } @@ -4179,7 +4258,7 @@ private void writeln(PrintWriter writer) throws IOException { void read(DataInputStream input) throws IOException { int count = input.readInt(); //System.out.println("found " + count + " entries in category map"); - dataToIndex = new HashMap(count); + dataToIndex = new HashMap<>(count); for (int i = 0; i < count; i++) { String str = input.readUTF(); //System.out.println(i + " " + str); @@ -4214,12 +4293,21 @@ void read(DataInputStream input) throws IOException { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - + /** + * Sorts (orders) a table based on the values in a column. + * + * @webref table:method + * @brief Orders a table based on the values in a column + * @param columnName the name of the column to sort + * @see Table#trim() + */ public void sort(String columnName) { sort(getColumnIndex(columnName), false); } - + /** + * @param column the column ID, e.g. 0, 1, 2 + */ public void sort(int column) { sort(column, false); } @@ -4245,7 +4333,7 @@ public int size() { } @Override - public float compare(int index1, int index2) { + public int compare(int index1, int index2) { int a = reverse ? order[index2] : order[index1]; int b = reverse ? order[index1] : order[index2]; @@ -4253,13 +4341,24 @@ public float compare(int index1, int index2) { case INT: return getInt(a, column) - getInt(b, column); case LONG: - return getLong(a, column) - getLong(b, column); + long diffl = getLong(a, column) - getLong(b, column); + return diffl == 0 ? 0 : (diffl < 0 ? -1 : 1); case FLOAT: - return getFloat(a, column) - getFloat(b, column); + float difff = getFloat(a, column) - getFloat(b, column); + return difff == 0 ? 0 : (difff < 0 ? -1 : 1); case DOUBLE: - return (float) (getDouble(a, column) - getDouble(b, column)); + double diffd = getDouble(a, column) - getDouble(b, column); + return diffd == 0 ? 0 : (diffd < 0 ? -1 : 1); case STRING: - return getString(a, column).compareToIgnoreCase(getString(b, column)); + String string1 = getString(a, column); + if (string1 == null) { + string1 = ""; // avoid NPE when cells are left empty + } + String string2 = getString(b, column); + if (string2 == null) { + string2 = ""; + } + return string1.compareToIgnoreCase(string2); case CATEGORY: return getInt(a, column) - getInt(b, column); default: @@ -4418,13 +4517,13 @@ public FloatDict getFloatDict(String keyColumnName, String valueColumnName) { public FloatDict getFloatDict(int keyColumn, int valueColumn) { return new FloatDict(getStringColumn(keyColumn), - getFloatColumn(valueColumn)); + getFloatColumn(valueColumn)); } public StringDict getStringDict(String keyColumnName, String valueColumnName) { return new StringDict(getStringColumn(keyColumnName), - getStringColumn(valueColumnName)); + getStringColumn(valueColumnName)); } @@ -4434,6 +4533,39 @@ public StringDict getStringDict(int keyColumn, int valueColumn) { } + public Map getRowMap(String columnName) { + int col = getColumnIndex(columnName); + return (col == -1) ? null : getRowMap(col); + } + + + /** + * Return a mapping that connects the entry from a column back to the row + * from which it came. For instance: + *
+   * Table t = loadTable("country-data.tsv", "header");
+   * // use the contents of the 'country' column to index the table
+   * Map lookup = t.getRowMap("country");
+   * // get the row that has "us" in the "country" column:
+   * TableRow usRow = lookup.get("us");
+   * // get an entry from the 'population' column
+   * int population = usRow.getInt("population");
+   * 
+ */ + public Map getRowMap(int column) { + Map outgoing = new HashMap<>(); + for (int row = 0; row < getRowCount(); row++) { + String id = getString(row, column); + outgoing.put(id, new RowPointer(this, row)); + } +// for (TableRow row : rows()) { +// String id = row.getString(column); +// outgoing.put(id, row); +// } + return outgoing; + } + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . diff --git a/core/src/processing/data/TableRow.java b/core/src/processing/data/TableRow.java index 0c2ae79da0..3ac59fe4c8 100644 --- a/core/src/processing/data/TableRow.java +++ b/core/src/processing/data/TableRow.java @@ -21,6 +21,7 @@ public interface TableRow { * @see TableRow#getFloat(int) */ public String getString(int column); + /** * @param columnName title of the column to reference */ @@ -34,12 +35,24 @@ public interface TableRow { * @see TableRow#getString(int) */ public int getInt(int column); + /** * @param columnName title of the column to reference */ public int getInt(String columnName); + /** + * @brief Get a long value from the specified column + * @param column ID number of the column to reference + * @see TableRow#getFloat(int) + * @see TableRow#getString(int) + */ + public long getLong(int column); + + /** + * @param columnName title of the column to reference + */ public long getLong(String columnName); /** @@ -50,12 +63,23 @@ public interface TableRow { * @see TableRow#getString(int) */ public float getFloat(int column); + /** * @param columnName title of the column to reference */ public float getFloat(String columnName); - + + /** + * @brief Get a double value from the specified column + * @param column ID number of the column to reference + * @see TableRow#getInt(int) + * @see TableRow#getString(int) + */ public double getDouble(int column); + + /** + * @param columnName title of the column to reference + */ public double getDouble(String columnName); /** @@ -81,12 +105,24 @@ public interface TableRow { * @see TableRow#setString(int, String) */ public void setInt(int column, int value); + /** * @param columnName title of the target column */ public void setInt(String columnName, int value); - + + /** + * @brief Store a long value in the specified column + * @param column ID number of the target column + * @param value value to assign + * @see TableRow#setFloat(int, float) + * @see TableRow#setString(int, String) + */ public void setLong(int column, long value); + + /** + * @param columnName title of the target column + */ public void setLong(String columnName, long value); /** @@ -98,21 +134,63 @@ public interface TableRow { * @see TableRow#setString(int, String) */ public void setFloat(int column, float value); + /** * @param columnName title of the target column */ public void setFloat(String columnName, float value); + /** + * @brief Store a double value in the specified column + * @param column ID number of the target column + * @param value value to assign + * @see TableRow#setFloat(int, float) + * @see TableRow#setString(int, String) + */ public void setDouble(int column, double value); + + /** + * @param columnName title of the target column + */ public void setDouble(String columnName, double value); + /** + * @webref tablerow:method + * @brief Get the column count. + * @return count of all columns + */ public int getColumnCount(); + + /** + * @brief Get the column type. + * @param columnName title of the target column + * @return type of the column + */ public int getColumnType(String columnName); + + /** + * @param column ID number of the target column + */ public int getColumnType(int column); - + + /** + * @brief Get the all column types + * @return list of all column types + */ public int[] getColumnTypes(); + /** + * @webref tablerow:method + * @brief Get the column title. + * @param column ID number of the target column + * @return title of the column + */ public String getColumnTitle(int column); + + /** + * @brief Get the all column titles + * @return list of all column titles + */ public String[] getColumnTitles(); public void write(PrintWriter writer); diff --git a/core/src/processing/data/XML.java b/core/src/processing/data/XML.java index fbe6f3b673..7089e65db3 100644 --- a/core/src/processing/data/XML.java +++ b/core/src/processing/data/XML.java @@ -231,7 +231,18 @@ public XML(String name) { protected XML(XML parent, Node node) { this.node = node; this.parent = parent; -// this.name = node.getNodeName(); + + for (String attr : parent.listAttributes()) { + if (attr.startsWith("xmlns")) { + // Copy namespace attributes to the kids, otherwise this XML + // can no longer be printed (or manipulated in most ways). + // Only do this when it's an Element, otherwise it's trying to set + // attributes on text notes (interstitial content). + if (node instanceof Element) { + setString(attr, parent.getString(attr)); + } + } + } } @@ -429,8 +440,7 @@ public XML[] getChildren() { /** * Quick accessor for an element at a particular index. * - * @webref xml:method - * @brief Returns the child element with the specified index value or path + * @nowebref */ public XML getChild(int index) { checkChildren(); @@ -441,6 +451,8 @@ public XML getChild(int index) { /** * Get a child by its name or path. * + * @webref xml:method + * @brief Returns the child element with the specified index value or path * @param name element name or path/to/element * @return the first matching element or null if no match */ @@ -583,7 +595,14 @@ public void removeChild(XML kid) { children = null; // TODO not efficient } - + /** + * Removes whitespace nodes. + * Those whitespace nodes are required to reconstruct the original XML's spacing and indentation. + * If you call this and use saveXML() your original spacing will be gone. + * + * @nowebref + * @brief Removes whitespace nodes + */ public void trim() { try { XPathFactory xpathFactory = XPathFactory.newInstance(); @@ -1094,10 +1113,18 @@ public String format(int indent) { String outgoing = stringWriter.toString(); // Add the XML declaration to the top if it's not there already - if (!outgoing.startsWith(decl)) { - return decl + sep + outgoing; - } else { + if (outgoing.startsWith(decl)) { + int declen = decl.length(); + int seplen = sep.length(); + if (outgoing.length() > declen + seplen && + !outgoing.substring(declen, declen + seplen).equals(sep)) { + // make sure there's a line break between the XML decl and the code + return outgoing.substring(0, decl.length()) + + sep + outgoing.substring(decl.length()); + } return outgoing; + } else { + return decl + sep + outgoing; } } catch (Exception e) { @@ -1107,6 +1134,11 @@ public String format(int indent) { } + public void print() { + PApplet.println(format(2)); + } + + /** * Return the XML document formatted with two spaces for indents. * Chosen to do this since it's the most common case (e.g. with println()). diff --git a/core/src/processing/javafx/PGraphicsFX2D.java b/core/src/processing/javafx/PGraphicsFX2D.java index d2f4fdb0a6..7868c7fe0f 100644 --- a/core/src/processing/javafx/PGraphicsFX2D.java +++ b/core/src/processing/javafx/PGraphicsFX2D.java @@ -41,7 +41,6 @@ import javafx.scene.image.WritableImage; import javafx.scene.image.WritablePixelFormat; import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; import javafx.scene.shape.ArcType; import javafx.scene.shape.StrokeLineCap; import javafx.scene.shape.StrokeLineJoin; @@ -64,10 +63,11 @@ public class PGraphicsFX2D extends PGraphics { Path2D workPath = new Path2D(); Path2D auxPath = new Path2D(); boolean openContour; + boolean adjustedForThinLines; /// break the shape at the next vertex (next vertex() call is a moveto()) boolean breakShape; - private float pathCoordsBuffer[] = new float[6]; + private float[] pathCoordsBuffer = new float[6]; /// coordinates for internal curve calculation float[] curveCoordX; @@ -76,7 +76,7 @@ public class PGraphicsFX2D extends PGraphics { float[] curveDrawY; int transformCount; - Affine transformStack[] = new Affine[MATRIX_STACK_DEPTH]; + Affine[] transformStack = new Affine[MATRIX_STACK_DEPTH]; // Line2D.Float line = new Line2D.Float(); // Ellipse2D.Float ellipse = new Ellipse2D.Float(); @@ -207,6 +207,7 @@ public void endDraw() { public void beginShape(int kind) { shape = kind; vertexCount = 0; + curveVertexCount = 0; workPath.reset(); auxPath.reset(); @@ -214,7 +215,7 @@ public void beginShape(int kind) { flushPixels(); if (drawingThinLines()) { - pushMatrix(); + adjustedForThinLines = true; translate(0.5f, 0.5f); } } @@ -238,7 +239,7 @@ public void texture(PImage image) { @Override public void vertex(float x, float y) { if (vertexCount == vertices.length) { - float temp[][] = new float[vertexCount<<1][VERTEX_FIELD_COUNT]; + float[][] temp = new float[vertexCount<<1][VERTEX_FIELD_COUNT]; System.arraycopy(vertices, 0, temp, 0, vertexCount); vertices = temp; //message(CHATTER, "allocating more vertices " + vertices.length); @@ -420,8 +421,9 @@ public void endShape(int mode) { } } shape = 0; - if (drawingThinLines()) { - popMatrix(); + if (adjustedForThinLines) { + adjustedForThinLines = false; + translate(-0.5f, -0.5f); } loaded = false; } @@ -643,9 +645,27 @@ protected void flushPixels() { int mw = mx2 - mx1; int mh = my2 - my1; - PixelWriter pw = context.getPixelWriter(); - pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels, - mx1 + my1 * pixelWidth, pixelWidth); + if (pixelDensity == 1) { + PixelWriter pw = context.getPixelWriter(); + pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels, + mx1 + my1 * pixelWidth, pixelWidth); + } else { + // The only way to push all the pixels is to draw a scaled-down image + if (snapshotImage == null || + snapshotImage.getWidth() != pixelWidth || + snapshotImage.getHeight() != pixelHeight) { + snapshotImage = new WritableImage(pixelWidth, pixelHeight); + } + + PixelWriter pw = snapshotImage.getPixelWriter(); + pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels, + mx1 + my1 * pixelWidth, pixelWidth); + context.save(); + resetMatrix(); + context.scale(1d / pixelDensity, 1d / pixelDensity); + context.drawImage(snapshotImage, mx1, my1, mw, mh, mx1, my1, mw, mh); + context.restore(); + } } modified = false; @@ -1011,8 +1031,8 @@ protected void imageImpl(PImage who, // Nuke the cache if the image was resized if (cash != null) { - if (who.width != cash.image.getWidth() || - who.height != cash.image.getHeight()) { + if (who.pixelWidth != cash.image.getWidth() || + who.pixelHeight != cash.image.getHeight()) { cash = null; } } @@ -1039,12 +1059,17 @@ protected void imageImpl(PImage who, // This might be a PGraphics that hasn't been drawn to yet. // Can't just bail because the cache has been created above. // https://github.com/processing/processing/issues/2208 - who.pixels = new int[who.width * who.height]; + who.pixels = new int[who.pixelWidth * who.pixelHeight]; } cash.update(who, tint, tintColor); who.setModified(false); } + u1 *= who.pixelDensity; + v1 *= who.pixelDensity; + u2 *= who.pixelDensity; + v2 *= who.pixelDensity; + context.drawImage(((ImageCache) getCache(who)).image, u1, v1, u2-u1, v2-v1, x1, y1, x2-x1, y2-y1); @@ -1085,14 +1110,14 @@ public void update(PImage source, boolean tint, int tintColor) { // BufferedImage.TYPE_INT_ARGB); // } if (image == null) { - image = new WritableImage(source.width, source.height); + image = new WritableImage(source.pixelWidth, source.pixelHeight); } //WritableRaster wr = image.getRaster(); PixelWriter pw = image.getPixelWriter(); if (tint) { - if (tintedTemp == null || tintedTemp.length != source.width) { - tintedTemp = new int[source.width]; + if (tintedTemp == null || tintedTemp.length != source.pixelWidth) { + tintedTemp = new int[source.pixelWidth]; } int a2 = (tintColor >> 24) & 0xff; // System.out.println("tint color is " + a2); @@ -1106,8 +1131,8 @@ public void update(PImage source, boolean tint, int tintColor) { // The target image is opaque, meaning that the source image has no // alpha (is not ARGB), and the tint has no alpha. int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + for (int y = 0; y < source.pixelHeight; y++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1122,7 +1147,7 @@ public void update(PImage source, boolean tint, int tintColor) { (((b2 * b1) & 0xff00) >> 8); } //wr.setDataElements(0, y, source.width, 1, tintedTemp); - pw.setPixels(0, y, source.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth); } // could this be any slower? // float[] scales = { tintR, tintG, tintB }; @@ -1136,19 +1161,19 @@ public void update(PImage source, boolean tint, int tintColor) { (tintColor & 0xffffff) == 0xffffff) { int hi = tintColor & 0xff000000; int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + for (int y = 0; y < source.pixelHeight; y++) { + for (int x = 0; x < source.pixelWidth; x++) { tintedTemp[x] = hi | (source.pixels[index++] & 0xFFFFFF); } //wr.setDataElements(0, y, source.width, 1, tintedTemp); - pw.setPixels(0, y, source.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth); } } else { int index = 0; - for (int y = 0; y < source.height; y++) { + for (int y = 0; y < source.pixelHeight; y++) { if (source.format == RGB) { int alpha = tintColor & 0xFF000000; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1159,7 +1184,7 @@ public void update(PImage source, boolean tint, int tintColor) { (((b2 * b1) & 0xff00) >> 8); } } else if (source.format == ARGB) { - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int a1 = (argb1 >> 24) & 0xff; int r1 = (argb1 >> 16) & 0xff; @@ -1173,14 +1198,14 @@ public void update(PImage source, boolean tint, int tintColor) { } } else if (source.format == ALPHA) { int lower = tintColor & 0xFFFFFF; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int a1 = source.pixels[index++]; tintedTemp[x] = (((a2 * a1) & 0xff00) << 16) | lower; } } //wr.setDataElements(0, y, source.width, 1, tintedTemp); - pw.setPixels(0, y, source.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth); } } // Not sure why ARGB images take the scales in this order... @@ -1202,8 +1227,8 @@ public void update(PImage source, boolean tint, int tintColor) { // If no tint, just shove the pixels on in there verbatim //wr.setDataElements(0, 0, source.width, source.height, source.pixels); //System.out.println("moving the big one"); - pw.setPixels(0, 0, source.width, source.height, - argbFormat, source.pixels, 0, source.width); + pw.setPixels(0, 0, source.pixelWidth, source.pixelHeight, + argbFormat, source.pixels, 0, source.pixelWidth); } this.tinted = tint; this.tintedColor = tintColor; @@ -2012,15 +2037,20 @@ public void backgroundImpl() { modified = false; loaded = false; + // Save drawing context (transform, fill, blend mode, etc.) + context.save(); + + // Reset transform to identity + context.setTransform(new Affine()); + // This only takes into account cases where this is the primary surface. // Not sure what we do with offscreen anyway. - Paint savedFill = context.getFill(); - BlendMode savedBlend = context.getGlobalBlendMode(); context.setFill(new Color(backgroundR, backgroundG, backgroundB, backgroundA)); context.setGlobalBlendMode(BlendMode.SRC_OVER); context.fillRect(0, 0, width, height); - context.setFill(savedFill); - context.setGlobalBlendMode(savedBlend); + + // Restore drawing context (transform, fill, blend mode, etc.) + context.restore(); } @@ -2126,8 +2156,9 @@ public void loadPixels() { snapshotImage = new WritableImage(pixelWidth, pixelHeight); } - SnapshotParameters sp = new SnapshotParameters(); + SnapshotParameters sp = null; if (pixelDensity != 1) { + sp = new SnapshotParameters(); sp.setTransform(Transform.scale(pixelDensity, pixelDensity)); } snapshotImage = ((PSurfaceFX) surface).canvas.snapshot(sp, snapshotImage); diff --git a/core/src/processing/javafx/PSurfaceFX.java b/core/src/processing/javafx/PSurfaceFX.java index 9cd5baa115..4061f36fca 100644 --- a/core/src/processing/javafx/PSurfaceFX.java +++ b/core/src/processing/javafx/PSurfaceFX.java @@ -22,6 +22,8 @@ package processing.javafx; +import com.sun.glass.ui.Screen; + import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; @@ -30,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.SynchronousQueue; import javafx.animation.Animation; import javafx.animation.KeyFrame; @@ -71,6 +74,8 @@ public class PSurfaceFX implements PSurface { final Animation animation; float frameRate = 60; + private SynchronousQueue drawExceptionQueue = new SynchronousQueue<>(); + public PSurfaceFX(PGraphicsFX2D graphics) { fx = graphics; canvas = new ResizableCanvas(); @@ -80,7 +85,16 @@ public PSurfaceFX(PGraphicsFX2D graphics) { new EventHandler() { public void handle(ActionEvent event) { long startNanoTime = System.nanoTime(); - sketch.handleDraw(); + try { + sketch.handleDraw(); + } catch (Throwable e) { + // Let exception handler thread crash with our exception + drawExceptionQueue.offer(e); + // Stop animating right now so nothing runs afterwards + // and crash frame can be for example traced by println() + animation.stop(); + return; + } long drawNanos = System.nanoTime() - startNanoTime; if (sketch.exitCalled()) { @@ -232,6 +246,19 @@ public void start(final Stage stage) { PApplet sketch = surface.sketch; + float renderScale = Screen.getMainScreen().getRenderScale(); + if (PApplet.platform == PConstants.MACOSX) { + for (Screen s : Screen.getScreens()) { + renderScale = Math.max(renderScale, s.getRenderScale()); + } + } + float uiScale = Screen.getMainScreen().getUIScale(); + if (sketch.pixelDensity == 2 && renderScale < 2) { + sketch.pixelDensity = 1; + sketch.g.pixelDensity = 1; + System.err.println("pixelDensity(2) is not available for this display"); + } + // Use AWT display code, because FX orders screens in different way GraphicsDevice displayDevice = null; @@ -245,7 +272,7 @@ public void start(final Stage stage) { displayDevice = devices[displayNum - 1]; } else { System.err.format("Display %d does not exist, " + - "using the default display instead.%n", displayNum); + "using the default display instead.%n", displayNum); for (int i = 0; i < devices.length; i++) { System.err.format("Display %d is %s%n", (i+1), devices[i]); } @@ -274,17 +301,8 @@ public void start(final Stage stage) { maxY = Math.max(maxY, bounds.getMaxY()); } } - if (minY < 0) { - // FX can't handle this - System.err.format("FX can't place window at negative Y coordinate " + - "[x=%d, y=%d]. Please make sure that your secondary " + - "display does not extend above the main display.", - (int) minX, (int) minY); - screenRect = primaryScreenRect; - } else { - screenRect = new Rectangle((int) minX, (int) minY, - (int) (maxX - minX), (int) (maxY - minY)); - } + screenRect = new Rectangle((int) minX, (int) minY, + (int) (maxX - minX), (int) (maxY - minY)); } // Set the displayWidth/Height variables inside PApplet, so that they're @@ -296,14 +314,14 @@ public void start(final Stage stage) { int sketchHeight = sketch.sketchHeight(); if (fullScreen || spanDisplays) { - sketchWidth = (int) screenRect.getWidth(); - sketchHeight = (int) screenRect.getHeight(); + sketchWidth = (int) (screenRect.getWidth() / uiScale); + sketchHeight = (int) (screenRect.getHeight() / uiScale); stage.initStyle(StageStyle.UNDECORATED); - stage.setX(screenRect.getMinX()); - stage.setY(screenRect.getMinY()); - stage.setWidth(screenRect.getWidth()); - stage.setHeight(screenRect.getHeight()); + stage.setX(screenRect.getMinX() / uiScale); + stage.setY(screenRect.getMinY() / uiScale); + stage.setWidth(screenRect.getWidth() / uiScale); + stage.setHeight(screenRect.getHeight() / uiScale); } Canvas canvas = surface.canvas; @@ -366,10 +384,40 @@ public void run() { } catch (InterruptedException e) { } } + startExceptionHandlerThread(); + setProcessingIcon(stage); } + private void startExceptionHandlerThread() { + Thread exceptionHandlerThread = new Thread(() -> { + Throwable drawException; + try { + drawException = drawExceptionQueue.take(); + } catch (InterruptedException e) { + return; + } + // Adapted from PSurfaceJOGL + if (drawException != null) { + if (drawException instanceof ThreadDeath) { +// System.out.println("caught ThreadDeath"); +// throw (ThreadDeath)cause; + } else if (drawException instanceof RuntimeException) { + throw (RuntimeException) drawException; + } else if (drawException instanceof UnsatisfiedLinkError) { + throw new UnsatisfiedLinkError(drawException.getMessage()); + } else { + throw new RuntimeException(drawException); + } + } + }); + exceptionHandlerThread.setDaemon(true); + exceptionHandlerThread.setName("Processing-FX-ExceptionHandler"); + exceptionHandlerThread.start(); + } + + /** Set the window (and dock, or whatever necessary) title. */ public void setTitle(String title) { // PApplicationFX.title = title; // store this in case the stage still null @@ -498,14 +546,11 @@ public void placeWindow(int[] location) { public void placeWindow(int[] location, int[] editorLocation) { if (sketch.sketchFullScreen()) { PApplet.hideMenuBar(); + return; } - //Dimension window = setFrameSize(); -// int contentW = Math.max(sketchWidth, MIN_WINDOW_WIDTH); -// int contentH = Math.max(sketchHeight, MIN_WINDOW_HEIGHT); -// System.out.println("stage size is " + stage.getWidth() + " " + stage.getHeight()); int wide = sketch.width; // stage.getWidth() is NaN here - int high = sketch.height; // stage.getHeight() + //int high = sketch.height; // stage.getHeight() if (location != null) { // a specific location was received from the Runner @@ -523,42 +568,10 @@ public void placeWindow(int[] location, int[] editorLocation) { stage.setY(locationY); } else { // doesn't fit -// // if it fits inside the editor window, -// // offset slightly from upper lefthand corner -// // so that it's plunked inside the text area -// locationX = editorLocation[0] + 66; -// locationY = editorLocation[1] + 66; -// -// if ((locationX + stage.getWidth() > sketch.displayWidth - 33) || -// (locationY + stage.getHeight() > sketch.displayHeight - 33)) { -// // otherwise center on screen -// locationX = (int) ((sketch.displayWidth - wide) / 2); -// locationY = (int) ((sketch.displayHeight - high) / 2); -// } - locationX = (sketch.displayWidth - wide) / 2; - locationY = (sketch.displayHeight - high) / 2; - stage.setX(locationX); - stage.setY(locationY); + stage.centerOnScreen(); } } else { // just center on screen - //setFrameCentered(); - } - if (stage.getY() < 0) { - // Windows actually allows you to place frames where they can't be - // closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508 - //frame.setLocation(frameLoc.x, 30); - stage.setY(30); - } - - //canvas.setBounds((contentW - sketchWidth)/2, - // (contentH - sketchHeight)/2, - // sketchWidth, sketchHeight); - - // handle frame resizing events - //setupFrameResizeListener(); - - if (sketch.getGraphics().displayable()) { - setVisible(true); + stage.centerOnScreen(); } } @@ -603,14 +616,24 @@ public void setLocation(int x, int y) { } - public void setSize(int width, int height) { + public void setSize(int wide, int high) { + // When the surface is set to resizable via surface.setResizable(true), + // a crash may occur if the user sets the window to size zero. + // https://github.com/processing/processing/issues/5052 + if (high <= 0) { + high = 1; + } + if (wide <= 0) { + wide = 1; + } + //System.out.format("%s.setSize(%d, %d)%n", getClass().getSimpleName(), width, height); Scene scene = stage.getScene(); double decorH = stage.getWidth() - scene.getWidth(); double decorV = stage.getHeight() - scene.getHeight(); - stage.setWidth(width + decorH); - stage.setHeight(height + decorV); - fx.setSize(width, height); + stage.setWidth(wide + decorH); + stage.setHeight(high + decorV); + fx.setSize(wide, high); } @@ -806,11 +829,6 @@ protected void fxMouseEvent(MouseEvent fxEvent) { int count = fxEvent.getClickCount(); int action = mouseMap.get(fxEvent.getEventType()); - //EventType et = nativeEvent.getEventType(); -// if (et == MouseEvent.MOUSE_PRESSED) { -// peAction = processing.event.MouseEvent.PRESS; -// } else if (et == MouseEvent.MOUSE_RELEASED) { -// peAction = processing.event.MouseEvent.RELEASE; int modifiers = 0; if (fxEvent.isShiftDown()) { @@ -827,20 +845,19 @@ protected void fxMouseEvent(MouseEvent fxEvent) { } int button = 0; - if (fxEvent.isPrimaryButtonDown()) { - button = PConstants.LEFT; - } else if (fxEvent.isSecondaryButtonDown()) { - button = PConstants.RIGHT; - } else if (fxEvent.isMiddleButtonDown()) { - button = PConstants.CENTER; - } - - // If running on Mac OS, allow ctrl-click as right mouse. - // Verified to be necessary with Java 8u45. - if (PApplet.platform == PConstants.MACOSX && - fxEvent.isControlDown() && - button == PConstants.LEFT) { - button = PConstants.RIGHT; + switch (fxEvent.getButton()) { + case PRIMARY: + button = PConstants.LEFT; + break; + case SECONDARY: + button = PConstants.RIGHT; + break; + case MIDDLE: + button = PConstants.CENTER; + break; + case NONE: + // not currently handled + break; } //long when = nativeEvent.getWhen(); // from AWT @@ -853,23 +870,37 @@ protected void fxMouseEvent(MouseEvent fxEvent) { x, y, button, count)); } + // https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/ScrollEvent.html + protected void fxScrollEvent(ScrollEvent fxEvent) { + // the number of steps/clicks on the wheel for a mouse wheel event. + int count = (int) -(fxEvent.getDeltaY() / fxEvent.getMultiplierY()); - // https://docs.oracle.com/javafx/2/api/javafx/scene/input/ScrollEvent.html - protected void fxScrollEvent(ScrollEvent event) { -// //case java.awt.event.MouseWheelEvent.WHEEL_UNIT_SCROLL: -// case java.awt.event.MouseEvent.MOUSE_WHEEL: -// peAction = MouseEvent.WHEEL; -// /* -// if (preciseWheelMethod != null) { -// try { -// peAmount = ((Double) preciseWheelMethod.invoke(nativeEvent, (Object[]) null)).floatValue(); -// } catch (Exception e) { -// preciseWheelMethod = null; -// } -// } -// */ -// peCount = ((MouseWheelEvent) nativeEvent).getWheelRotation(); -// break; + int action = processing.event.MouseEvent.WHEEL; + + int modifiers = 0; + if (fxEvent.isShiftDown()) { + modifiers |= processing.event.Event.SHIFT; + } + if (fxEvent.isControlDown()) { + modifiers |= processing.event.Event.CTRL; + } + if (fxEvent.isMetaDown()) { + modifiers |= processing.event.Event.META; + } + if (fxEvent.isAltDown()) { + modifiers |= processing.event.Event.ALT; + } + + // FX does not supply button info + int button = 0; + + long when = System.currentTimeMillis(); + int x = (int) fxEvent.getX(); // getSceneX()? + int y = (int) fxEvent.getY(); + + sketch.postEvent(new processing.event.MouseEvent(fxEvent, when, + action, modifiers, + x, y, button, count)); } diff --git a/core/src/processing/opengl/LinePath.java b/core/src/processing/opengl/LinePath.java index a3705df0fc..03c1d69d57 100644 --- a/core/src/processing/opengl/LinePath.java +++ b/core/src/processing/opengl/LinePath.java @@ -324,7 +324,7 @@ public final void reset() { static public class PathIterator { - float floatCoords[]; + float[] floatCoords; int typeIdx; @@ -334,7 +334,7 @@ static public class PathIterator { LinePath path; - static final int curvecoords[] = { 2, 2, 0 }; + static final int[] curvecoords = { 2, 2, 0 }; PathIterator(LinePath p2df) { this.path = p2df; @@ -470,7 +470,7 @@ private static void strokeTo(LinePath src, float width, int caps, int join, private static void pathTo(PathIterator pi, LineStroker lsink) { - float coords[] = new float[6]; + float[] coords = new float[6]; while (!pi.isDone()) { int color; switch (pi.currentSegment(coords)) { diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index e04de7500d..d57eb91269 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -272,6 +272,13 @@ public abstract class PGL { protected boolean clearColor = false; protected boolean pclearColor; + protected boolean clearDepth = false; + protected boolean pclearDepth; + + protected boolean clearStencil = false; + protected boolean pclearStencil; + + // ........................................................ // Error messages @@ -468,7 +475,7 @@ protected int getDefaultReadBuffer() { } - protected boolean isFBOBacked() {; + protected boolean isFBOBacked() { return fboLayerEnabled; } @@ -636,13 +643,49 @@ public boolean insideStopButton(float x, float y) { // Frame rendering - protected void clearBackground(float r, float g, float b, float a, boolean depth) { - if (depth) { + protected void clearDepthStencil() { + if (!pclearDepth && !pclearStencil) { + depthMask(true); clearDepth(1); - clear(PGL.DEPTH_BUFFER_BIT); + clearStencil(0); + clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT); + } else if (!pclearDepth) { + depthMask(true); + clearDepth(1); + clear(DEPTH_BUFFER_BIT); + } else if (!pclearStencil) { + clearStencil(0); + clear(STENCIL_BUFFER_BIT); } + } + + + protected void clearBackground(float r, float g, float b, float a, + boolean depth, boolean stencil) { clearColor(r, g, b, a); - clear(PGL.COLOR_BUFFER_BIT); + if (depth && stencil) { + clearDepth(1); + clearStencil(0); + clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT); + if (0 < sketch.frameCount) { + clearDepth = true; + clearStencil = true; + } + } else if (depth) { + clearDepth(1); + clear(DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT); + if (0 < sketch.frameCount) { + clearDepth = true; + } + } else if (stencil) { + clearStencil(0); + clear(STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT); + if (0 < sketch.frameCount) { + clearStencil = true; + } + } else { + clear(PGL.COLOR_BUFFER_BIT); + } if (0 < sketch.frameCount) { clearColor = true; } @@ -660,6 +703,12 @@ protected void beginRender() { pclearColor = clearColor; clearColor = false; + pclearDepth = clearDepth; + clearDepth = false; + + pclearStencil = clearStencil; + clearStencil = false; + if (SINGLE_BUFFERED && sketch.frameCount == 1) { restoreFirstFrame(); } @@ -912,7 +961,16 @@ private void createFBOLayer() { createDepthAndStencilBuffer(true, depthBits, stencilBits, packed); } - validateFramebuffer(); + int status = validateFramebuffer(); + + if (status == FRAMEBUFFER_INCOMPLETE_MULTISAMPLE && 1 < numSamples) { + System.err.println("Continuing with multisampling disabled"); + reqNumSamples = 1; + destroyFBOLayer(); + // try again + createFBOLayer(); + return; + } // Clear all buffers. clearDepth(1); @@ -1229,9 +1287,9 @@ protected PGL initTex2DShader() { PGL ppgl = primaryPGL ? this : graphics.getPrimaryPGL(); if (!ppgl.loadedTex2DShader || ppgl.tex2DShaderContext != ppgl.glContext) { - String[] preprocVertSrc = preprocessVertexSource(texVertShaderSource, getGLSLVersion()); + String[] preprocVertSrc = preprocessVertexSource(texVertShaderSource, getGLSLVersion(), getGLSLVersionSuffix()); String vertSource = PApplet.join(preprocVertSrc, "\n"); - String[] preprocFragSrc = preprocessFragmentSource(tex2DFragShaderSource, getGLSLVersion()); + String[] preprocFragSrc = preprocessFragmentSource(tex2DFragShaderSource, getGLSLVersion(), getGLSLVersionSuffix()); String fragSource = PApplet.join(preprocFragSrc, "\n"); ppgl.tex2DVertShader = createShader(VERTEX_SHADER, vertSource); ppgl.tex2DFragShader = createShader(FRAGMENT_SHADER, fragSource); @@ -1361,9 +1419,9 @@ protected PGL initTexRectShader() { PGL ppgl = primaryPGL ? this : graphics.getPrimaryPGL(); if (!ppgl.loadedTexRectShader || ppgl.texRectShaderContext != ppgl.glContext) { - String[] preprocVertSrc = preprocessVertexSource(texVertShaderSource, getGLSLVersion()); + String[] preprocVertSrc = preprocessVertexSource(texVertShaderSource, getGLSLVersion(), getGLSLVersionSuffix()); String vertSource = PApplet.join(preprocVertSrc, "\n"); - String[] preprocFragSrc = preprocessFragmentSource(texRectFragShaderSource, getGLSLVersion()); + String[] preprocFragSrc = preprocessFragmentSource(texRectFragShaderSource, getGLSLVersion(), getGLSLVersionSuffix()); String fragSource = PApplet.join(preprocFragSrc, "\n"); ppgl.texRectVertShader = createShader(VERTEX_SHADER, vertSource); ppgl.texRectFragShader = createShader(FRAGMENT_SHADER, fragSource); @@ -1790,6 +1848,7 @@ protected static int qualityToSamples(int quality) { abstract protected int getGLSLVersion(); + abstract protected String getGLSLVersionSuffix(); protected String[] loadVertexShader(String filename) { @@ -1822,28 +1881,29 @@ protected String[] loadVertexShader(URL url) { } - protected String[] loadVertexShader(String filename, int version) { + protected String[] loadVertexShader(String filename, int version, String versionSuffix) { return loadVertexShader(filename); } - protected String[] loadFragmentShader(String filename, int version) { + protected String[] loadFragmentShader(String filename, int version, String versionSuffix) { return loadFragmentShader(filename); } - protected String[] loadFragmentShader(URL url, int version) { + protected String[] loadFragmentShader(URL url, int version, String versionSuffix) { return loadFragmentShader(url); } - protected String[] loadVertexShader(URL url, int version) { + protected String[] loadVertexShader(URL url, int version, String versionSuffix) { return loadVertexShader(url); } protected static String[] preprocessFragmentSource(String[] fragSrc0, - int version) { + int version, + String versionSuffix) { if (containsVersionDirective(fragSrc0)) { // The user knows what she or he is doing return fragSrc0; @@ -1857,7 +1917,7 @@ protected static String[] preprocessFragmentSource(String[] fragSrc0, int offset = 1; fragSrc = preprocessShaderSource(fragSrc0, search, replace, offset); - fragSrc[0] = "#version " + version; + fragSrc[0] = "#version " + version + versionSuffix; } else { // We need to replace 'texture' uniform by 'texMap' uniform and // 'textureXXX()' functions by 'texture()' functions. Order of these @@ -1865,7 +1925,7 @@ protected static String[] preprocessFragmentSource(String[] fragSrc0, Pattern[] search = new Pattern[] { Pattern.compile(String.format(GLSL_ID_REGEX, "varying|attribute")), Pattern.compile(String.format(GLSL_ID_REGEX, "texture")), - Pattern.compile(String.format(GLSL_FN_REGEX, "textureRect|texture2D|texture3D|textureCube")), + Pattern.compile(String.format(GLSL_FN_REGEX, "texture2DRect|texture2D|texture3D|textureCube")), Pattern.compile(String.format(GLSL_ID_REGEX, "gl_FragColor")) }; String[] replace = new String[] { @@ -1874,15 +1934,20 @@ protected static String[] preprocessFragmentSource(String[] fragSrc0, int offset = 2; fragSrc = preprocessShaderSource(fragSrc0, search, replace, offset); - fragSrc[0] = "#version " + version; - fragSrc[1] = "out vec4 _fragColor;"; + fragSrc[0] = "#version " + version + versionSuffix; + if (" es".equals(versionSuffix)) { + fragSrc[1] = "out mediump vec4 _fragColor;"; + } else { + fragSrc[1] = "out vec4 _fragColor;"; + } } return fragSrc; } protected static String[] preprocessVertexSource(String[] vertSrc0, - int version) { + int version, + String versionSuffix) { if (containsVersionDirective(vertSrc0)) { // The user knows what she or he is doing return vertSrc0; @@ -1896,7 +1961,7 @@ protected static String[] preprocessVertexSource(String[] vertSrc0, int offset = 1; vertSrc = preprocessShaderSource(vertSrc0, search, replace, offset); - vertSrc[0] = "#version " + version; + vertSrc[0] = "#version " + version + versionSuffix; } else { // We need to replace 'texture' uniform by 'texMap' uniform and // 'textureXXX()' functions by 'texture()' functions. Order of these @@ -1905,7 +1970,7 @@ protected static String[] preprocessVertexSource(String[] vertSrc0, Pattern.compile(String.format(GLSL_ID_REGEX, "varying")), Pattern.compile(String.format(GLSL_ID_REGEX, "attribute")), Pattern.compile(String.format(GLSL_ID_REGEX, "texture")), - Pattern.compile(String.format(GLSL_FN_REGEX, "textureRect|texture2D|texture3D|textureCube")) + Pattern.compile(String.format(GLSL_FN_REGEX, "texture2DRect|texture2D|texture3D|textureCube")) }; String[] replace = new String[] { "out", "in", "texMap", "texture", @@ -1913,7 +1978,7 @@ protected static String[] preprocessVertexSource(String[] vertSrc0, int offset = 1; vertSrc = preprocessShaderSource(vertSrc0, search, replace, offset); - vertSrc[0] = "#version " + version; + vertSrc[0] = "#version " + version + versionSuffix; } return vertSrc; @@ -1931,8 +1996,9 @@ protected static String[] preprocessShaderSource(String[] src0, String[] src = new String[src0.length+offset]; for (int i = 0; i < src0.length; i++) { String line = src0[i]; - if (line.contains("#version")) { - line = ""; + int versionIndex = line.indexOf("#version"); + if (versionIndex >= 0) { + line = line.substring(0, versionIndex); } for (int j = 0; j < search.length; j++) { line = search[j].matcher(line).replaceAll(replace[j]); @@ -1945,8 +2011,12 @@ protected static String[] preprocessShaderSource(String[] src0, protected static boolean containsVersionDirective(String[] shSrc) { for (int i = 0; i < shSrc.length; i++) { String line = shSrc[i]; - if (line.contains("#version")) { - return true; + int versionIndex = line.indexOf("#version"); + if (versionIndex >= 0) { + int commentIndex = line.indexOf("//"); + if (commentIndex < 0 || versionIndex < commentIndex) { + return true; + } } } return false; @@ -1999,10 +2069,13 @@ protected boolean linked(int program) { } - protected boolean validateFramebuffer() { + protected int validateFramebuffer() { int status = checkFramebufferStatus(FRAMEBUFFER); if (status == FRAMEBUFFER_COMPLETE) { - return true; + return 0; + } else if (status == FRAMEBUFFER_UNDEFINED) { + System.err.println(String.format(FRAMEBUFFER_ERROR, + "framebuffer undefined")); } else if (status == FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { System.err.println(String.format(FRAMEBUFFER_ERROR, "incomplete attachment")); @@ -2015,14 +2088,26 @@ protected boolean validateFramebuffer() { } else if (status == FRAMEBUFFER_INCOMPLETE_FORMATS) { System.err.println(String.format(FRAMEBUFFER_ERROR, "incomplete formats")); + } else if (status == FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) { + System.err.println(String.format(FRAMEBUFFER_ERROR, + "incomplete draw buffer")); + } else if (status == FRAMEBUFFER_INCOMPLETE_READ_BUFFER) { + System.err.println(String.format(FRAMEBUFFER_ERROR, + "incomplete read buffer")); } else if (status == FRAMEBUFFER_UNSUPPORTED) { System.err.println(String.format(FRAMEBUFFER_ERROR, "framebuffer unsupported")); + } else if (status == FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) { + System.err.println(String.format(FRAMEBUFFER_ERROR, + "incomplete multisample buffer")); + } else if (status == FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS) { + System.err.println(String.format(FRAMEBUFFER_ERROR, + "incomplete layer targets")); } else { System.err.println(String.format(FRAMEBUFFER_ERROR, - "unknown error")); + "unknown error " + status)); } - return false; + return status; } protected boolean isES() { @@ -2042,7 +2127,7 @@ protected int[] getGLVersion() { String[] parts = version.split(" "); for (int i = 0; i < parts.length; i++) { if (0 < parts[i].indexOf(".")) { - String nums[] = parts[i].split("\\."); + String[] nums = parts[i].split("\\."); try { res[0] = Integer.parseInt(nums[0]); } catch (NumberFormatException e) { } @@ -2147,7 +2232,7 @@ protected boolean hasPackedDepthStencilSupport() { protected boolean hasAnisoSamplingSupport() { int major = getGLVersion()[0]; - if (major < 3) { + if (isES() || major < 3) { String ext = getString(EXTENSIONS); return -1 < ext.indexOf("_texture_filter_anisotropic"); } else { @@ -2596,12 +2681,17 @@ protected static void fillFloatBuffer(FloatBuffer buf, int i0, int i1, protected interface Tessellator { + public void setCallback(int flag); + public void setWindingRule(int rule); + public void setProperty(int property, int value); + public void beginPolygon(); + public void beginPolygon(Object data); public void endPolygon(); - public void setWindingRule(int rule); public void beginContour(); public void endContour(); public void addVertex(double[] v); + public void addVertex(double[] v, int n, Object data); } @@ -2713,6 +2803,7 @@ protected interface FontOutline { public static int TESS_WINDING_NONZERO; public static int TESS_WINDING_ODD; + public static int TESS_EDGE_FLAG; public static int GENERATE_MIPMAP_HINT; public static int FASTEST; @@ -2936,6 +3027,7 @@ protected interface FontOutline { public static int DEPTH_STENCIL; public static int FRAMEBUFFER_COMPLETE; + public static int FRAMEBUFFER_UNDEFINED; public static int FRAMEBUFFER_INCOMPLETE_ATTACHMENT; public static int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; public static int FRAMEBUFFER_INCOMPLETE_DIMENSIONS; @@ -2943,6 +3035,8 @@ protected interface FontOutline { public static int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; public static int FRAMEBUFFER_INCOMPLETE_READ_BUFFER; public static int FRAMEBUFFER_UNSUPPORTED; + public static int FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + public static int FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; public static int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; public static int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java index f3860e20dd..8fbdd5eff9 100644 --- a/core/src/processing/opengl/PGraphics2D.java +++ b/core/src/processing/opengl/PGraphics2D.java @@ -251,6 +251,31 @@ static protected PShape loadShapeImpl(PGraphics pg, } + ////////////////////////////////////////////////////////////// + + // SCREEN TRANSFORMS + + + @Override + public float modelX(float x, float y, float z) { + showDepthWarning("modelX"); + return 0; + } + + + @Override + public float modelY(float x, float y, float z) { + showDepthWarning("modelY"); + return 0; + } + + + @Override + public float modelZ(float x, float y, float z) { + showDepthWarning("modelZ"); + return 0; + } + ////////////////////////////////////////////////////////////// diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 5c17d87b57..b4f145eda6 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -49,6 +49,43 @@ public class PGraphicsOpenGL extends PGraphics { // ........................................................ + // Disposal of native resources + // Using the technique alternative to finalization described in: + // http://www.oracle.com/technetwork/articles/java/finalization-137655.html + private static ReferenceQueue refQueue = new ReferenceQueue<>(); + private static List> reachableWeakReferences = + new LinkedList<>(); + + static final private int MAX_DRAIN_GLRES_ITERATIONS = 10; + + static void drainRefQueueBounded() { + int iterations = 0; + while (iterations < MAX_DRAIN_GLRES_ITERATIONS) { + Disposable res = + (Disposable) refQueue.poll(); + if (res == null) { + break; + } + res.dispose(); + ++iterations; + } + } + + private static abstract class Disposable extends WeakReference { + protected Disposable(T obj) { + super(obj, refQueue); + drainRefQueueBounded(); + reachableWeakReferences.add(this); + } + + public void dispose() { + reachableWeakReferences.remove(this); + disposeNative(); + } + + abstract public void disposeNative(); + } + // Basic rendering parameters: /** Whether the PGraphics object is ready to render or not. */ @@ -225,6 +262,12 @@ public class PGraphicsOpenGL extends PGraphics { /** Aspect ratio of camera's view. */ public float cameraAspect; + /** Default camera properties. */ + public float defCameraFOV; + public float defCameraX, defCameraY, defCameraZ; + public float defCameraNear, defCameraFar; + public float defCameraAspect; + /** Distance between camera eye and center. */ protected float eyeDist; @@ -574,7 +617,7 @@ public void setPrimary(boolean primary) { format = ARGB; if (primary) { fbStack = new FrameBuffer[FB_STACK_DEPTH]; - fontMap = new WeakHashMap(); + fontMap = new WeakHashMap<>(); tessellator = new Tessellator(); } else { tessellator = getPrimaryPG().tessellator; @@ -594,14 +637,25 @@ public void setSize(int iwidth, int iheight) { height = iheight; updatePixelSize(); + texture = null; + ptexture = null; + // init perspective projection based on new dimensions - cameraFOV = 60 * DEG_TO_RAD; // at least for now - cameraX = width / 2.0f; - cameraY = height / 2.0f; - cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f)); - cameraNear = cameraZ / 10.0f; - cameraFar = cameraZ * 10.0f; - cameraAspect = (float) width / (float) height; + defCameraFOV = 60 * DEG_TO_RAD; // at least for now + defCameraX = width / 2.0f; + defCameraY = height / 2.0f; + defCameraZ = defCameraY / ((float) Math.tan(defCameraFOV / 2.0f)); + defCameraNear = defCameraZ / 10.0f; + defCameraFar = defCameraZ * 10.0f; + defCameraAspect = (float) width / (float) height; + + cameraFOV = defCameraFOV; + cameraX = defCameraX; + cameraY = defCameraY; + cameraZ = defCameraZ; + cameraNear = defCameraNear; + cameraFar = defCameraFar; + cameraAspect = defCameraAspect; sized = true; } @@ -641,6 +695,10 @@ protected void updatePixelSize() { float f = pgl.getPixelScale(); pixelWidth = (int)(width * f); pixelHeight = (int)(height * f); + if (primaryGraphics) { + parent.pixelWidth = pixelWidth; + parent.pixelHeight = pixelHeight; + } } @@ -806,42 +864,16 @@ protected void removeFontTexture(PFont font) { ////////////////////////////////////////////////////////////// - // RESOURCE HANDLING - // Using the technique alternative to finalization described in: - // http://www.oracle.com/technetwork/articles/java/finalization-137655.html - static final private int MAX_DRAIN_GLRES_ITERATIONS = 10; - - protected static class GLResourceTexture extends WeakReference { + protected static class GLResourceTexture extends Disposable { int glName; private PGL pgl; private int context; - static private ReferenceQueue refQueue = new ReferenceQueue(); - static private List refList = new ArrayList(); - - static void drainRefQueueBounded() { - ReferenceQueue refQueue = GLResourceTexture.referenceQueue(); - int iterations = 0; - while (iterations < MAX_DRAIN_GLRES_ITERATIONS) { - GLResourceTexture res = (GLResourceTexture)refQueue.poll(); - if (res == null) { - break; - } - res.dispose(); - ++iterations; - } - } - - static ReferenceQueue referenceQueue() { - return refQueue; - } - public GLResourceTexture(Texture tex) { - super(tex, refQueue); + super(tex); - drainRefQueueBounded(); pgl = tex.pg.getPrimaryPGL(); pgl.genTextures(1, intBuffer); @@ -849,11 +881,10 @@ public GLResourceTexture(Texture tex) { this.glName = tex.glName; this.context = tex.context; - - refList.add(this); } - private void disposeNative() { + @Override + public void disposeNative() { if (pgl != null) { if (glName != 0) { intBuffer.put(0, glName); @@ -864,13 +895,11 @@ private void disposeNative() { } } - void dispose() { - refList.remove(this); - disposeNative(); - } - @Override public boolean equals(Object obj) { + if (!(obj instanceof GLResourceTexture)) { + return false; + } GLResourceTexture other = (GLResourceTexture)obj; return other.glName == glName && other.context == context; @@ -886,36 +915,14 @@ public int hashCode() { } - protected static class GLResourceVertexBuffer extends WeakReference { + protected static class GLResourceVertexBuffer extends Disposable { int glId; private PGL pgl; private int context; - static private ReferenceQueue refQueue = new ReferenceQueue(); - static private List refList = new ArrayList(); - - static void drainRefQueueBounded() { - ReferenceQueue refQueue = GLResourceVertexBuffer.referenceQueue(); - int iterations = 0; - while (iterations < MAX_DRAIN_GLRES_ITERATIONS) { - GLResourceVertexBuffer res = (GLResourceVertexBuffer)refQueue.poll(); - if (res == null) { - break; - } - res.dispose(); - ++iterations; - } - } - - static ReferenceQueue referenceQueue() { - return refQueue; - } - public GLResourceVertexBuffer(VertexBuffer vbo) { - super(vbo, refQueue); - - drainRefQueueBounded(); + super(vbo); pgl = vbo.pgl.graphics.getPrimaryPGL(); pgl.genBuffers(1, intBuffer); @@ -923,11 +930,10 @@ public GLResourceVertexBuffer(VertexBuffer vbo) { this.glId = vbo.glId; this.context = vbo.context; - - refList.add(this); } - private void disposeNative() { + @Override + public void disposeNative() { if (pgl != null) { if (glId != 0) { intBuffer.put(0, glId); @@ -938,13 +944,11 @@ private void disposeNative() { } } - void dispose() { - refList.remove(this); - disposeNative(); - } - @Override public boolean equals(Object obj) { + if (!(obj instanceof GLResourceVertexBuffer)) { + return false; + } GLResourceVertexBuffer other = (GLResourceVertexBuffer)obj; return other.glId == glId && other.context == context; @@ -960,7 +964,7 @@ public int hashCode() { } - protected static class GLResourceShader extends WeakReference { + protected static class GLResourceShader extends Disposable { int glProgram; int glVertex; int glFragment; @@ -968,30 +972,8 @@ protected static class GLResourceShader extends WeakReference { private PGL pgl; private int context; - static private ReferenceQueue refQueue = new ReferenceQueue(); - static private List refList = new ArrayList(); - - static void drainRefQueueBounded() { - ReferenceQueue refQueue = GLResourceShader.referenceQueue(); - int iterations = 0; - while (iterations < MAX_DRAIN_GLRES_ITERATIONS) { - GLResourceShader res = (GLResourceShader)refQueue.poll(); - if (res == null) { - break; - } - res.dispose(); - ++iterations; - } - } - - static ReferenceQueue referenceQueue() { - return refQueue; - } - public GLResourceShader(PShader sh) { - super(sh, refQueue); - - drainRefQueueBounded(); + super(sh); this.pgl = sh.pgl.graphics.getPrimaryPGL(); sh.glProgram = pgl.createProgram(); @@ -1003,11 +985,10 @@ public GLResourceShader(PShader sh) { this.glFragment = sh.glFragment; this.context = sh.context; - - refList.add(this); } - private void disposeNative() { + @Override + public void disposeNative() { if (pgl != null) { if (glFragment != 0) { pgl.deleteShader(glFragment); @@ -1025,13 +1006,11 @@ private void disposeNative() { } } - void dispose() { - refList.remove(this); - disposeNative(); - } - @Override public boolean equals(Object obj) { + if (!(obj instanceof GLResourceShader)) { + return false; + } GLResourceShader other = (GLResourceShader)obj; return other.glProgram == glProgram && other.glVertex == glVertex && @@ -1051,7 +1030,7 @@ public int hashCode() { } - protected static class GLResourceFrameBuffer extends WeakReference { + protected static class GLResourceFrameBuffer extends Disposable { int glFbo; int glDepth; int glStencil; @@ -1061,30 +1040,8 @@ protected static class GLResourceFrameBuffer extends WeakReference private PGL pgl; private int context; - static private ReferenceQueue refQueue = new ReferenceQueue(); - static private List refList = new ArrayList(); - - static void drainRefQueueBounded() { - ReferenceQueue refQueue = GLResourceFrameBuffer.referenceQueue(); - int iterations = 0; - while (iterations < MAX_DRAIN_GLRES_ITERATIONS) { - GLResourceFrameBuffer res = (GLResourceFrameBuffer)refQueue.poll(); - if (res == null) { - break; - } - res.dispose(); - ++iterations; - } - } - - static ReferenceQueue referenceQueue() { - return refQueue; - } - public GLResourceFrameBuffer(FrameBuffer fb) { - super(fb, refQueue); - - drainRefQueueBounded(); + super(fb); pgl = fb.pg.getPrimaryPGL(); if (!fb.screenFb) { @@ -1118,11 +1075,10 @@ public GLResourceFrameBuffer(FrameBuffer fb) { } this.context = fb.context; - - refList.add(this); } - private void disposeNative() { + @Override + public void disposeNative() { if (pgl != null) { if (glFbo != 0) { intBuffer.put(0, glFbo); @@ -1153,13 +1109,11 @@ private void disposeNative() { } } - void dispose() { - refList.remove(this); - disposeNative(); - } - @Override public boolean equals(Object obj) { + if (!(obj instanceof GLResourceFrameBuffer)) { + return false; + } GLResourceFrameBuffer other = (GLResourceFrameBuffer)obj; return other.glFbo == glFbo && other.glDepth == glDepth && @@ -1236,7 +1190,7 @@ protected void createPolyBuffers() { if (!polyBuffersCreated || polyBuffersContextIsOutdated()) { polyBuffersContext = pgl.getCurrentContext(); - bufPolyVertex = new VertexBuffer(this, PGL.ARRAY_BUFFER, 3, PGL.SIZEOF_FLOAT); + bufPolyVertex = new VertexBuffer(this, PGL.ARRAY_BUFFER, 4, PGL.SIZEOF_FLOAT); bufPolyColor = new VertexBuffer(this, PGL.ARRAY_BUFFER, 1, PGL.SIZEOF_INT); bufPolyNormal = new VertexBuffer(this, PGL.ARRAY_BUFFER, 3, PGL.SIZEOF_FLOAT); bufPolyTexcoord = new VertexBuffer(this, PGL.ARRAY_BUFFER, 2, PGL.SIZEOF_FLOAT); @@ -1607,13 +1561,14 @@ protected void restoreGL() { } pgl.depthFunc(PGL.LEQUAL); - if (OPENGL_RENDERER.equals("VideoCore IV HW")) { - // Broadcom's VC IV driver is unhappy with either of these - // ignore for now + if (pgl.isES()) { + // neither GL_MULTISAMPLE nor GL_POLYGON_SMOOTH are part of GLES2 or GLES3 } else if (smooth < 1) { pgl.disable(PGL.MULTISAMPLE); } else if (1 <= smooth) { pgl.enable(PGL.MULTISAMPLE); + } + if (!pgl.isES()) { pgl.disable(PGL.POLYGON_SMOOTH); } @@ -1667,42 +1622,51 @@ protected void endReadPixels() { protected void beginPixelsOp(int op) { FrameBuffer pixfb = null; + FrameBuffer currfb = getCurrentFB(); if (primaryGraphics) { - if (op == OP_READ) { - if (pgl.isFBOBacked() && pgl.isMultisampled()) { - // Making sure the back texture is up-to-date... - pgl.syncBackTexture(); - // ...because the read framebuffer uses it as the color buffer (the - // draw framebuffer is MSAA so it cannot be read from it). - pixfb = readFramebuffer; - } else { - pixfb = drawFramebuffer; + FrameBuffer rfb = readFramebuffer; + FrameBuffer dfb = drawFramebuffer; + if ((currfb == rfb) || (currfb == dfb)) { + // Not user-provided FB, need to check if the correct FB is current. + if (op == OP_READ) { + if (pgl.isFBOBacked() && pgl.isMultisampled()) { + // Making sure the back texture is up-to-date... + pgl.syncBackTexture(); + // ...because the read framebuffer uses it as the color buffer (the + // draw framebuffer is MSAA so it cannot be read from it). + pixfb = rfb; + } else { + pixfb = dfb; + } + } else if (op == OP_WRITE) { + // We can write to the draw framebuffer irrespective of whether is + // FBO-baked or multisampled. + pixfb = dfb; } - } else if (op == OP_WRITE) { - // We can write to the draw framebuffer irrespective of whether is - // FBO-baked or multisampled. - pixfb = drawFramebuffer; } } else { FrameBuffer ofb = offscreenFramebuffer; FrameBuffer mfb = multisampleFramebuffer; - if (op == OP_READ) { - if (offscreenMultisample) { - // Making sure the offscreen FBO is up-to-date - int mask = PGL.COLOR_BUFFER_BIT; - if (hints[ENABLE_BUFFER_READING]) { - mask |= PGL.DEPTH_BUFFER_BIT | PGL.STENCIL_BUFFER_BIT; - } - if (ofb != null && mfb != null) { - mfb.copy(ofb, mask); + if ((currfb == ofb) || (currfb == mfb)) { + // Not user-provided FB, need to check if the correct FB is current. + if (op == OP_READ) { + if (offscreenMultisample) { + // Making sure the offscreen FBO is up-to-date + int mask = PGL.COLOR_BUFFER_BIT; + if (hints[ENABLE_BUFFER_READING]) { + mask |= PGL.DEPTH_BUFFER_BIT | PGL.STENCIL_BUFFER_BIT; + } + if (ofb != null && mfb != null) { + mfb.copy(ofb, mask); + } } + // We always read the screen pixels from the color FBO. + pixfb = ofb; + } else if (op == OP_WRITE) { + // We can write directly to the color FBO, or to the multisample FBO + // if multisampling is enabled. + pixfb = offscreenMultisample ? mfb : ofb; } - // We always read the screen pixels from the color FBO. - pixfb = ofb; - } else if (op == OP_WRITE) { - // We can write directly to the color FBO, or to the multisample FBO - // if multisampling is enabled. - pixfb = offscreenMultisample ? mfb : ofb; } } @@ -2030,6 +1994,9 @@ protected void endShape(int[] indices) { @Override public void textureWrap(int wrap) { + if (this.textureWrap != wrap) { + flush(); + } this.textureWrap = wrap; } @@ -2184,8 +2151,8 @@ protected void vertexImpl(float x, float y, float z, float u, float v) { } if (textured && textureMode == IMAGE) { - u /= textureImage.width; - v /= textureImage.height; + u /= textureImage.pixelWidth; + v /= textureImage.pixelHeight; } inGeo.addVertex(x, y, z, @@ -2398,8 +2365,8 @@ protected void flushPixels() { protected void flushPolys() { boolean customShader = polyShader != null; - boolean needNormals = customShader ? polyShader.accessNormals() : false; - boolean needTexCoords = customShader ? polyShader.accessTexCoords() : false; + boolean needNormals = customShader && polyShader.accessNormals(); + boolean needTexCoords = customShader && polyShader.accessTexCoords(); updatePolyBuffers(lights, texCache.hasTextures, needNormals, needTexCoords); @@ -2471,8 +2438,8 @@ protected void flushPolys() { protected void flushSortedPolys() { boolean customShader = polyShader != null; - boolean needNormals = customShader ? polyShader.accessNormals() : false; - boolean needTexCoords = customShader ? polyShader.accessTexCoords() : false; + boolean needNormals = customShader && polyShader.accessNormals(); + boolean needTexCoords = customShader && polyShader.accessTexCoords(); sorter.sort(tessGeo); @@ -3518,7 +3485,8 @@ public float textDescent() { @Override - protected float textWidthImpl(char buffer[], int start, int stop) { + protected float textWidthImpl(char[] buffer, int start, int stop) { + if (textFont == null) defaultFontOrDeath("textWidth"); Object font = textFont.getNative(); float twidth = 0; if (font != null) twidth = pgl.getTextWidth(font, buffer, start, stop); @@ -3542,8 +3510,14 @@ protected void handleTextSize(float size) { * Implementation of actual drawing for a line of text. */ @Override - protected void textLineImpl(char buffer[], int start, int stop, + protected void textLineImpl(char[] buffer, int start, int stop, float x, float y) { + + if (textMode == SHAPE && textFont.getNative() == null) { + showWarning("textMode(SHAPE) not available for .vlw fonts, " + + "use an .otf or .ttf instead."); + textMode(MODEL); + } if (textMode == MODEL) { textTex = getFontTexture(textFont); @@ -3680,7 +3654,7 @@ protected void textCharShapeImpl(char ch, float x, float y) { PGL.FontOutline outline = pgl.createFontOutline(ch, textFont.getNative()); // six element array received from the Java2D path iterator - float textPoints[] = new float[6]; + float[] textPoints = new float[6]; float lastX = 0; float lastY = 0; @@ -3798,6 +3772,13 @@ static protected void invTranslate(PMatrix3D matrix, } + static protected void invTranslate(PMatrix2D matrix, + float tx, float ty) { + matrix.preApply(1, 0, -tx, + 0, 1, -ty); + } + + static protected float matrixScale(PMatrix matrix) { // Volumetric scaling factor that is associated to the given // transformation matrix, which is given by the absolute value of its @@ -3883,8 +3864,8 @@ protected void rotateImpl(float angle, float v0, float v1, float v2) { } - static private void invRotate(PMatrix3D matrix, float angle, - float v0, float v1, float v2) { + static protected void invRotate(PMatrix3D matrix, float angle, + float v0, float v1, float v2) { float c = PApplet.cos(-angle); float s = PApplet.sin(-angle); float t = 1.0f - c; @@ -3896,6 +3877,11 @@ static private void invRotate(PMatrix3D matrix, float angle, } + static protected void invRotate(PMatrix2D matrix, float angle) { + matrix.rotate(-angle); + } + + /** * Same as scale(s, s, s). */ @@ -3937,6 +3923,11 @@ static protected void invScale(PMatrix3D matrix, float x, float y, float z) { } + static protected void invScale(PMatrix2D matrix, float x, float y) { + matrix.preApply(1/x, 0, 0, 1/y, 0, 0); + } + + @Override public void shearX(float angle) { float t = (float) Math.tan(angle); @@ -4327,7 +4318,8 @@ public void endCamera() { */ @Override public void camera() { - camera(cameraX, cameraY, cameraZ, cameraX, cameraY, 0, 0, 1, 0); + camera(defCameraX, defCameraY, defCameraZ, defCameraX, defCameraY, + 0, 0, 1, 0); } @@ -4391,6 +4383,10 @@ public void camera() { public void camera(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { + cameraX = eyeX; + cameraY = eyeY; + cameraZ = eyeZ; + // Calculating Z vector float z0 = eyeX - centerX; float z1 = eyeY - centerY; @@ -4548,7 +4544,7 @@ public void ortho(float left, float right, */ @Override public void perspective() { - perspective(cameraFOV, cameraAspect, cameraNear, cameraFar); + perspective(defCameraFOV, defCameraAspect, defCameraNear, defCameraFar); } @@ -4577,6 +4573,11 @@ public void frustum(float left, float right, float bottom, float top, // Flushing geometry with a different perspective configuration. flush(); + cameraFOV = 2 * (float) Math.atan2(top, znear); + cameraAspect = left / bottom; + cameraNear = znear; + cameraFar = zfar; + float n2 = 2 * znear; float w = right - left; float h = top - bottom; @@ -5292,7 +5293,7 @@ protected void backgroundImpl(PImage image) { protected void backgroundImpl() { flush(); pgl.clearBackground(backgroundR, backgroundG, backgroundB, backgroundA, - !hints[DISABLE_DEPTH_MASK]); + !hints[DISABLE_DEPTH_MASK], true); loaded = false; } @@ -5445,30 +5446,29 @@ protected void readPixels() { protected void drawPixels(int x, int y, int w, int h) { - int f = (int)pgl.getPixelScale(); - int len = f * w * f * h; + int len = w * h; if (nativePixels == null || nativePixels.length < len) { nativePixels = new int[len]; nativePixelBuffer = PGL.allocateIntBuffer(nativePixels); } try { - if (0 < x || 0 < y || w < width || h < height) { + if (0 < x || 0 < y || w < pixelWidth || h < pixelHeight) { // The pixels to be copied to the texture need to be consecutive, and // they are not in the pixels array, so putting each row one after // another in nativePixels. - int offset0 = f * (y * width + x); + int offset0 = y * pixelWidth + x; int offset1 = 0; - for (int yc = f * y; yc < f * (y + h); yc++) { - System.arraycopy(pixels, offset0, nativePixels, offset1, f * w); - offset0 += f * width; - offset1 += f * w; + for (int yc = y; yc < y + h; yc++) { + System.arraycopy(pixels, offset0, nativePixels, offset1, w); + offset0 += pixelWidth; + offset1 += w; } } else { PApplet.arrayCopy(pixels, 0, nativePixels, 0, len); } - PGL.javaToNativeARGB(nativePixels, f * w, f * h); + PGL.javaToNativeARGB(nativePixels, w, h); } catch (ArrayIndexOutOfBoundsException e) { } PGL.putIntArray(nativePixelBuffer, nativePixels); @@ -5492,19 +5492,19 @@ protected void drawPixels(int x, int y, int w, int h) { // (off)screen buffer. // First, copy the pixels to the texture. We don't need to invert the // pixel copy because the texture will be drawn inverted. - int tw = PApplet.min(texture.glWidth - f * x, f * w); - int th = PApplet.min(texture.glHeight - f * y, f * h); + int tw = PApplet.min(texture.glWidth - x, w); + int th = PApplet.min(texture.glHeight - y, h); pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName, - f * x, f * y, tw, th, nativePixelBuffer); + x, y, tw, th, nativePixelBuffer); beginPixelsOp(OP_WRITE); drawTexture(x, y, w, h); endPixelsOp(); } else { // We only need to copy the pixels to the back texture where we are - // currently drawing to. Because the texture is invertex along Y, we + // currently drawing to. Because the texture is inverted along Y, we // need to reflect that in the vertical arguments. pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName, - f * x, f * (height - (y + h)), f * w, f * h, nativePixelBuffer); + x, pixelHeight - (y + h), w, h, nativePixelBuffer); } } @@ -5577,10 +5577,10 @@ public boolean save(String filename) { @Override protected void processImageBeforeAsyncSave(PImage image) { if (image.format == AsyncPixelReader.OPENGL_NATIVE) { - PGL.nativeToJavaARGB(image.pixels, image.width, image.height); + PGL.nativeToJavaARGB(image.pixels, image.pixelWidth, image.pixelHeight); image.format = ARGB; } else if (image.format == AsyncPixelReader.OPENGL_NATIVE_OPAQUE) { - PGL.nativeToJavaRGB(image.pixels, image.width, image.height); + PGL.nativeToJavaRGB(image.pixels, image.pixelWidth, image.pixelHeight); image.format = RGB; } } @@ -5988,9 +5988,9 @@ protected void drawTexture(int x, int y, int w, int h) { pgl.disable(PGL.BLEND); pgl.drawTexture(texture.glTarget, texture.glName, texture.glWidth, texture.glHeight, - 0, 0, width, height, + 0, 0, pixelWidth, pixelHeight, 1, x, y, x + w, y + h, - x, height - (y + h), x + w, height - y); + x, pixelHeight - (y + h), x + w, pixelHeight - y); pgl.enable(PGL.BLEND); } } @@ -6025,7 +6025,7 @@ protected void drawPTexture() { @Override public void mask(PImage alpha) { updatePixelSize(); - if (alpha.width != pixelWidth || alpha.height != pixelHeight) { + if (alpha.pixelWidth != pixelWidth || alpha.pixelHeight != pixelHeight) { throw new RuntimeException("The PImage used with mask() must be " + "the same size as the applet."); } @@ -6386,8 +6386,8 @@ public Texture getTexture(PImage img) { if (tex == null) return null; if (img.isModified()) { - if (img.width != tex.width || img.height != tex.height) { - tex.init(img.width, img.height); + if (img.pixelWidth != tex.width || img.pixelHeight != tex.height) { + tex.init(img.pixelWidth, img.pixelHeight); } updateTexture(img, tex); } @@ -6429,9 +6429,16 @@ protected Object initCache(PImage img) { if (tex == null || tex.contextIsOutdated()) { tex = addTexture(img); if (tex != null) { + boolean dispose = img.pixels == null; img.loadPixels(); tex.set(img.pixels, img.format); img.setModified(); + if (dispose) { + // We only used the pixels to load the image into the texture and the user did not request + // to load the pixels, so we should dispose the pixels array to avoid wasting memory + img.pixels = null; + img.loaded = false; + } } } return tex; @@ -6513,8 +6520,8 @@ protected PImage wrapTexture(Texture tex) { // avoid initializing the pixels array. PImage img = new PImage(); img.parent = parent; - img.width = tex.width; - img.height = tex.height; + img.width = img.pixelWidth = tex.width; + img.height = img.pixelHeight = tex.height; img.format = ARGB; setCache(img, tex); return img; @@ -6547,6 +6554,8 @@ protected void deleteSurfaceTextures() { if (filterTexture != null) { filterTexture.dispose(); } + + } @@ -6791,16 +6800,14 @@ protected void setGLSettings() { // quality = temp; // } } - if (OPENGL_RENDERER.equals("VideoCore IV HW")) { - // Broadcom's VC IV driver is unhappy with either of these - // ignore for now + if (pgl.isES()) { + // neither GL_MULTISAMPLE nor GL_POLYGON_SMOOTH are part of GLES2 or GLES3 } else if (smooth < 1) { pgl.disable(PGL.MULTISAMPLE); } else if (1 <= smooth) { pgl.enable(PGL.MULTISAMPLE); } - // work around runtime exceptions in Broadcom's VC IV driver - if (false == OPENGL_RENDERER.equals("VideoCore IV HW")) { + if (!pgl.isES()) { pgl.disable(PGL.POLYGON_SMOOTH); } @@ -6814,6 +6821,9 @@ protected void setGLSettings() { } else { // offscreen surfaces are transparent by default. background(0x00 << 24 | (backgroundColor & 0xFFFFFF)); + + // Recreate offscreen FBOs + restartPGL(); } // Sets the default projection and camera (initializes modelview). @@ -6855,11 +6865,7 @@ protected void setGLSettings() { normalX = normalY = 0; normalZ = 1; - // Clear depth and stencil buffers. - pgl.depthMask(true); - pgl.clearDepth(1); - pgl.clearStencil(0); - pgl.clear(PGL.DEPTH_BUFFER_BIT | PGL.STENCIL_BUFFER_BIT); + pgl.clearDepthStencil(); if (hints[DISABLE_DEPTH_MASK]) { pgl.depthMask(false); @@ -6915,8 +6921,12 @@ protected void getGLParameters() { // overwrite the default shaders with vendor specific versions // if needed - if (OPENGL_RENDERER.equals("VideoCore IV HW") || // Broadcom's binary driver for Raspberry Pi - OPENGL_RENDERER.equals("Gallium 0.4 on VC4")) { // Mesa driver for same hardware + if (OPENGL_RENDERER.equals("VideoCore IV HW")) { // Broadcom's binary driver for Raspberry Pi + defLightShaderVertURL = + PGraphicsOpenGL.class.getResource("/processing/opengl/shaders/LightVert-brcm.glsl"); + defTexlightShaderVertURL = + PGraphicsOpenGL.class.getResource("/processing/opengl/shaders/TexLightVert-brcm.glsl"); + } else if (OPENGL_RENDERER.contains("VC4")) { // Mesa driver for same hardware defLightShaderVertURL = PGraphicsOpenGL.class.getResource("/processing/opengl/shaders/LightVert-vc4.glsl"); defTexlightShaderVertURL = @@ -7165,7 +7175,7 @@ static protected AttributeMap newAttributeMap() { static protected class AttributeMap extends HashMap { - public ArrayList names = new ArrayList(); + public ArrayList names = new ArrayList<>(); public int numComp = 0; // number of components for a single vertex @Override @@ -7691,9 +7701,9 @@ void allocate() { shininess = new float[PGL.DEFAULT_IN_VERTICES]; edges = new int[PGL.DEFAULT_IN_EDGES][3]; - fattribs = new HashMap(); - iattribs = new HashMap(); - battribs = new HashMap(); + fattribs = new HashMap<>(); + iattribs = new HashMap<>(); + battribs = new HashMap<>(); clear(); } @@ -7889,61 +7899,61 @@ int getVertexSum(PVector v) { // Expand arrays void expandVertices(int n) { - float temp[] = new float[3 * n]; + float[] temp = new float[3 * n]; PApplet.arrayCopy(vertices, 0, temp, 0, 3 * vertexCount); vertices = temp; } void expandColors(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(colors, 0, temp, 0, vertexCount); colors = temp; } void expandNormals(int n) { - float temp[] = new float[3 * n]; + float[] temp = new float[3 * n]; PApplet.arrayCopy(normals, 0, temp, 0, 3 * vertexCount); normals = temp; } void expandTexCoords(int n) { - float temp[] = new float[2 * n]; + float[] temp = new float[2 * n]; PApplet.arrayCopy(texcoords, 0, temp, 0, 2 * vertexCount); texcoords = temp; } void expandStrokeColors(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(strokeColors, 0, temp, 0, vertexCount); strokeColors = temp; } void expandStrokeWeights(int n) { - float temp[] = new float[n]; + float[] temp = new float[n]; PApplet.arrayCopy(strokeWeights, 0, temp, 0, vertexCount); strokeWeights = temp; } void expandAmbient(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(ambient, 0, temp, 0, vertexCount); ambient = temp; } void expandSpecular(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(specular, 0, temp, 0, vertexCount); specular = temp; } void expandEmissive(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(emissive, 0, temp, 0, vertexCount); emissive = temp; } void expandShininess(int n) { - float temp[] = new float[n]; + float[] temp = new float[n]; PApplet.arrayCopy(shininess, 0, temp, 0, vertexCount); shininess = temp; } @@ -7963,33 +7973,33 @@ void expandAttribs(int n) { void expandFloatAttrib(VertexAttribute attrib, int n) { float[] values = fattribs.get(attrib.name); - float temp[] = new float[attrib.size * n]; + float[] temp = new float[attrib.size * n]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); fattribs.put(attrib.name, temp); } void expandIntAttrib(VertexAttribute attrib, int n) { int[] values = iattribs.get(attrib.name); - int temp[] = new int[attrib.size * n]; + int[] temp = new int[attrib.size * n]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); iattribs.put(attrib.name, temp); } void expandBoolAttrib(VertexAttribute attrib, int n) { byte[] values = battribs.get(attrib.name); - byte temp[] = new byte[attrib.size * n]; + byte[] temp = new byte[attrib.size * n]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); battribs.put(attrib.name, temp); } void expandCodes(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(codes, 0, temp, 0, codeCount); codes = temp; } void expandEdges(int n) { - int temp[][] = new int[n][3]; + int[][] temp = new int[n][3]; PApplet.arrayCopy(edges, 0, temp, 0, edgeCount); edges = temp; } @@ -8023,73 +8033,73 @@ void trim() { } void trimVertices() { - float temp[] = new float[3 * vertexCount]; + float[] temp = new float[3 * vertexCount]; PApplet.arrayCopy(vertices, 0, temp, 0, 3 * vertexCount); vertices = temp; } void trimColors() { - int temp[] = new int[vertexCount]; + int[] temp = new int[vertexCount]; PApplet.arrayCopy(colors, 0, temp, 0, vertexCount); colors = temp; } void trimNormals() { - float temp[] = new float[3 * vertexCount]; + float[] temp = new float[3 * vertexCount]; PApplet.arrayCopy(normals, 0, temp, 0, 3 * vertexCount); normals = temp; } void trimTexCoords() { - float temp[] = new float[2 * vertexCount]; + float[] temp = new float[2 * vertexCount]; PApplet.arrayCopy(texcoords, 0, temp, 0, 2 * vertexCount); texcoords = temp; } void trimStrokeColors() { - int temp[] = new int[vertexCount]; + int[] temp = new int[vertexCount]; PApplet.arrayCopy(strokeColors, 0, temp, 0, vertexCount); strokeColors = temp; } void trimStrokeWeights() { - float temp[] = new float[vertexCount]; + float[] temp = new float[vertexCount]; PApplet.arrayCopy(strokeWeights, 0, temp, 0, vertexCount); strokeWeights = temp; } void trimAmbient() { - int temp[] = new int[vertexCount]; + int[] temp = new int[vertexCount]; PApplet.arrayCopy(ambient, 0, temp, 0, vertexCount); ambient = temp; } void trimSpecular() { - int temp[] = new int[vertexCount]; + int[] temp = new int[vertexCount]; PApplet.arrayCopy(specular, 0, temp, 0, vertexCount); specular = temp; } void trimEmissive() { - int temp[] = new int[vertexCount]; + int[] temp = new int[vertexCount]; PApplet.arrayCopy(emissive, 0, temp, 0, vertexCount); emissive = temp; } void trimShininess() { - float temp[] = new float[vertexCount]; + float[] temp = new float[vertexCount]; PApplet.arrayCopy(shininess, 0, temp, 0, vertexCount); shininess = temp; } void trimCodes() { - int temp[] = new int[codeCount]; + int[] temp = new int[codeCount]; PApplet.arrayCopy(codes, 0, temp, 0, codeCount); codes = temp; } void trimEdges() { - int temp[][] = new int[edgeCount][3]; + int[][] temp = new int[edgeCount][3]; PApplet.arrayCopy(edges, 0, temp, 0, edgeCount); edges = temp; } @@ -8109,21 +8119,21 @@ void trimAttribs() { void trimFloatAttrib(VertexAttribute attrib) { float[] values = fattribs.get(attrib.name); - float temp[] = new float[attrib.size * vertexCount]; + float[] temp = new float[attrib.size * vertexCount]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); fattribs.put(attrib.name, temp); } void trimIntAttrib(VertexAttribute attrib) { int[] values = iattribs.get(attrib.name); - int temp[] = new int[attrib.size * vertexCount]; + int[] temp = new int[attrib.size * vertexCount]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); iattribs.put(attrib.name, temp); } void trimBoolAttrib(VertexAttribute attrib) { byte[] values = battribs.get(attrib.name); - byte temp[] = new byte[attrib.size * vertexCount]; + byte[] temp = new byte[attrib.size * vertexCount]; PApplet.arrayCopy(values, 0, temp, 0, attrib.size * vertexCount); battribs.put(attrib.name, temp); } @@ -8414,9 +8424,9 @@ void addTrianglesEdges() { int i1 = 3 * i + 1; int i2 = 3 * i + 2; - addEdge(i0, i1, true, false); + addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); - addEdge(i2, i0, false, false); + addEdge(i2, i0, false, false); closeEdge(i2, i0); } } @@ -8427,9 +8437,9 @@ void addTriangleFanEdges() { int i1 = i; int i2 = i + 1; - addEdge(i0, i1, true, false); + addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); - addEdge(i2, i0, false, false); + addEdge(i2, i0, false, false); closeEdge(i2, i0); } } @@ -8446,9 +8456,9 @@ void addTriangleStripEdges() { i2 = i - 1; } - addEdge(i0, i1, true, false); + addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); - addEdge(i2, i0, false, false); + addEdge(i2, i0, false, false); closeEdge(i2, i0); } } @@ -8460,7 +8470,7 @@ void addQuadsEdges() { int i2 = 4 * i + 2; int i3 = 4 * i + 3; - addEdge(i0, i1, true, false); + addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); addEdge(i2, i3, false, false); addEdge(i3, i0, false, false); @@ -8475,10 +8485,10 @@ void addQuadStripEdges() { int i2 = 2 * qd + 1; int i3 = 2 * qd; - addEdge(i0, i1, true, false); + addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); - addEdge(i2, i3, false, false); - addEdge(i3, i0, false, true); + addEdge(i2, i3, false, false); + addEdge(i3, i0, false, false); closeEdge(i3, i0); } } @@ -9096,7 +9106,6 @@ int[] addSphere(float r, int detailU, int detailV, indices[indCount + 3 * i + 1] = i0; indices[indCount + 3 * i + 2] = i0 + 1; - addEdge(i0, i0 + 1, true, true); addEdge(i0, i1, true, true); } indCount += 3 * detailU; @@ -9129,7 +9138,7 @@ static protected class TessGeometry { FloatBuffer polyShininessBuffer; // Generic attributes - HashMap polyAttribBuffers = new HashMap(); + HashMap polyAttribBuffers = new HashMap<>(); int polyIndexCount; int firstPolyIndex; @@ -9184,9 +9193,9 @@ static protected class TessGeometry { float[] pointOffsets; short[] pointIndices; - HashMap fpolyAttribs = new HashMap(); - HashMap ipolyAttribs = new HashMap(); - HashMap bpolyAttribs = new HashMap(); + HashMap fpolyAttribs = new HashMap<>(); + HashMap ipolyAttribs = new HashMap<>(); + HashMap bpolyAttribs = new HashMap<>(); TessGeometry(PGraphicsOpenGL pg, AttributeMap attr, int mode) { this.pg = pg; @@ -9666,56 +9675,56 @@ protected void updatePointIndicesBuffer(int offset, int size) { // Expand arrays void expandPolyVertices(int n) { - float temp[] = new float[4 * n]; + float[] temp = new float[4 * n]; PApplet.arrayCopy(polyVertices, 0, temp, 0, 4 * polyVertexCount); polyVertices = temp; polyVerticesBuffer = PGL.allocateFloatBuffer(polyVertices); } void expandPolyColors(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(polyColors, 0, temp, 0, polyVertexCount); polyColors = temp; polyColorsBuffer = PGL.allocateIntBuffer(polyColors); } void expandPolyNormals(int n) { - float temp[] = new float[3 * n]; + float[] temp = new float[3 * n]; PApplet.arrayCopy(polyNormals, 0, temp, 0, 3 * polyVertexCount); polyNormals = temp; polyNormalsBuffer = PGL.allocateFloatBuffer(polyNormals); } void expandPolyTexCoords(int n) { - float temp[] = new float[2 * n]; + float[] temp = new float[2 * n]; PApplet.arrayCopy(polyTexCoords, 0, temp, 0, 2 * polyVertexCount); polyTexCoords = temp; polyTexCoordsBuffer = PGL.allocateFloatBuffer(polyTexCoords); } void expandPolyAmbient(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(polyAmbient, 0, temp, 0, polyVertexCount); polyAmbient = temp; polyAmbientBuffer = PGL.allocateIntBuffer(polyAmbient); } void expandPolySpecular(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(polySpecular, 0, temp, 0, polyVertexCount); polySpecular = temp; polySpecularBuffer = PGL.allocateIntBuffer(polySpecular); } void expandPolyEmissive(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(polyEmissive, 0, temp, 0, polyVertexCount); polyEmissive = temp; polyEmissiveBuffer = PGL.allocateIntBuffer(polyEmissive); } void expandPolyShininess(int n) { - float temp[] = new float[n]; + float[] temp = new float[n]; PApplet.arrayCopy(polyShininess, 0, temp, 0, polyVertexCount); polyShininess = temp; polyShininessBuffer = PGL.allocateFloatBuffer(polyShininess); @@ -9736,7 +9745,7 @@ void expandAttributes(int n) { void expandFloatAttribute(VertexAttribute attrib, int n) { float[] array = fpolyAttribs.get(attrib.name); - float temp[] = new float[attrib.tessSize * n]; + float[] temp = new float[attrib.tessSize * n]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); fpolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateFloatBuffer(temp)); @@ -9744,7 +9753,7 @@ void expandFloatAttribute(VertexAttribute attrib, int n) { void expandIntAttribute(VertexAttribute attrib, int n) { int[] array = ipolyAttribs.get(attrib.name); - int temp[] = new int[attrib.tessSize * n]; + int[] temp = new int[attrib.tessSize * n]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); ipolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateIntBuffer(temp)); @@ -9752,70 +9761,70 @@ void expandIntAttribute(VertexAttribute attrib, int n) { void expandBoolAttribute(VertexAttribute attrib, int n) { byte[] array = bpolyAttribs.get(attrib.name); - byte temp[] = new byte[attrib.tessSize * n]; + byte[] temp = new byte[attrib.tessSize * n]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); bpolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateByteBuffer(temp)); } void expandPolyIndices(int n) { - short temp[] = new short[n]; + short[] temp = new short[n]; PApplet.arrayCopy(polyIndices, 0, temp, 0, polyIndexCount); polyIndices = temp; polyIndicesBuffer = PGL.allocateShortBuffer(polyIndices); } void expandLineVertices(int n) { - float temp[] = new float[4 * n]; + float[] temp = new float[4 * n]; PApplet.arrayCopy(lineVertices, 0, temp, 0, 4 * lineVertexCount); lineVertices = temp; lineVerticesBuffer = PGL.allocateFloatBuffer(lineVertices); } void expandLineColors(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(lineColors, 0, temp, 0, lineVertexCount); lineColors = temp; lineColorsBuffer = PGL.allocateIntBuffer(lineColors); } void expandLineDirections(int n) { - float temp[] = new float[4 * n]; + float[] temp = new float[4 * n]; PApplet.arrayCopy(lineDirections, 0, temp, 0, 4 * lineVertexCount); lineDirections = temp; lineDirectionsBuffer = PGL.allocateFloatBuffer(lineDirections); } void expandLineIndices(int n) { - short temp[] = new short[n]; + short[] temp = new short[n]; PApplet.arrayCopy(lineIndices, 0, temp, 0, lineIndexCount); lineIndices = temp; lineIndicesBuffer = PGL.allocateShortBuffer(lineIndices); } void expandPointVertices(int n) { - float temp[] = new float[4 * n]; + float[] temp = new float[4 * n]; PApplet.arrayCopy(pointVertices, 0, temp, 0, 4 * pointVertexCount); pointVertices = temp; pointVerticesBuffer = PGL.allocateFloatBuffer(pointVertices); } void expandPointColors(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(pointColors, 0, temp, 0, pointVertexCount); pointColors = temp; pointColorsBuffer = PGL.allocateIntBuffer(pointColors); } void expandPointOffsets(int n) { - float temp[] = new float[2 * n]; + float[] temp = new float[2 * n]; PApplet.arrayCopy(pointOffsets, 0, temp, 0, 2 * pointVertexCount); pointOffsets = temp; pointOffsetsBuffer = PGL.allocateFloatBuffer(pointOffsets); } void expandPointIndices(int n) { - short temp[] = new short[n]; + short[] temp = new short[n]; PApplet.arrayCopy(pointIndices, 0, temp, 0, pointIndexCount); pointIndices = temp; pointIndicesBuffer = PGL.allocateShortBuffer(pointIndices); @@ -9864,56 +9873,56 @@ void trim() { } void trimPolyVertices() { - float temp[] = new float[4 * polyVertexCount]; + float[] temp = new float[4 * polyVertexCount]; PApplet.arrayCopy(polyVertices, 0, temp, 0, 4 * polyVertexCount); polyVertices = temp; polyVerticesBuffer = PGL.allocateFloatBuffer(polyVertices); } void trimPolyColors() { - int temp[] = new int[polyVertexCount]; + int[] temp = new int[polyVertexCount]; PApplet.arrayCopy(polyColors, 0, temp, 0, polyVertexCount); polyColors = temp; polyColorsBuffer = PGL.allocateIntBuffer(polyColors); } void trimPolyNormals() { - float temp[] = new float[3 * polyVertexCount]; + float[] temp = new float[3 * polyVertexCount]; PApplet.arrayCopy(polyNormals, 0, temp, 0, 3 * polyVertexCount); polyNormals = temp; polyNormalsBuffer = PGL.allocateFloatBuffer(polyNormals); } void trimPolyTexCoords() { - float temp[] = new float[2 * polyVertexCount]; + float[] temp = new float[2 * polyVertexCount]; PApplet.arrayCopy(polyTexCoords, 0, temp, 0, 2 * polyVertexCount); polyTexCoords = temp; polyTexCoordsBuffer = PGL.allocateFloatBuffer(polyTexCoords); } void trimPolyAmbient() { - int temp[] = new int[polyVertexCount]; + int[] temp = new int[polyVertexCount]; PApplet.arrayCopy(polyAmbient, 0, temp, 0, polyVertexCount); polyAmbient = temp; polyAmbientBuffer = PGL.allocateIntBuffer(polyAmbient); } void trimPolySpecular() { - int temp[] = new int[polyVertexCount]; + int[] temp = new int[polyVertexCount]; PApplet.arrayCopy(polySpecular, 0, temp, 0, polyVertexCount); polySpecular = temp; polySpecularBuffer = PGL.allocateIntBuffer(polySpecular); } void trimPolyEmissive() { - int temp[] = new int[polyVertexCount]; + int[] temp = new int[polyVertexCount]; PApplet.arrayCopy(polyEmissive, 0, temp, 0, polyVertexCount); polyEmissive = temp; polyEmissiveBuffer = PGL.allocateIntBuffer(polyEmissive); } void trimPolyShininess() { - float temp[] = new float[polyVertexCount]; + float[] temp = new float[polyVertexCount]; PApplet.arrayCopy(polyShininess, 0, temp, 0, polyVertexCount); polyShininess = temp; polyShininessBuffer = PGL.allocateFloatBuffer(polyShininess); @@ -9934,7 +9943,7 @@ void trimPolyAttributes() { void trimFloatAttribute(VertexAttribute attrib) { float[] array = fpolyAttribs.get(attrib.name); - float temp[] = new float[attrib.tessSize * polyVertexCount]; + float[] temp = new float[attrib.tessSize * polyVertexCount]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); fpolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateFloatBuffer(temp)); @@ -9942,7 +9951,7 @@ void trimFloatAttribute(VertexAttribute attrib) { void trimIntAttribute(VertexAttribute attrib) { int[] array = ipolyAttribs.get(attrib.name); - int temp[] = new int[attrib.tessSize * polyVertexCount]; + int[] temp = new int[attrib.tessSize * polyVertexCount]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); ipolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateIntBuffer(temp)); @@ -9950,70 +9959,70 @@ void trimIntAttribute(VertexAttribute attrib) { void trimBoolAttribute(VertexAttribute attrib) { byte[] array = bpolyAttribs.get(attrib.name); - byte temp[] = new byte[attrib.tessSize * polyVertexCount]; + byte[] temp = new byte[attrib.tessSize * polyVertexCount]; PApplet.arrayCopy(array, 0, temp, 0, attrib.tessSize * polyVertexCount); bpolyAttribs.put(attrib.name, temp); polyAttribBuffers.put(attrib.name, PGL.allocateByteBuffer(temp)); } void trimPolyIndices() { - short temp[] = new short[polyIndexCount]; + short[] temp = new short[polyIndexCount]; PApplet.arrayCopy(polyIndices, 0, temp, 0, polyIndexCount); polyIndices = temp; polyIndicesBuffer = PGL.allocateShortBuffer(polyIndices); } void trimLineVertices() { - float temp[] = new float[4 * lineVertexCount]; + float[] temp = new float[4 * lineVertexCount]; PApplet.arrayCopy(lineVertices, 0, temp, 0, 4 * lineVertexCount); lineVertices = temp; lineVerticesBuffer = PGL.allocateFloatBuffer(lineVertices); } void trimLineColors() { - int temp[] = new int[lineVertexCount]; + int[] temp = new int[lineVertexCount]; PApplet.arrayCopy(lineColors, 0, temp, 0, lineVertexCount); lineColors = temp; lineColorsBuffer = PGL.allocateIntBuffer(lineColors); } void trimLineDirections() { - float temp[] = new float[4 * lineVertexCount]; + float[] temp = new float[4 * lineVertexCount]; PApplet.arrayCopy(lineDirections, 0, temp, 0, 4 * lineVertexCount); lineDirections = temp; lineDirectionsBuffer = PGL.allocateFloatBuffer(lineDirections); } void trimLineIndices() { - short temp[] = new short[lineIndexCount]; + short[] temp = new short[lineIndexCount]; PApplet.arrayCopy(lineIndices, 0, temp, 0, lineIndexCount); lineIndices = temp; lineIndicesBuffer = PGL.allocateShortBuffer(lineIndices); } void trimPointVertices() { - float temp[] = new float[4 * pointVertexCount]; + float[] temp = new float[4 * pointVertexCount]; PApplet.arrayCopy(pointVertices, 0, temp, 0, 4 * pointVertexCount); pointVertices = temp; pointVerticesBuffer = PGL.allocateFloatBuffer(pointVertices); } void trimPointColors() { - int temp[] = new int[pointVertexCount]; + int[] temp = new int[pointVertexCount]; PApplet.arrayCopy(pointColors, 0, temp, 0, pointVertexCount); pointColors = temp; pointColorsBuffer = PGL.allocateIntBuffer(pointColors); } void trimPointOffsets() { - float temp[] = new float[2 * pointVertexCount]; + float[] temp = new float[2 * pointVertexCount]; PApplet.arrayCopy(pointOffsets, 0, temp, 0, 2 * pointVertexCount); pointOffsets = temp; pointOffsetsBuffer = PGL.allocateFloatBuffer(pointOffsets); } void trimPointIndices() { - short temp[] = new short[pointIndexCount]; + short[] temp = new short[pointIndexCount]; PApplet.arrayCopy(pointIndices, 0, temp, 0, pointIndexCount); pointIndices = temp; pointIndicesBuffer = PGL.allocateShortBuffer(pointIndices); @@ -12439,7 +12448,7 @@ void addDupIndex(int idx) { if (dupIndices.length == dupCount) { int n = dupCount << 1; - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(dupIndices, 0, temp, 0, dupCount); dupIndices = temp; } @@ -12486,7 +12495,7 @@ void setRawSize(int size) { } void expandRawIndices(int n) { - int temp[] = new int[n]; + int[] temp = new int[n]; PApplet.arrayCopy(rawIndices, 0, temp, 0, rawSize); rawIndices = temp; } @@ -12931,15 +12940,15 @@ void addStrokeVertex(float x, float y, float z, int c, float w) { if (pathVertexCount == pathVertices.length / 3) { int newSize = pathVertexCount << 1; - float vtemp[] = new float[3 * newSize]; + float[] vtemp = new float[3 * newSize]; PApplet.arrayCopy(pathVertices, 0, vtemp, 0, 3 * pathVertexCount); pathVertices = vtemp; - int ctemp[] = new int[newSize]; + int[] ctemp = new int[newSize]; PApplet.arrayCopy(pathColors, 0, ctemp, 0, pathVertexCount); pathColors = ctemp; - float wtemp[] = new float[newSize]; + float[] wtemp = new float[newSize]; PApplet.arrayCopy(pathWeights, 0, wtemp, 0, pathVertexCount); pathWeights = wtemp; } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 9a429f8005..9c057313a0 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -503,6 +503,7 @@ protected Object getDerivedFont(Object font, float size) { return ((Font) font).deriveFont(size); } + @Override protected int getGLSLVersion() { VersionNumber vn = context.getGLSLVersionNumber(); @@ -510,49 +511,60 @@ protected int getGLSLVersion() { } + @Override + protected String getGLSLVersionSuffix() { + VersionNumber vn = context.getGLSLVersionNumber(); + if (context.isGLESProfile() && 1 < vn.getMajor()) { + return " es"; + } else { + return ""; + } + } + + @Override protected String[] loadVertexShader(String filename) { - return loadVertexShader(filename, getGLSLVersion()); + return loadVertexShader(filename, getGLSLVersion(), getGLSLVersionSuffix()); } @Override protected String[] loadFragmentShader(String filename) { - return loadFragmentShader(filename, getGLSLVersion()); + return loadFragmentShader(filename, getGLSLVersion(), getGLSLVersionSuffix()); } @Override protected String[] loadVertexShader(URL url) { - return loadVertexShader(url, getGLSLVersion()); + return loadVertexShader(url, getGLSLVersion(), getGLSLVersionSuffix()); } @Override protected String[] loadFragmentShader(URL url) { - return loadFragmentShader(url, getGLSLVersion()); + return loadFragmentShader(url, getGLSLVersion(), getGLSLVersionSuffix()); } @Override - protected String[] loadFragmentShader(String filename, int version) { + protected String[] loadFragmentShader(String filename, int version, String versionSuffix) { String[] fragSrc0 = sketch.loadStrings(filename); - return preprocessFragmentSource(fragSrc0, version); + return preprocessFragmentSource(fragSrc0, version, versionSuffix); } @Override - protected String[] loadVertexShader(String filename, int version) { + protected String[] loadVertexShader(String filename, int version, String versionSuffix) { String[] vertSrc0 = sketch.loadStrings(filename); - return preprocessVertexSource(vertSrc0, version); + return preprocessVertexSource(vertSrc0, version, versionSuffix); } @Override - protected String[] loadFragmentShader(URL url, int version) { + protected String[] loadFragmentShader(URL url, int version, String versionSuffix) { try { String[] fragSrc0 = PApplet.loadStrings(url.openStream()); - return preprocessFragmentSource(fragSrc0, version); + return preprocessFragmentSource(fragSrc0, version, versionSuffix); } catch (IOException e) { PGraphics.showException("Cannot load fragment shader " + url.getFile()); } @@ -561,10 +573,10 @@ protected String[] loadFragmentShader(URL url, int version) { @Override - protected String[] loadVertexShader(URL url, int version) { + protected String[] loadVertexShader(URL url, int version, String versionSuffix) { try { String[] vertSrc0 = PApplet.loadStrings(url.openStream()); - return preprocessVertexSource(vertSrc0, version); + return preprocessVertexSource(vertSrc0, version, versionSuffix); } catch (IOException e) { PGraphics.showException("Cannot load vertex shader " + url.getFile()); } @@ -600,19 +612,33 @@ public Tessellator(TessellatorCallback callback) { GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); } + @Override + public void setCallback(int flag) { + GLU.gluTessCallback(tess, flag, gluCallback); + } + + @Override + public void setWindingRule(int rule) { + setProperty(GLU.GLU_TESS_WINDING_RULE, rule); + } + + public void setProperty(int property, int value) { + GLU.gluTessProperty(tess, property, value); + } + @Override public void beginPolygon() { - GLU.gluTessBeginPolygon(tess, null); + beginPolygon(null); } @Override - public void endPolygon() { - GLU.gluTessEndPolygon(tess); + public void beginPolygon(Object data) { + GLU.gluTessBeginPolygon(tess, data); } @Override - public void setWindingRule(int rule) { - GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); + public void endPolygon() { + GLU.gluTessEndPolygon(tess); } @Override @@ -627,7 +653,12 @@ public void endContour() { @Override public void addVertex(double[] v) { - GLU.gluTessVertex(tess, v, 0, v); + addVertex(v, 0, v); + } + + @Override + public void addVertex(double[] v, int n, Object data) { + GLU.gluTessVertex(tess, v, n, data); } protected class GLUCallback extends GLUtessellatorCallbackAdapter { @@ -691,7 +722,7 @@ protected class FontOutline implements PGL.FontOutline { PathIterator iter; public FontOutline(char ch, Font font) { - char textArray[] = new char[] { ch }; + char[] textArray = new char[] { ch }; FontRenderContext frc = getFontRenderContext(font); GlyphVector gv = font.createGlyphVector(frc, textArray); Shape shp = gv.getOutline(); @@ -702,7 +733,7 @@ public boolean isDone() { return iter.isDone(); } - public int currentSegment(float coords[]) { + public int currentSegment(float[] coords) { return iter.currentSegment(coords); } @@ -752,6 +783,7 @@ public void next() { TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; + TESS_EDGE_FLAG = GLU.GLU_TESS_EDGE_FLAG; GENERATE_MIPMAP_HINT = GL.GL_GENERATE_MIPMAP_HINT; FASTEST = GL.GL_FASTEST; @@ -976,6 +1008,7 @@ public void next() { DEPTH_STENCIL = GL.GL_DEPTH_STENCIL; FRAMEBUFFER_COMPLETE = GL.GL_FRAMEBUFFER_COMPLETE; + FRAMEBUFFER_UNDEFINED = GL2ES3.GL_FRAMEBUFFER_UNDEFINED; FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; @@ -983,6 +1016,8 @@ public void next() { FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; FRAMEBUFFER_UNSUPPORTED = GL.GL_FRAMEBUFFER_UNSUPPORTED; + FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = GL.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = GL3ES3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; @@ -1701,7 +1736,7 @@ public void getProgramiv(int program, int pname, IntBuffer params) { @Override public String getProgramInfoLog(int program) { int[] val = { 0 }; - gl2.glGetShaderiv(program, GL2ES2.GL_INFO_LOG_LENGTH, val, 0); + gl2.glGetProgramiv(program, GL2ES2.GL_INFO_LOG_LENGTH, val, 0); int length = val[0]; if (0 < length) { @@ -1903,6 +1938,8 @@ public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX gl2x.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else if (gl3 != null) { gl3.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } else if (gl3es3 != null) { + gl3es3.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else { throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glBlitFramebuffer()")); } @@ -1914,6 +1951,8 @@ public void renderbufferStorageMultisample(int target, int samples, int format, gl2x.glRenderbufferStorageMultisample(target, samples, format, width, height); } else if (gl3 != null) { gl3.glRenderbufferStorageMultisample(target, samples, format, width, height); + } else if (gl3es3 != null) { + gl3es3.glRenderbufferStorageMultisample(target, samples, format, width, height); } else { throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glRenderbufferStorageMultisample()")); } @@ -1925,6 +1964,8 @@ public void readBuffer(int buf) { gl2x.glReadBuffer(buf); } else if (gl3 != null) { gl3.glReadBuffer(buf); + } else if (gl3es3 != null) { + gl3es3.glReadBuffer(buf); } else { throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glReadBuffer()")); } @@ -1936,6 +1977,11 @@ public void drawBuffer(int buf) { gl2x.glDrawBuffer(buf); } else if (gl3 != null) { gl3.glDrawBuffer(buf); + } else if (gl3es3 != null) { + IntBuffer intBuffer = IntBuffer.allocate(1); + intBuffer.put(buf); + intBuffer.rewind(); + gl3es3.glDrawBuffers(1, intBuffer); } else { throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glDrawBuffer()")); } diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 61129b184b..d5f8f1d531 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -51,8 +51,12 @@ public class PShader implements PConstants { static protected String pointShaderAttrRegexp = "attribute *vec2 *offset"; + static protected String pointShaderInRegexp = + "in *vec2 *offset;"; static protected String lineShaderAttrRegexp = "attribute *vec4 *direction"; + static protected String lineShaderInRegexp = + "in *vec4 *direction"; static protected String pointShaderDefRegexp = "#define *PROCESSING_POINT_SHADER"; static protected String lineShaderDefRegexp = @@ -122,6 +126,7 @@ public class PShader implements PConstants { protected int ppixelsLoc; protected int ppixelsUnit; protected int viewportLoc; + protected int resolutionLoc; // Uniforms only for lines and points protected int perspectiveLoc; @@ -1015,15 +1020,8 @@ protected void dispose() { static protected int getShaderType(String[] source, int defaultType) { for (int i = 0; i < source.length; i++) { String line = source[i].trim(); - if (PApplet.match(line, pointShaderAttrRegexp) != null) - return PShader.POINT; - else if (PApplet.match(line, lineShaderAttrRegexp) != null) - return PShader.LINE; - else if (PApplet.match(line, pointShaderDefRegexp) != null) - return PShader.POINT; - else if (PApplet.match(line, lineShaderDefRegexp) != null) - return PShader.LINE; - else if (PApplet.match(line, colorShaderDefRegexp) != null) + + if (PApplet.match(line, colorShaderDefRegexp) != null) return PShader.COLOR; else if (PApplet.match(line, lightShaderDefRegexp) != null) return PShader.LIGHT; @@ -1037,6 +1035,18 @@ else if (PApplet.match(line, triShaderAttrRegexp) != null) return PShader.POLY; else if (PApplet.match(line, quadShaderAttrRegexp) != null) return PShader.POLY; + else if (PApplet.match(line, pointShaderDefRegexp) != null) + return PShader.POINT; + else if (PApplet.match(line, lineShaderDefRegexp) != null) + return PShader.LINE; + else if (PApplet.match(line, pointShaderAttrRegexp) != null) + return PShader.POINT; + else if (PApplet.match(line, pointShaderInRegexp) != null) + return PShader.POINT; + else if (PApplet.match(line, lineShaderAttrRegexp) != null) + return PShader.LINE; + else if (PApplet.match(line, lineShaderInRegexp) != null) + return PShader.LINE; } return defaultType; } @@ -1148,6 +1158,7 @@ protected void loadUniforms() { projectionMatLoc = getUniformLoc("projectionMatrix"); viewportLoc = getUniformLoc("viewport"); + resolutionLoc = getUniformLoc("resolution"); ppixelsLoc = getUniformLoc("ppixels"); normalMatLoc = getUniformLoc("normalMatrix"); @@ -1199,6 +1210,12 @@ protected void setCommonUniforms() { setUniformValue(viewportLoc, x, y, w, h); } + if (-1 < resolutionLoc) { + float w = currentPG.viewport.get(2); + float h = currentPG.viewport.get(3); + setUniformValue(resolutionLoc, w, h); + } + if (-1 < ppixelsLoc) { ppixelsUnit = getLastTexUnit() + 1; setUniformValue(ppixelsLoc, ppixelsUnit); diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 45811bbaff..c240847512 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -43,7 +43,6 @@ import java.nio.Buffer; import java.util.Arrays; import java.util.HashSet; -import java.util.Stack; /** * This class holds a 3D model composed of vertices, normals, colors @@ -171,7 +170,8 @@ public class PShapeOpenGL extends PShape { // Geometric transformations. protected PMatrix transform; - protected Stack transformStack; + protected PMatrix transformInv; + protected PMatrix matrixInv; // ........................................................ @@ -847,7 +847,7 @@ protected void scaleTextureUV(float uFactor, float vFactor) { protected void addTexture(PImage tex) { if (textures == null) { - textures = new HashSet(); + textures = new HashSet<>(); } textures.add(tex); if (parent != null) { @@ -1334,39 +1334,34 @@ public void applyMatrix(float n00, float n01, float n02, float n03, @Override public void resetMatrix() { - if (shapeCreated && matrix != null && transformStack != null) { + if (shapeCreated && matrix != null && matrixInv != null) { if (family == GROUP) { updateTessellation(); } if (tessellated) { - PMatrix mat = popTransform(); - while (mat != null) { - boolean res = mat.invert(); - if (res) { - applyMatrixImpl(mat); - } else { - PGraphics.showWarning("Transformation applied on the shape cannot be inverted"); - } - mat = popTransform(); - } + applyMatrixImpl(matrixInv); } matrix.reset(); - transformStack.clear(); + matrixInv.reset(); } } protected void transform(int type, float... args) { int dimensions = is3D ? 3 : 2; + boolean invertible = true; checkMatrix(dimensions); if (transform == null) { if (dimensions == 2) { transform = new PMatrix2D(); + transformInv = new PMatrix2D(); } else { transform = new PMatrix3D(); + transformInv = new PMatrix3D(); } } else { transform.reset(); + transformInv.reset(); } int ncoords = args.length; @@ -1380,22 +1375,28 @@ protected void transform(int type, float... args) { case TRANSLATE: if (ncoords == 3) { transform.translate(args[0], args[1], args[2]); + PGraphicsOpenGL.invTranslate((PMatrix3D)transformInv, args[0], args[1], args[2]); } else { transform.translate(args[0], args[1]); + PGraphicsOpenGL.invTranslate((PMatrix2D)transformInv, args[0], args[1]); } break; case ROTATE: if (ncoords == 3) { transform.rotate(args[0], args[1], args[2], args[3]); + PGraphicsOpenGL.invRotate((PMatrix3D)transformInv, args[0], args[1], args[2], args[3]); } else { transform.rotate(args[0]); + PGraphicsOpenGL.invRotate((PMatrix2D)transformInv, -args[0]); } break; case SCALE: if (ncoords == 3) { transform.scale(args[0], args[1], args[2]); + PGraphicsOpenGL.invScale((PMatrix3D)transformInv, args[0], args[1], args[2]); } else { transform.scale(args[0], args[1]); + PGraphicsOpenGL.invScale((PMatrix2D)transformInv, args[0], args[1]); } break; case MATRIX: @@ -1408,32 +1409,20 @@ protected void transform(int type, float... args) { transform.set(args[0], args[1], args[2], args[3], args[4], args[5]); } + transformInv.set(transform); + invertible = transformInv.invert(); break; } - matrix.apply(transform); - pushTransform(); - if (tessellated) applyMatrixImpl(transform); - } - - - protected void pushTransform() { - if (transformStack == null) transformStack = new Stack(); - PMatrix mat; - if (transform instanceof PMatrix2D) { - mat = new PMatrix2D(); + matrix.preApply(transform); + if (invertible) { + matrixInv.apply(transformInv); } else { - mat = new PMatrix3D(); + PGraphics.showWarning("Transformation applied on the shape cannot be inverted"); } - mat.set(transform); - transformStack.push(mat); + if (tessellated) applyMatrixImpl(transform); } - protected PMatrix popTransform() { - if (transformStack == null || transformStack.size() == 0) return null; - return transformStack.pop(); - } - protected void applyMatrixImpl(PMatrix matrix) { if (hasPolys) { tessGeo.applyMatrixOnPolyGeometry(matrix, @@ -1465,6 +1454,23 @@ protected void applyMatrixImpl(PMatrix matrix) { } + @Override + protected void checkMatrix(int dimensions) { + if (matrix == null) { + if (dimensions == 2) { + matrix = new PMatrix2D(); + matrixInv = new PMatrix2D(); + } else { + matrix = new PMatrix3D(); + matrixInv = new PMatrix3D(); + } + } else if (dimensions == 3 && (matrix instanceof PMatrix2D)) { + matrix = new PMatrix3D(matrix); + matrixInv = new PMatrix3D(matrixInv); + } + } + + /////////////////////////////////////////////////////////// // @@ -1664,7 +1670,10 @@ public void setVertex(int index, float x, float y, float z) { } vertices[index][X] = x; vertices[index][Y] = y; - if (is3D) vertices[index][Z] = z; + if (is3D && vertices[index].length > 2) { + // P3D allows to modify 2D shapes, ignoring the Z coordinate. + vertices[index][Z] = z; + } } else { inGeo.vertices[3 * index + 0] = x; inGeo.vertices[3 * index + 1] = y; @@ -1681,9 +1690,22 @@ public void setVertex(int index, PVector vec) { return; } - inGeo.vertices[3 * index + 0] = vec.x; - inGeo.vertices[3 * index + 1] = vec.y; - inGeo.vertices[3 * index + 2] = vec.z; + if (family == PATH) { + if (vertexCodes != null && vertexCodeCount > 0 && + vertexCodes[index] != VERTEX) { + PGraphics.showWarning(NOT_A_SIMPLE_VERTEX, "setVertex()"); + return; + } + vertices[index][X] = vec.x; + vertices[index][Y] = vec.y; + if (is3D && vertices[index].length > 2) { + vertices[index][Z] = vec.z; + } + } else { + inGeo.vertices[3 * index + 0] = vec.x; + inGeo.vertices[3 * index + 1] = vec.y; + inGeo.vertices[3 * index + 2] = vec.z; + } markForTessellation(); } @@ -1739,10 +1761,11 @@ public void setAttrib(String name, int index, float... values) { return; } - VertexAttribute attrib = polyAttribs.get(name); + VertexAttribute attrib = attribImpl(name, VertexAttribute.OTHER, PGL.FLOAT, + values.length); float[] array = inGeo.fattribs.get(name); for (int i = 0; i < values.length; i++) { - array[attrib.size * index + 0] = values[i]; + array[attrib.size * index + i] = values[i]; } markForTessellation(); } @@ -1755,10 +1778,11 @@ public void setAttrib(String name, int index, int... values) { return; } - VertexAttribute attrib = polyAttribs.get(name); + VertexAttribute attrib = attribImpl(name, VertexAttribute.OTHER, PGL.INT, + values.length); int[] array = inGeo.iattribs.get(name); for (int i = 0; i < values.length; i++) { - array[attrib.size * index + 0] = values[i]; + array[attrib.size * index + i] = values[i]; } markForTessellation(); } @@ -1771,10 +1795,11 @@ public void setAttrib(String name, int index, boolean... values) { return; } - VertexAttribute attrib = polyAttribs.get(name); + VertexAttribute attrib = attribImpl(name, VertexAttribute.OTHER, PGL.BOOL, + values.length); byte[] array = inGeo.battribs.get(name); for (int i = 0; i < values.length; i++) { - array[attrib.size * index + 0] = (byte)(values[i]?1:0); + array[attrib.size * index + i] = (byte)(values[i]?1:0); } markForTessellation(); } @@ -2035,8 +2060,8 @@ protected void setStrokeImpl(boolean stroke) { if (is2D() && parent != null) { ((PShapeOpenGL)parent).strokedTexture(stroke && image != null); } - - this.stroke = stroke; + + this.stroke = stroke; } } @@ -2806,15 +2831,21 @@ protected void initModified() { protected void tessellate() { if (root == this && parent == null) { // Root shape + boolean initAttr = false; if (polyAttribs == null) { polyAttribs = PGraphicsOpenGL.newAttributeMap(); - collectPolyAttribs(); + initAttr = true; } if (tessGeo == null) { tessGeo = PGraphicsOpenGL.newTessGeometry(pg, polyAttribs, PGraphicsOpenGL.RETAINED); } tessGeo.clear(); + + if (initAttr) { + collectPolyAttribs(); + } + for (int i = 0; i < polyAttribs.size(); i++) { VertexAttribute attrib = polyAttribs.get(i); tessGeo.initAttrib(attrib); @@ -2832,6 +2863,7 @@ protected void tessellate() { protected void collectPolyAttribs() { AttributeMap rootAttribs = root.polyAttribs; + tessGeo = root.tessGeo; if (family == GROUP) { for (int i = 0; i < childCount; i++) { @@ -4664,10 +4696,99 @@ public void draw(PGraphics g) { post(gl); } } else { - // The renderer is not PGraphicsOpenGL, which probably means that - // the draw() method is being called by the recorder. We just use - // the default draw implementation from the parent class. - super.draw(g); + if (family == GEOMETRY) { + inGeoToVertices(); + } + pre(g); + drawImpl(g); + post(g); + } + } + + + private void inGeoToVertices() { + vertexCount = 0; + vertexCodeCount = 0; + if (inGeo.codeCount == 0) { + for (int i = 0; i < inGeo.vertexCount; i++) { + int index = 3 * i; + float x = inGeo.vertices[index++]; + float y = inGeo.vertices[index ]; + super.vertex(x, y); + } + } else { + int v; + float x, y; + float cx, cy; + float x2, y2, x3, y3, x4, y4; + int idx = 0; + boolean insideContour = false; + + for (int j = 0; j < inGeo.codeCount; j++) { + switch (inGeo.codes[j]) { + + case VERTEX: + v = 3 * idx; + x = inGeo.vertices[v++]; + y = inGeo.vertices[v ]; + super.vertex(x, y); + + idx++; + break; + + case QUADRATIC_VERTEX: + v = 3 * idx; + cx = inGeo.vertices[v++]; + cy = inGeo.vertices[v]; + + v = 3 * (idx + 1); + x3 = inGeo.vertices[v++]; + y3 = inGeo.vertices[v]; + + super.quadraticVertex(cx, cy, x3, y3); + + idx += 2; + break; + + case BEZIER_VERTEX: + v = 3 * idx; + x2 = inGeo.vertices[v++]; + y2 = inGeo.vertices[v ]; + + v = 3 * (idx + 1); + x3 = inGeo.vertices[v++]; + y3 = inGeo.vertices[v ]; + + v = 3 * (idx + 2); + x4 = inGeo.vertices[v++]; + y4 = inGeo.vertices[v ]; + + super.bezierVertex(x2, y2, x3, y3, x4, y4); + + idx += 3; + break; + + case CURVE_VERTEX: + v = 3 * idx; + x = inGeo.vertices[v++]; + y = inGeo.vertices[v ]; + + super.curveVertex(x, y); + + idx++; + break; + + case BREAK: + if (insideContour) { + super.endContourImpl(); + } + super.beginContourImpl(); + insideContour = true; + } + } + if (insideContour) { + super.endContourImpl(); + } } } diff --git a/core/src/processing/opengl/PSurfaceJOGL.java b/core/src/processing/opengl/PSurfaceJOGL.java index 7e5e15b662..a9de3f0b82 100644 --- a/core/src/processing/opengl/PSurfaceJOGL.java +++ b/core/src/processing/opengl/PSurfaceJOGL.java @@ -36,10 +36,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.swing.ImageIcon; @@ -58,9 +55,9 @@ import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLProfile; import com.jogamp.nativewindow.MutableGraphicsConfiguration; +import com.jogamp.nativewindow.WindowClosingProtocol; import com.jogamp.newt.Display; import com.jogamp.newt.Display.PointerIcon; -import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; import com.jogamp.newt.awt.NewtCanvasAWT; @@ -68,6 +65,7 @@ import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.FPSAnimator; + import processing.core.PApplet; import processing.core.PConstants; import processing.core.PGraphics; @@ -87,11 +85,11 @@ public class PSurfaceJOGL implements PSurface { protected FPSAnimator animator; protected Rectangle screenRect; + private Thread drawExceptionHandler; + protected PApplet sketch; protected PGraphics graphics; - protected int sketchX; - protected int sketchY; protected int sketchWidth0; protected int sketchHeight0; protected int sketchWidth; @@ -99,13 +97,14 @@ public class PSurfaceJOGL implements PSurface { protected Display display; protected Screen screen; - protected List monitors; - protected MonitorDevice displayDevice; + protected Rectangle displayRect; protected Throwable drawException; - protected Object waitObject = new Object(); + private final Object drawExceptionMutex = new Object(); protected NewtCanvasAWT canvas; + protected int windowScaleFactor; + protected float[] currentPixelScale = {0, 0}; protected boolean external = false; @@ -133,16 +132,6 @@ public void initOffscreen(PApplet sketch) { public void initFrame(PApplet sketch) { this.sketch = sketch; initIcons(); - - // https://jogamp.org/bugzilla/show_bug.cgi?id=1290 - File mesaLib = new File("/usr/lib/arm-linux-gnueabihf/libGLESv2.so.2"); - if (mesaLib.exists()) { - System.out.println("\nIf you are receiving an error regarding the undefined symbol bcm_host_init, " + - "make sure you have the package libgles2-mesa deinstalled. This can be done " + - "by executing \"sudo aptitude remove libgles2-mesa\" in the terminal, and is " + - "a known issue with the Raspbian distribution.\n"); - } - initDisplay(); initGL(); initWindow(); @@ -157,103 +146,35 @@ public Object getNative() { protected void initDisplay() { - Display tmpDisplay = NewtFactory.createDisplay(null); - tmpDisplay.addReference(); - Screen tmpScreen = NewtFactory.createScreen(tmpDisplay, 0); - tmpScreen.addReference(); + display = NewtFactory.createDisplay(null); + display.addReference(); + screen = NewtFactory.createScreen(display, 0); + screen.addReference(); - monitors = new ArrayList(); GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] awtDevices = environment.getScreenDevices(); - List newtDevices = tmpScreen.getMonitorDevices(); - - // AWT and NEWT name devices in different ways, depending on the platform, - // and also appear to order them in different ways. The following code - // tries to address the differences. - if (PApplet.platform == PConstants.LINUX) { - for (GraphicsDevice device: awtDevices) { - String did = device.getIDstring(); - String[] parts = did.split("\\."); - String id1 = ""; - if (1 < parts.length) { - id1 = parts[1].trim(); - } - MonitorDevice monitor = null; - int id0 = newtDevices.size() > 0 ? newtDevices.get(0).getId() : 0; - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId() - id0); - if (id1.equals(mid)) { - monitor = mon; - break; - } - } - if (monitor != null) { - monitors.add(monitor); - } - } - } else if (PApplet.platform == PConstants.WINDOWS) { - // NEWT display id is == (adapterId << 8 | monitorId), - // should be in the same order as AWT - monitors.addAll(newtDevices); - } else { // MAC OSX and others - for (GraphicsDevice device: awtDevices) { - String did = device.getIDstring(); - String[] parts = did.split("Display"); - String id1 = ""; - if (1 < parts.length) { - id1 = parts[1].trim(); - } - MonitorDevice monitor = null; - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId()); - if (id1.equals(mid)) { - monitor = mon; - break; - } - } - if (monitor == null) { - // Didn't find a matching monitor, try using less stringent id check - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId()); - if (-1 < did.indexOf(mid)) { - monitor = mon; - break; - } - } - } - if (monitor != null) { - monitors.add(monitor); - } - } - } - displayDevice = null; + GraphicsDevice awtDisplayDevice = null; int displayNum = sketch.sketchDisplay(); if (displayNum > 0) { // if -1, use the default device - if (displayNum <= monitors.size()) { - displayDevice = monitors.get(displayNum - 1); + if (displayNum <= awtDevices.length) { + awtDisplayDevice = awtDevices[displayNum-1]; } else { System.err.format("Display %d does not exist, " + "using the default display instead.%n", displayNum); - for (int i = 0; i < monitors.size(); i++) { - System.err.format("Display %d is %s%n", i+1, monitors.get(i)); + for (int i = 0; i < awtDevices.length; i++) { + System.err.format("Display %d is %s%n", i+1, awtDevices[i]); } } - } else if (0 < monitors.size()) { - displayDevice = monitors.get(0); + } else if (0 < awtDevices.length) { + awtDisplayDevice = awtDevices[0]; } - if (displayDevice != null) { - screen = displayDevice.getScreen(); - display = screen.getDisplay(); - } else { - screen = tmpScreen; - display = tmpDisplay; - displayDevice = screen.getPrimaryMonitor(); + if (awtDisplayDevice == null) { + awtDisplayDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); } + + displayRect = awtDisplayDevice.getDefaultConfiguration().getBounds(); } @@ -269,6 +190,15 @@ protected void initGL() { } else if (PJOGL.profile == 2) { try { profile = GLProfile.getGL2ES2(); + + // workaround for https://jogamp.org/bugzilla/show_bug.cgi?id=1347 + if (!profile.isHardwareRasterizer()) { + GLProfile hardware = GLProfile.getMaxProgrammable(true); + if (hardware.isGL2ES2()) { + profile = hardware; + } + } + } catch (GLException ex) { profile = GLProfile.getMaxProgrammable(true); } @@ -314,6 +244,12 @@ protected void initGL() { protected void initWindow() { window = GLWindow.create(screen, pgl.getCaps()); + // Make sure that we pass the window close through to exit(), otherwise + // we're likely to have OpenGL try to shut down halfway through rendering + // a frame. Particularly problematic for complex/slow apps. + // https://github.com/processing/processing/issues/4690 + window.setDefaultCloseOperation(WindowClosingProtocol.WindowClosingMode.DO_NOTHING_ON_CLOSE); + // if (displayDevice == null) { // // @@ -321,13 +257,15 @@ protected void initWindow() { // window = GLWindow.create(displayDevice.getScreen(), pgl.getCaps()); // } + windowScaleFactor = PApplet.platform == PConstants.MACOSX ? + 1 : sketch.pixelDensity; boolean spanDisplays = sketch.sketchDisplay() == PConstants.SPAN; screenRect = spanDisplays ? - new Rectangle(0, 0, screen.getWidth(), screen.getHeight()) : - new Rectangle(0, 0, - displayDevice.getViewportInWindowUnits().getWidth(), - displayDevice.getViewportInWindowUnits().getHeight()); + new Rectangle(screen.getX(), screen.getY(), screen.getWidth(), screen.getHeight()) : + new Rectangle((int) displayRect.getX(), (int) displayRect.getY(), + (int) displayRect.getWidth(), + (int) displayRect.getHeight()); // Set the displayWidth/Height variables inside PApplet, so that they're // usable and can even be returned by the sketchWidth()/Height() methods. @@ -376,12 +314,14 @@ protected void initWindow() { */ if (fullScreen || spanDisplays) { - sketchWidth = screenRect.width; - sketchHeight = screenRect.height; + sketchWidth = screenRect.width / windowScaleFactor; + sketchHeight = screenRect.height / windowScaleFactor; } + sketch.setSize(sketchWidth, sketchHeight); + float[] reqSurfacePixelScale; - if (graphics.is2X()) { + if (graphics.is2X() && PApplet.platform == PConstants.MACOSX) { // Retina reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; @@ -391,19 +331,17 @@ protected void initWindow() { ScalableSurface.IDENTITY_PIXELSCALE }; } window.setSurfaceScale(reqSurfacePixelScale); - window.setSize(sketchWidth, sketchHeight); + window.setSize(sketchWidth * windowScaleFactor, sketchHeight * windowScaleFactor); window.setResizable(false); setSize(sketchWidth, sketchHeight); - sketchX = displayDevice.getViewportInWindowUnits().getX(); - sketchY = displayDevice.getViewportInWindowUnits().getY(); if (fullScreen) { PApplet.hideMenuBar(); - window.setTopLevelPosition(sketchX, sketchY); if (spanDisplays) { - window.setFullscreen(monitors); + window.setFullscreen(screen.getMonitorDevices()); } else { - List display = Collections.singletonList(displayDevice); - window.setFullscreen(display); + window.setUndecorated(true); + window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY()); + window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight()); } } } @@ -423,6 +361,20 @@ protected void initListeners() { protected void initAnimator() { + if (PApplet.platform == PConstants.WINDOWS) { + // Force Windows to keep timer resolution high by + // sleeping for time which is not a multiple of 10 ms. + // See section "Clocks and Timers on Windows": + // https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks + Thread highResTimerThread = new Thread(() -> { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException ignore) { } + }, "HighResTimerThread"); + highResTimerThread.setDaemon(true); + highResTimerThread.start(); + } + animator = new FPSAnimator(window, 60); drawException = null; animator.setUncaughtExceptionHandler(new GLAnimatorControl.UncaughtExceptionHandler() { @@ -430,40 +382,43 @@ protected void initAnimator() { public void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) { - synchronized (waitObject) { + synchronized (drawExceptionMutex) { drawException = cause; - waitObject.notify(); + drawExceptionMutex.notify(); } } }); - new Thread(new Runnable() { + drawExceptionHandler = new Thread(new Runnable() { public void run() { - synchronized (waitObject) { + synchronized (drawExceptionMutex) { try { - if (drawException == null) waitObject.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } -// System.err.println("Caught exception: " + drawException.getMessage()); - if (drawException != null) { - Throwable cause = drawException.getCause(); - if (cause instanceof ThreadDeath) { -// System.out.println("caught ThreadDeath"); -// throw (ThreadDeath)cause; - } else if (cause instanceof RuntimeException) { - throw (RuntimeException)cause; - } else if (cause instanceof UnsatisfiedLinkError) { - throw new UnsatisfiedLinkError(cause.getMessage()); - } else if (cause == null) { - throw new RuntimeException(drawException.getMessage()); - } else { - throw new RuntimeException(cause); + while (drawException == null) { + drawExceptionMutex.wait(); } + // System.err.println("Caught exception: " + drawException.getMessage()); + if (drawException != null) { + Throwable cause = drawException.getCause(); + if (cause instanceof ThreadDeath) { + // System.out.println("caught ThreadDeath"); + // throw (ThreadDeath)cause; + } else if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } else if (cause instanceof UnsatisfiedLinkError) { + throw new UnsatisfiedLinkError(cause.getMessage()); + } else if (cause == null) { + throw new RuntimeException(drawException.getMessage()); + } else { + throw new RuntimeException(cause); + } + } + } catch (InterruptedException e) { + return; } } } - }).start(); + }); + drawExceptionHandler.start(); } @@ -662,6 +617,11 @@ private String resourceFilename(String filename) { @Override public void placeWindow(int[] location, int[] editorLocation) { + + if (sketch.sketchFullScreen()) { + return; + } + int x = window.getX() - window.getInsets().getLeftWidth(); int y = window.getY() - window.getInsets().getTopHeight(); int w = window.getWidth() + window.getInsets().getTotalWidth(); @@ -702,10 +662,8 @@ public void placeWindow(int[] location, int[] editorLocation) { } else { // just center on screen // Can't use frame.setLocationRelativeTo(null) because it sends the // frame to the main display, which undermines the --display setting. - int sketchX = displayDevice.getViewportInWindowUnits().getX(); - int sketchY = displayDevice.getViewportInWindowUnits().getY(); - window.setTopLevelPosition(sketchX + screenRect.x + (screenRect.width - sketchWidth) / 2, - sketchY + screenRect.y + (screenRect.height - sketchHeight) / 2); + window.setTopLevelPosition(screenRect.x + (screenRect.width - sketchWidth) / 2, + screenRect.y + (screenRect.height - sketchHeight) / 2); } Point frameLoc = new Point(x, y); @@ -718,13 +676,14 @@ public void placeWindow(int[] location, int[] editorLocation) { public void placePresent(int stopColor) { - pgl.initPresentMode(0.5f * (screenRect.width - sketchWidth), - 0.5f * (screenRect.height - sketchHeight), stopColor); - window.setSize(screenRect.width, screenRect.height); + float scale = getPixelScale(); + pgl.initPresentMode(0.5f * (screenRect.width/scale - sketchWidth), + 0.5f * (screenRect.height/scale - sketchHeight), stopColor); PApplet.hideMenuBar(); - window.setTopLevelPosition(sketchX + screenRect.x, - sketchY + screenRect.y); - window.setFullscreen(true); + + window.setUndecorated(true); + window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY()); + window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight()); } @@ -755,6 +714,10 @@ public void resumeThread() { public boolean stopThread() { + if (drawExceptionHandler != null) { + drawExceptionHandler.interrupt(); + drawExceptionHandler = null; + } if (animator != null) { return animator.stop(); } else { @@ -782,30 +745,50 @@ public void run() { } - public void setSize(final int width, final int height) { - if (width == sketch.width && height == sketch.height) { - return; + public void setSize(int wide, int high) { + if (pgl.presentMode()) return; + + // When the surface is set to resizable via surface.setResizable(true), + // a crash may occur if the user sets the window to size zero. + // https://github.com/processing/processing/issues/5052 + if (high <= 0) { + high = 1; + } + if (wide <= 0) { + wide = 1; } - if (!pgl.presentMode()) { - sketch.setSize(width, height); - sketchWidth = width; - sketchHeight = height; - graphics.setSize(width, height); - window.setSize(width, height); + boolean changed = sketch.width != wide || sketch.height != high; + + sketchWidth = wide; + sketchHeight = high; + + sketch.setSize(wide, high); + graphics.setSize(wide, high); + + if (changed) { + window.setSize(wide * windowScaleFactor, high * windowScaleFactor); } } public float getPixelScale() { - if (graphics.is2X()) { - // Even if the graphics are retina, the user might have moved the window - // into a non-retina monitor, so we need to check - window.getCurrentSurfaceScale(currentPixelScale); - return currentPixelScale[0]; - } else { + if (graphics.pixelDensity == 1) { return 1; } + + if (PApplet.platform == PConstants.MACOSX) { + return getCurrentPixelScale(); + } + + return 2; + } + + private float getCurrentPixelScale() { + // Even if the graphics are retina, the user might have moved the window + // into a non-retina monitor, so we need to check + window.getCurrentSurfaceScale(currentPixelScale); + return currentPixelScale[0]; } @@ -831,6 +814,17 @@ public void setSmooth(int level) { public void setFrameRate(float fps) { + if (fps < 1) { + PGraphics.showWarning( + "The OpenGL renderer cannot have a frame rate lower than 1.\n" + + "Your sketch will run at 1 frame per second."); + fps = 1; + } else if (fps > 1000) { + PGraphics.showWarning( + "The OpenGL renderer cannot have a frame rate higher than 1000.\n" + + "Your sketch will run at 1000 frames per second."); + fps = 1000; + } if (animator != null) { animator.stop(); animator.setFPS((int)fps); @@ -866,18 +860,20 @@ public void display(GLAutoDrawable drawable) { requestFocus(); } - pgl.getGL(drawable); - int pframeCount = sketch.frameCount; - sketch.handleDraw(); - if (pframeCount == sketch.frameCount) { - // This hack allows the FBO layer to be swapped normally even if - // the sketch is no looping, otherwise background artifacts will occur. - pgl.beginRender(); - pgl.endRender(sketch.sketchWindowColor()); + if (!sketch.finished) { + pgl.getGL(drawable); + int pframeCount = sketch.frameCount; + sketch.handleDraw(); + if (pframeCount == sketch.frameCount || sketch.finished) { + // This hack allows the FBO layer to be swapped normally even if + // the sketch is no looping or finished because it does not call draw(), + // otherwise background artifacts may occur (depending on the hardware/drivers). + pgl.beginRender(); + pgl.endRender(sketch.sketchWindowColor()); + } + PGraphicsOpenGL.completeFinishedPixelTransfers(); } - PGraphicsOpenGL.completeFinishedPixelTransfers(); - if (sketch.exitCalled()) { PGraphicsOpenGL.completeAllPixelTransfers(); @@ -886,7 +882,7 @@ public void display(GLAutoDrawable drawable) { } } public void dispose(GLAutoDrawable drawable) { - sketch.dispose(); +// sketch.dispose(); } public void init(GLAutoDrawable drawable) { pgl.getGL(drawable); @@ -902,32 +898,11 @@ public void init(GLAutoDrawable drawable) { } public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) { -// int c = graphics.backgroundColor; -// pgl.clearColor(((c >> 16) & 0xff) / 255f, -// ((c >> 8) & 0xff) / 255f, -// ((c >> 0) & 0xff) / 255f, -// ((c >> 24) & 0xff) / 255f); -// pgl.clear(PGL.COLOR_BUFFER_BIT); pgl.resetFBOLayer(); -// final float[] valReqSurfacePixelScale = window.getRequestedSurfaceScale(new float[2]); - window.getCurrentSurfaceScale(currentPixelScale); -// final float[] nativeSurfacePixelScale = window.getMaximumSurfaceScale(new float[2]); -// System.err.println("[set PixelScale post]: "+ -// valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ -// hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+" (has), "+ -// nativeSurfacePixelScale[0]+"x"+nativeSurfacePixelScale[1]+" (native)"); - - - - -// System.out.println("reshape: " + w + ", " + h); pgl.getGL(drawable); -// if (!graphics.is2X() && 1 < hasSurfacePixelScale[0]) { -// setSize(w/2, h/2); -// } else { -// setSize(w, h); -// } - setSize((int)(w/currentPixelScale[0]), (int)(h/currentPixelScale[1])); + float scale = PApplet.platform == PConstants.MACOSX ? + getCurrentPixelScale() : getPixelScale(); + setSize((int) (w / scale), (int) (h / scale)); } } @@ -955,6 +930,7 @@ public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { @Override public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { + sketch.exit(); } @Override @@ -1045,19 +1021,16 @@ protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, InputEvent.ALT_MASK); int peButton = 0; - if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { - peButton = PConstants.LEFT; - } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - peButton = PConstants.CENTER; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - peButton = PConstants.RIGHT; - } - - if (PApplet.platform == PConstants.MACOSX) { - //if (nativeEvent.isPopupTrigger()) { - if ((modifiers & InputEvent.CTRL_MASK) != 0) { + switch (nativeEvent.getButton()) { + case com.jogamp.newt.event.MouseEvent.BUTTON1: + peButton = PConstants.LEFT; + break; + case com.jogamp.newt.event.MouseEvent.BUTTON2: + peButton = PConstants.CENTER; + break; + case com.jogamp.newt.event.MouseEvent.BUTTON3: peButton = PConstants.RIGHT; - } + break; } int peCount = 0; @@ -1070,9 +1043,14 @@ protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, peCount = nativeEvent.getClickCount(); } - window.getCurrentSurfaceScale(currentPixelScale); - int sx = (int)(nativeEvent.getX()/currentPixelScale[0]); - int sy = (int)(nativeEvent.getY()/currentPixelScale[1]); + int scale; + if (PApplet.platform == PConstants.MACOSX) { + scale = (int) getCurrentPixelScale(); + } else { + scale = (int) getPixelScale(); + } + int sx = nativeEvent.getX() / scale; + int sy = nativeEvent.getY() / scale; int mx = sx; int my = sy; @@ -1080,7 +1058,7 @@ protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, mx -= (int)pgl.presentX; my -= (int)pgl.presentY; if (peAction == KeyEvent.RELEASE && - pgl.insideStopButton(sx, sy - screenRect.height)) { + pgl.insideStopButton(sx, sy - screenRect.height / windowScaleFactor)) { sketch.exit(); } if (mx < 0 || sketchWidth < mx || my < 0 || sketchHeight < my) { @@ -1242,7 +1220,7 @@ void set() { } static Map cursors = new HashMap<>(); - static Map cursorNames = new HashMap(); + static Map cursorNames = new HashMap<>(); static { cursorNames.put(PConstants.ARROW, "arrow"); cursorNames.put(PConstants.CROSS, "cross"); @@ -1302,6 +1280,7 @@ public void setCursor(PImage image, int hotspotX, int hotspotY) { display.getEDTUtil().invoke(false, new Runnable() { @Override public void run() { + window.setPointerVisible(true); window.setPointerIcon(pi); } }); diff --git a/core/src/processing/opengl/Texture.java b/core/src/processing/opengl/Texture.java index c2f75f3f28..4cc51ba645 100644 --- a/core/src/processing/opengl/Texture.java +++ b/core/src/processing/opengl/Texture.java @@ -340,6 +340,8 @@ public void set(int[] pixels, int x, int y, int w, int h, int format) { loadPixels(w * h); convertToRGBA(pixels, format, w, h); + if (invertedX) flipArrayOnX(rgbaPixels, 1); + if (invertedY) flipArrayOnY(rgbaPixels, 1); updatePixelBuffer(rgbaPixels); pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); diff --git a/core/src/processing/opengl/shaders/LightVert-brcm.glsl b/core/src/processing/opengl/shaders/LightVert-brcm.glsl new file mode 100644 index 0000000000..b96caa4b3b --- /dev/null +++ b/core/src/processing/opengl/shaders/LightVert-brcm.glsl @@ -0,0 +1,154 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; +uniform mat3 normalMatrix; + +uniform int lightCount; +uniform vec4 lightPosition[8]; +uniform vec3 lightNormal[8]; +uniform vec3 lightAmbient[8]; +uniform vec3 lightDiffuse[8]; +uniform vec3 lightSpecular[8]; +uniform vec3 lightFalloff[8]; +uniform vec2 lightSpot[8]; + +attribute vec4 position; +attribute vec4 color; +attribute vec3 normal; + +attribute vec4 ambient; +attribute vec4 specular; +attribute vec4 emissive; +attribute float shininess; + +varying vec4 vertColor; +varying vec4 backVertColor; + +const float zero_float = 0.0; +const float one_float = 1.0; +const vec3 zero_vec3 = vec3(0.0); +const vec3 minus_one_vec3 = vec3(0.0-1.0); + +float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) { + vec3 lpv = lightPos - vertPos; + vec3 dist = vec3(one_float); + dist.z = dot(lpv, lpv); + dist.y = sqrt(dist.z); + return one_float / dot(dist, coeff); +} + +float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) { + vec3 lpv = normalize(lightPos - vertPos); + vec3 nln = minus_one_vec3 * lightNorm; + float spotCos = dot(nln, lpv); + return spotCos <= minCos ? zero_float : pow(spotCos, spotExp); +} + +float lambertFactor(vec3 lightDir, vec3 vecNormal) { + return max(zero_float, dot(lightDir, vecNormal)); +} + +float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) { + vec3 np = normalize(vertPos); + vec3 ldp = normalize(lightDir - np); + return pow(max(zero_float, dot(ldp, vecNormal)), shine); +} + +void main() { + // Vertex in clip coordinates + gl_Position = transformMatrix * position; + + // Vertex in eye coordinates + vec3 ecVertex = vec3(modelviewMatrix * position); + + // Normal vector in eye coordinates + vec3 ecNormal = normalize(normalMatrix * normal); + vec3 ecNormalInv = ecNormal * minus_one_vec3; + + // Light calculations + vec3 totalAmbient = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + + // prevent register allocation failure by limiting ourselves to + // two lights for now + for (int i = 0; i < 2; i++) { + if (lightCount == i) break; + + vec3 lightPos = lightPosition[i].xyz; + bool isDir = lightPosition[i].w < one_float; + float spotCos = lightSpot[i].x; + float spotExp = lightSpot[i].y; + + vec3 lightDir; + float falloff; + float spotf; + + if (isDir) { + falloff = one_float; + lightDir = minus_one_vec3 * lightNormal[i]; + } else { + falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]); + lightDir = normalize(lightPos - ecVertex); + } + + spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i], + spotCos, spotExp) + : one_float; + + if (any(greaterThan(lightAmbient[i], zero_vec3))) { + totalAmbient += lightAmbient[i] * falloff; + } + + if (any(greaterThan(lightDiffuse[i], zero_vec3))) { + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); + } + + if (any(greaterThan(lightSpecular[i], zero_vec3))) { + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); + } + } + + // Calculating final color as result of all lights (plus emissive term). + // Transparency is determined exclusively by the diffuse component. + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); +} \ No newline at end of file diff --git a/core/src/processing/opengl/shaders/LightVert-vc4.glsl b/core/src/processing/opengl/shaders/LightVert-vc4.glsl index b96caa4b3b..ba79726767 100644 --- a/core/src/processing/opengl/shaders/LightVert-vc4.glsl +++ b/core/src/processing/opengl/shaders/LightVert-vc4.glsl @@ -96,8 +96,8 @@ void main() { vec3 totalBackSpecular = vec3(0, 0, 0); // prevent register allocation failure by limiting ourselves to - // two lights for now - for (int i = 0; i < 2; i++) { + // four lights for now + for (int i = 0; i < 4; i++) { if (lightCount == i) break; vec3 lightPos = lightPosition[i].xyz; diff --git a/core/src/processing/opengl/shaders/LineVert.glsl b/core/src/processing/opengl/shaders/LineVert.glsl index b9237451d1..50946ba5ae 100644 --- a/core/src/processing/opengl/shaders/LineVert.glsl +++ b/core/src/processing/opengl/shaders/LineVert.glsl @@ -34,54 +34,67 @@ attribute vec4 color; attribute vec4 direction; varying vec4 vertColor; - -vec3 clipToWindow(vec4 clip, vec4 viewport) { - vec3 post_div = clip.xyz / clip.w; - vec2 xypos = (post_div.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw; - return vec3(xypos, post_div.z * 0.5 + 0.5); -} - -vec4 windowToClipVector(vec2 window, vec4 viewport, float clip_w) { - vec2 xypos = (window / viewport.zw) * 2.0; - return vec4(xypos, 0.0, 0.0) * clip_w; -} void main() { vec4 posp = modelviewMatrix * position; - + vec4 posq = modelviewMatrix * (position + vec4(direction.xyz, 0)); + // Moving vertices slightly toward the camera // to avoid depth-fighting with the fill triangles. // Discussed here: // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848 posp.xyz = posp.xyz * scale; - vec4 clipp = projectionMatrix * posp; + posq.xyz = posq.xyz * scale; + + vec4 p = projectionMatrix * posp; + vec4 q = projectionMatrix * posq; + + // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height]) + // screen_p = (p.xy/p.w + <1,1>) * 0.5 * viewport.zw + + // prevent division by W by transforming the tangent formula (div by 0 causes + // the line to disappear, see https://github.com/processing/processing/issues/5183) + // t = screen_q - screen_p + // + // tangent is normalized and we don't care which direction it points to (+-) + // t = +- normalize( screen_q - screen_p ) + // t = +- normalize( (q.xy/q.w+<1,1>)*0.5*viewport.zw - (p.xy/p.w+<1,1>)*0.5*viewport.zw ) + // + // extract common factor, <1,1> - <1,1> cancels out + // t = +- normalize( (q.xy/q.w - p.xy/p.w) * 0.5 * viewport.zw ) + // + // convert to common divisor + // t = +- normalize( ((q.xy*p.w - p.xy*q.w) / (p.w*q.w)) * 0.5 * viewport.zw ) + // + // remove the common scalar divisor/factor, not needed due to normalize and +- + // (keep viewport - can't remove because it has different components for x and y + // and corrects for aspect ratio, see https://github.com/processing/processing/issues/5181) + // t = +- normalize( (q.xy*p.w - p.xy*q.w) * viewport.zw ) + + vec2 tangent = (q.xy*p.w - p.xy*q.w) * viewport.zw; + + // don't normalize zero vector (line join triangles and lines perpendicular to the eye plane) + tangent = length(tangent) == 0.0 ? vec2(0.0, 0.0) : normalize(tangent); + + // flip tangent to normal (it's already normalized) + vec2 normal = vec2(-tangent.y, tangent.x); + float thickness = direction.w; - - if (thickness != 0.0) { - vec4 posq = posp + modelviewMatrix * vec4(direction.xyz, 0); - posq.xyz = posq.xyz * scale; - vec4 clipq = projectionMatrix * posq; - - vec3 window_p = clipToWindow(clipp, viewport); - vec3 window_q = clipToWindow(clipq, viewport); - vec3 tangent = window_q - window_p; - - vec2 perp = normalize(vec2(-tangent.y, tangent.x)); - vec2 offset = perp * thickness; - - if (0 < perspective) { - // Perspective correction (lines will look thiner as they move away - // from the view position). - gl_Position.xy = clipp.xy + offset.xy; - gl_Position.zw = clipp.zw; - } else { - // No perspective correction. - vec4 offsetp = windowToClipVector(offset, viewport, clipp.w); - gl_Position = clipp + offsetp; - } - } else { - gl_Position = clipp; - } - + vec2 offset = normal * thickness; + + // Perspective --- + // convert from world to clip by multiplying with projection scaling factor + // to get the right thickness (see https://github.com/processing/processing/issues/5182) + // invert Y, projections in Processing invert Y + vec2 perspScale = (projectionMatrix * vec4(1, -1, 0, 0)).xy; + + // No Perspective --- + // multiply by W (to cancel out division by W later in the pipeline) and + // convert from screen to clip (derived from clip to screen above) + vec2 noPerspScale = p.w / (0.5 * viewport.zw); + + gl_Position.xy = p.xy + offset.xy * mix(noPerspScale, perspScale, float(perspective > 0)); + gl_Position.zw = p.zw; + vertColor = color; } diff --git a/core/src/processing/opengl/shaders/PointVert.glsl b/core/src/processing/opengl/shaders/PointVert.glsl index 481fd1da76..8249e9076f 100644 --- a/core/src/processing/opengl/shaders/PointVert.glsl +++ b/core/src/processing/opengl/shaders/PointVert.glsl @@ -32,24 +32,25 @@ attribute vec2 offset; varying vec4 vertColor; -vec4 windowToClipVector(vec2 window, vec4 viewport, float clipw) { - vec2 xypos = (window / viewport.zw) * 2.0; - return vec4(xypos, 0.0, 0.0) * clipw; -} - void main() { vec4 pos = modelviewMatrix * position; vec4 clip = projectionMatrix * pos; - - if (0 < perspective) { - // Perspective correction (points will look thiner as they move away - // from the view position). - gl_Position = clip + projectionMatrix * vec4(offset.xy, 0, 0); - } else { - // No perspective correction. - vec4 cloff = windowToClipVector(offset.xy, viewport, clip.w); - gl_Position = clip + cloff; - } + + // Perspective --- + // convert from world to clip by multiplying with projection scaling factor + // invert Y, projections in Processing invert Y + vec2 perspScale = (projectionMatrix * vec4(1, -1, 0, 0)).xy; + + // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height]) + // screen_p = (p.xy/p.w + <1,1>) * 0.5 * viewport.zw + + // No Perspective --- + // multiply by W (to cancel out division by W later in the pipeline) and + // convert from screen to clip (derived from clip to screen above) + vec2 noPerspScale = clip.w / (0.5 * viewport.zw); + + gl_Position.xy = clip.xy + offset.xy * mix(noPerspScale, perspScale, float(perspective > 0)); + gl_Position.zw = clip.zw; vertColor = color; -} \ No newline at end of file +} diff --git a/core/src/processing/opengl/shaders/TexLightVert-brcm.glsl b/core/src/processing/opengl/shaders/TexLightVert-brcm.glsl new file mode 100644 index 0000000000..51e88ab056 --- /dev/null +++ b/core/src/processing/opengl/shaders/TexLightVert-brcm.glsl @@ -0,0 +1,160 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012-15 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; +uniform mat3 normalMatrix; +uniform mat4 texMatrix; + +uniform int lightCount; +uniform vec4 lightPosition[8]; +uniform vec3 lightNormal[8]; +uniform vec3 lightAmbient[8]; +uniform vec3 lightDiffuse[8]; +uniform vec3 lightSpecular[8]; +uniform vec3 lightFalloff[8]; +uniform vec2 lightSpot[8]; + +attribute vec4 position; +attribute vec4 color; +attribute vec3 normal; +attribute vec2 texCoord; + +attribute vec4 ambient; +attribute vec4 specular; +attribute vec4 emissive; +attribute float shininess; + +varying vec4 vertColor; +varying vec4 backVertColor; +varying vec4 vertTexCoord; + +const float zero_float = 0.0; +const float one_float = 1.0; +const vec3 zero_vec3 = vec3(0.0); +const vec3 minus_one_vec3 = vec3(0.0-1.0); + +float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) { + vec3 lpv = lightPos - vertPos; + vec3 dist = vec3(one_float); + dist.z = dot(lpv, lpv); + dist.y = sqrt(dist.z); + return one_float / dot(dist, coeff); +} + +float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) { + vec3 lpv = normalize(lightPos - vertPos); + vec3 nln = minus_one_vec3 * lightNorm; + float spotCos = dot(nln, lpv); + return spotCos <= minCos ? zero_float : pow(spotCos, spotExp); +} + +float lambertFactor(vec3 lightDir, vec3 vecNormal) { + return max(zero_float, dot(lightDir, vecNormal)); +} + +float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) { + vec3 np = normalize(vertPos); + vec3 ldp = normalize(lightDir - np); + return pow(max(zero_float, dot(ldp, vecNormal)), shine); +} + +void main() { + // Vertex in clip coordinates + gl_Position = transformMatrix * position; + + // Vertex in eye coordinates + vec3 ecVertex = vec3(modelviewMatrix * position); + + // Normal vector in eye coordinates + vec3 ecNormal = normalize(normalMatrix * normal); + vec3 ecNormalInv = ecNormal * minus_one_vec3; + + // Light calculations + vec3 totalAmbient = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + + // prevent register allocation failure by limiting ourselves to + // two lights for now + for (int i = 0; i < 2; i++) { + if (lightCount == i) break; + + vec3 lightPos = lightPosition[i].xyz; + bool isDir = lightPosition[i].w < one_float; + float spotCos = lightSpot[i].x; + float spotExp = lightSpot[i].y; + + vec3 lightDir; + float falloff; + float spotf; + + if (isDir) { + falloff = one_float; + lightDir = minus_one_vec3 * lightNormal[i]; + } else { + falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]); + lightDir = normalize(lightPos - ecVertex); + } + + spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i], + spotCos, spotExp) + : one_float; + + if (any(greaterThan(lightAmbient[i], zero_vec3))) { + totalAmbient += lightAmbient[i] * falloff; + } + + if (any(greaterThan(lightDiffuse[i], zero_vec3))) { + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); + } + + if (any(greaterThan(lightSpecular[i], zero_vec3))) { + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); + } + } + + // Calculating final color as result of all lights (plus emissive term). + // Transparency is determined exclusively by the diffuse component. + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + // Calculating texture coordinates, with r and q set both to one + vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); +} diff --git a/core/src/processing/opengl/shaders/TexLightVert-vc4.glsl b/core/src/processing/opengl/shaders/TexLightVert-vc4.glsl index 51e88ab056..f54277e812 100644 --- a/core/src/processing/opengl/shaders/TexLightVert-vc4.glsl +++ b/core/src/processing/opengl/shaders/TexLightVert-vc4.glsl @@ -99,8 +99,8 @@ void main() { vec3 totalBackSpecular = vec3(0, 0, 0); // prevent register allocation failure by limiting ourselves to - // two lights for now - for (int i = 0; i < 2; i++) { + // four lights for now + for (int i = 0; i < 4; i++) { if (lightCount == i) break; vec3 lightPos = lightPosition[i].xyz; diff --git a/core/todo.txt b/core/todo.txt index 6c82a318eb..8055db170c 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,56 +1,64 @@ -0253 (3.2.1) -X implement defaultUncaughtExceptionHandler -X helps avoid needing to double-quit OS X applications - - -started -X add toJSON() method to IntDict -X had to use JSONObject.quote() to wrap the text -_ do the same for the other data classes -_ note the difference between this and toJSONObject() or toJSONArray() -_ or is that the better way to handle it? hm - -_ should we drop the 'default' prefix from the ex handler so it's not static? -_ http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html -_ listPaths(), listFiles()? -_ https://github.com/processing/processing/issues/4622 - -_ option to disable OpenGL ES on Linux? -_ https://github.com/processing/processing/issues/4584 - -_ JSONObject get() method is private -_ https://github.com/processing/processing/issues/4334 -_ https://github.com/processing/processing/pull/4336 - +0271 (3.5.5 unlikely) + +contribs +X getShape() - Type of vertex was wrong for Cubic +X https://github.com/processing/processing/pull/6092 + + +_ size() issues on Mojave? +_ https://github.com/processing/processing/issues/5791 +_ use exit event to set mouseY to 0 on macOS +_ https://github.com/processing/processing/pull/5796/files +_ possible fix for precision issues with PDF +_ https://github.com/processing/processing/issues/5801#issuecomment-466632459 + + +high-ish +_ add separator option to loadTable() +_ https://github.com/processing/processing/issues/5068 +_ make setting the window icon automatic, based on files in local dirs +X https://github.com/processing/processing/issues/5123 +X https://github.com/processing/processing/pull/5202 +_ need to make this work behind the scenes instead +_ create icon.png or have an 'icons' folder with multiple sizes +_ don't override the window icon w/ p5 logo if already set +_ NullPointerException at java.awt.Window.init(Window.java:497) when using Airplay +_ https://github.com/processing/processing/issues/5620 +_ try to catch the NPE and warn the user about what's happening +_ requestSize() and xxxxTitle() (to diminish use of 'surface') +_ mostly held up by cross-renderer inconsistency with these _ textAlign(CENTER) and pixelDensity(2) aligning incorrectly with Java2D _ https://github.com/processing/processing/issues/4020 -_ add increment() that takes IntDict to merge things - +_ calling textSize() fixes it, only hpapens with the default font +_ incorrect textWidth() with pixelDensity(2) when textFont() not used +_ https://github.com/processing/processing/issues/5768 + + +retina/hi-dpi/sizing +_ implement sketch scaling into PApplet +_ https://github.com/processing/processing/issues/4897 +_ Sketches on Windows don't take UI sizing into account +_ https://github.com/processing/processing/issues/4894 +_ Sketches on Linux don't take UI scaling into account +_ https://github.com/processing/processing/issues/4895 +_ gohai says "xrdb -query" or "xdpyinfo" might work _ should fullScreen() set width and height to displayWidth/Height _ or is that being set/unset used for any state info? -_ when calling exit(), if sketch has halted w/ exception, force the quit -_ otherwise have to double-quit with cmd-q on OS X -_ simple test case: using size() inside setup() from Eclipse - - -discussion -_ how to handle the touch api -_ figure our size(img.width, img.height) situation -X just make loadImage() work in settings -_ update the wiki and reference - - -known -_ window must close when using file dialogs with OpenGL on Windows -_ https://github.com/processing/processing/issues/3831 -_ window loses focus after maximizing -_ https://github.com/processing/processing/issues/3339 +_ present window draws in stages (OS X) +_ crash on startup when "Mirror Displays" selected (cantfix?) +_ suspect that this is a specific chipset since Oracle didn't reproduce +_ AMD Radeon HD 6770M was in the Oracle bug report +_ https://github.com/processing/processing/issues/2186 +_ https://bugs.openjdk.java.net/browse/JDK-8027391 +_ test with JG's 13" retina laptop misc -_ move blending calculations from PImage into PGraphics -_ tricky because that means moving blend_resize() as well -_ and should that live in PGraphics or be its own class or ?? +_ should we drop the 'default' prefix from the ex handler so it's not static? +_ http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html +_ Switch to getModifiersEx() and fix the AWT modifiers used in PSurfaceAWT +_ this is an easy fix, but need to check impact elsewhere +_ does anything else rely on these modifiers? _ try using Frame instead of JFrame _ default sketch location using insets incorrectly _ use the BufferStrategy directly from the Frame object? @@ -59,88 +67,12 @@ _ sketch placement (window insets) not properly set on Linux _ https://github.com/processing/processing/issues/2063 _ note in docs that full screen and present are now different _ on Export to Application, this has an impact -_ update wiki/docs to say "don't override sketchXxxx() methods" _ SVG only exports last frame _ possibly because Java2D is disposing the Graphics2D in between? _ https://github.com/processing/processing/issues/3753 - - -javafx -_ menu bar not hiding properly in exported applications with FX2D -_ hideMenuBar() called from setup() works fine -_ just call it around setup time? -_ the --hide-stop option not working (FX only? traces?) -_ make wiki about quirks -_ starving the thread makes things really slow down -_ keyPressed() is always uppercase, keyTyped() will be correct -_ do we really need setTextFont/Size when we already have Impl? -_ need keyPressed() to do lower and upper case -_ static mode sketches (draw once and halt w/o closing window) -_ fix display handling, line up the device order with AWT -_ https://docs.oracle.com/javafx/2/api/javafx/stage/Screen.html -_ noLoop() -_ present mode not working at all -_ stage in the center, clear the rest of the screen -_ createGraphics() should probably create PGraphicsJava2D -_ or is Canvas specific to the PGraphics, and we get another Context2D? -_ http://docs.oracle.com/javafx/2/api/javafx/scene/canvas/Canvas.html -_ loadPixels() (also 2x) -_ text and fonts? -_ maybe helpful: https://wiki.openjdk.java.net/display/OpenJFX/Font+Setup -_ updatePixels() -_ save() and saveFrame() -_ get() and set() -_ clip/noClip -_ https://github.com/processing/processing/issues/3274 -_ getNative() in PImage problematic because it gives back a BufferedImage -_ move loadImage() into PGraphics, with AWT version the default -_ or pass createImage() through to renderer? -_ implement external messages (moving the window) -_ implement PSurfaceFX.setIcon() -_ javafx not supported with ARM (so we're screwed on raspberry pi) -_ https://www.linkedin.com/pulse/oracle-just-removed-javafx-support-arm-jan-snelders - - -opengl questions -_ hard crash at 1920x1080, mirrored, Casey's GT 650M 1GB -_ exitCalled() and exitActual made public by Andres, breaks Python -_ also not API we want to expose, so sort this out -_ or maybe we're fine b/c now FX2D needs it as well -_ when did setPath() sneak into PShape? API is nothing like anything else -_ probably from the material stuff, but we need to fix that -_ why is createShape() implemented 4x (for P2D, P3D, and 2x versions)? -_ shouldn't be static, run it from the renderer, that's point of createXxx() -_ public createShape() method that takes another shape as param? -_ should just be the constructor doing this, or copy() - - -full screen -_ present window draws in stages (OS X) -_ crash on startup when "Mirror Displays" selected (cantfix?) -_ suspect that this is a specific chipset since Oracle didn't reproduce -_ AMD Radeon HD 6770M was in the Oracle bug report -_ https://github.com/processing/processing/issues/2186 -_ https://bugs.openjdk.java.net/browse/JDK-8027391 -_ test with JG's 13" retina laptop - - -graphics -_ need to be able to call pixelDensity(2) before beginDraw() -_ add pixelDensity() method to PImage/PGraphics -_ pixelDensity(2) does: pixelWidth = width; width /= 2; pixelDensity = 2; -_ this works for both PGraphics and images (though they're a little backwards) -_ for PGraphics it comes early enough -_ should the re-alloc of the drawing surface happen in beginDraw() -_ that way it won't blit to the screen until we have a fresh redraw? -_ otherwise it'll also be resizing on another thread.. badness -_ how to allocation image object w/ createGraphics() (since no surface) -_ createGraphics() currently broken in Java2D -_ size() command not working to do a resize -_ need a programmatic way to set size -_ deal with applySettings() change (maybe not a problem?) -_ check on performance of the new EDT setup -_ present mode is 30-40% slower than windowed -_ w/ this example: https://github.com/processing/processing/issues/2423 +_ when calling exit(), if sketch has halted w/ exception, force the quit +_ otherwise have to double-quit with cmd-q on OS X +_ simple test case: using size() inside setup() from Eclipse data @@ -160,37 +92,20 @@ _ row count and array size are combined.. need to break apart _ match and iterators _ add match version that returns table that's only a pointer to original _ save the constructor for the version that actually copies data -_ the table pointer version will be speedy and allow chaining +_ the table pointer version will be speedy and allow chaining -high -_ point() rendering differently in 2.0.3 and 2.1 -_ https://github.com/processing/processing/issues/2278 -_ internally, we probably have to call set() if it's a 1 pixel point -_ but that's going to be a mess.. need to first check the CTM -_ tint() not working in PDF (regression between 2.0.3 and 2.1) -_ https://github.com/processing/processing/issues/2428 -_ finish PFont.getShape() implementation -_ needs to have a way to set width/height properly -_ draw(s) doesn't work on the returned PShape -_ y-location of frame might be negative, but that might be ok -_ right now, on Windows it moves it on-screen (b/c of previous bug reports) -_ may be cause of some of the display placement issues w/ multiple displays -_ seem to recall one of the bugs mentioning stacked displays -_ need to change to iterate through display rectangles -_ may be related to full-screen bug filed recently -_ closing a sketch window manually (not hitting Stop) not killing sketch -_ at least with the Java2D renderer -_ don't override the window icon w/ p5 logo if already set - - -retina/hidpi -_ no high-dpi support for core on Windows -_ https://github.com/processing/processing/issues/2411 - - -decisions/misc -_ Separately, if we wanted, we could add a method that can safely do drawing calls, but that won't be any faster or make use of more processors the way that `thread()` does. +discussion/decisions +_ how to handle the touch api +_ can't do MouseEvent et al with Android +_ http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html +_ http://www.html5rocks.com/en/mobile/touch.html +_ decision: go with what looks like javascript/ios +_ touchEvent(), gestureEvent()? +_ size() function that scales to screen, keeps aspect, re-scales mouse coords +_ add screen(PVector), model(PVector) and world(PVector)? +_ maybe screenVec()? or screenXYZ()? +_ Separately, if we wanted, we could add a method that can safely do drawing calls, but that won't be any faster or make use of more processors the way that `thread()` does. _ need reference update for createShape() _ though we need to verify the behavior here _ createShape(RECT) uses x/y/w/h, and optionally adds a mode param @@ -213,12 +128,9 @@ _ fix the registered methods doc, stop/dispose working _ Casey needs to nudge people about libraries, so we need to fix this _ pause(), resume(), start(), stop() clarifications _ dispose/stop not great w/ libraries yet -_ PShape complete refactoring _ proper touch events _ touch event doesn't make sense for mouseMove on desktop, hover on Android _ probably go with pointer: more universal for touch/mouse -_ high-level touch events (swipe, et al) -_ if Andres is done, they go in, if not then 3.0 _ move away from loadPixels _ add options for image.save() (or saveImage?) _ add quality=[0,1] for jpeg images @@ -231,16 +143,16 @@ _ public float textWidth(char[] chars, int start, int length) _ add version of math functions that use doubles? _ what other methods should work with doubles? all math functions? _ seems like internal (mostly static) things, but not graphics api -_ new PGraphics(... OutputStream) +_ new PGraphics(... OutputStream) _ https://github.com/processing/processing/issues/285 _ already added for PDF, just need to work out the API _ if save() returns boolean, does saveFrame()? _ also need to copy this over to android _ "translate, or this variation of it" when using text(s, x, y, z) accidentally _ change to be the text command -_ size() and resize() and whatever? +_ size() and resize() and whatever? _ should be setSize(), but that's odd for image files -_ -> resize() is fine with PImage and PGraphics... +_ -> resize() is fine with PImage and PGraphics... _ we may be inheriting the resize() from Java -> make it final? _ add resize().. make it call setSize(). _ also needs to do a redraw if noLoop() has been called @@ -274,7 +186,7 @@ _ have to pass PApplet just to make the rendering work to both renderers _ should instead be a renderer that splits things out _ wrap exceptions with die() and warn() methods _ this way, people can make use of exceptions if they would rather -_ or shut them off if they don't want to +_ or shut them off if they don't want to _ also need to explain exception handling in general _ https://github.com/processing/processing/issues/222 _ bring PConstants back in line w/ previous 1.5 (can't renumber) @@ -287,21 +199,20 @@ _ add reference/docs for urlEncode() and urlDecode() _ add explanation to the reference about using beginRecord() with fonts _ pdf.textMode(SHAPE) _ also set the font *after* the record has started -_ maybe should instead make textMode(SHAPE) the norm? +_ maybe should instead make textMode(SHAPE) the norm? _ and people can change it to textMode(MODEL) if they want? _ http://dev.processing.org/bugs/show_bug.cgi?id=1535 (no gcode) _ explain the new PGL interface _ decide how disconnectEvent should actually be handled (and name?) -_ was disconnect always there? +_ was disconnect always there? _ will need documentation _ negative indices so that we can work relative to the end in data classes? -_ add Double and Long versions of the data classes? _ add requestFocus() method to PApplet (or surface?) -o destroy() removed, but bring back? is that better than dispose()? -_ destroy() only called dispose(), so no difference -_ Python Mode has a hook for when it's called -_ probably should also check to make sure PApplet running JVM 8 -_ or compile against 1.8 and force it? +_ point() rendering differently in 2.0.3 and 2.1 +_ https://github.com/processing/processing/issues/2278 +_ internally, we probably have to call set() if it's a 1 pixel point +_ but that's going to be a mess.. need to first check the CTM +_ discussion from Jakub in the report @@ -321,7 +232,7 @@ _ http://www.javalobby.org/forums/thread.jspa?threadID=16867&tstart=0 _ http://www.gamedev.net/page/resources/_/technical/general-programming/java-games-active-rendering-r2418 -CORE / stop() +CORE / stop() _ in PApplet.main(), windowClosing() should probably be calling 'exit()' _ or rather, we should never call System.exit(0), ja? @@ -351,7 +262,7 @@ _ if not looping, need to do it immediately _ does stop() unwind the thread, or does the thread unwind call stop? _ browser will call start() and stop() methods _ need to figure out start/stop signals coming from the browser -_ is it dispose/destroy? +_ is it dispose/destroy? _ when closing a sketch via the close box, make sure stop() getting called _ test to see if it's working _ what's up with stop() vs exit()? @@ -365,21 +276,33 @@ _ noloop ref even says that redraw will be called on resize, make sure it is _ focus not coming through, ESC no longer working(?) _ hitting cmd-q when an applet is running quits p5 (on macosx) _ but cmd-q when running externally is ok because it just quits -_ is there a way to catch cmd-q when running a sketch? +_ is there a way to catch cmd-q when running a sketch? _ so that it could avoid quitting if the sketch hasn't been stopped _ or if the sketch window is foremost -_ maybe a hack where a new menubar is added? +_ maybe a hack where a new menubar is added? +o destroy() removed, but bring back? is that better than dispose()? +_ destroy() only called dispose(), so no difference +_ Python Mode has a hook for when it's called CORE / PFont and text() +_ finish PFont.getShape() implementation +_ needs to have a way to set width/height properly +_ draw(s) doesn't work on the returned PShape +_ y-location of frame might be negative, but that might be ok +_ right now, on Windows it moves it on-screen (b/c of previous bug reports) +_ may be cause of some of the display placement issues w/ multiple displays +_ seem to recall one of the bugs mentioning stacked displays +_ need to change to iterate through display rectangles +_ may be related to full-screen bug filed recently +_ when doing createFont, can we add it to the os fonts available? _ font rotation (native font problem?) with natives? _ https://github.com/processing/processing/issues/731 _ Text rotation, placement and font metrics incorrect when scaled _ https://github.com/processing/processing/issues/2167 - _ remove subsetting stuff from PFont? -_ or use hint(ENABLE_FONT_SUBSETTING)? +_ or use hint(ENABLE_FONT_SUBSETTING)? _ what's the difference with ascent on loadFont vs. createFont? _ svg fonts _ would be nifty if we could convert on the fly to ttf for speed... @@ -393,7 +316,7 @@ _ book example 25-03 _ accessors inside PFont need a lot of work _ improve font metrics _ http://java.sun.com/products/java-media/2D/reference/faqs/index.html#Q_How_do_I_obtain_font_metrics -_ font encoding issues +_ font encoding issues _ java seems to force straight windows encoding.. (problem for pi fonts) _ opentype/cff fonts don't work with live loading from the app _ many (all?) opentype fonts won't show up or aren't supported @@ -406,11 +329,11 @@ _ make screen space fonts use get/set as well? _ too much to debug on their own _ unfortunately tint not set with setImpl, but... _ not having kerning really blows -_ could this be pulled from the OpenType font stuff? +_ could this be pulled from the OpenType font stuff? _ it could be placed at the end of the file _ not having fractional widths on small fonts really blows _ screen space text looks crappy -_ working with vector fonts? +_ working with vector fonts? _ need to be able to handle shapes within shapes (reverse winding) _ ftgl: main code is in FTVectoriser _ uses gluTessBeginContour and gluTessEndContour @@ -425,25 +348,39 @@ CORE / PImage _ TGA files writing strangely _ https://github.com/processing/processing/issues/2096 - _ loadPixels() implementation needs to be in PApplet, not PGraphics -_ this is a tricky thing to implement because of how OpenGL is handled - +_ this is a tricky thing to implement because of how OpenGL is handled _ loadImage() should use the faster loading methods _ hint(DISABLE_IMAGE_CACHING) _ add a note to the loadImage() reference page _ figure out why 1024x768 image takes 3.5 seconds to load _ would using a BufferedImage work better? _ is the image actually a BufferedImage so PixelGrabber is a waste? - _ deprecate the blend() function - +_ move blending calculations from PImage into PGraphics +_ tricky because that means moving blend_resize() as well +_ and should that live in PGraphics or be its own class or ?? _ implement unified means to specify smoothing level for image scaling _ https://github.com/processing/processing/issues/204 +CORE / PGraphics + +_ need to be able to call pixelDensity(2) before beginDraw() +_ add pixelDensity() method to PImage/PGraphics +_ pixelDensity(2) does: pixelWidth = width; width /= 2; pixelDensity = 2; +_ this works for both PGraphics and images (though they're a little backwards) +_ for PGraphics it comes early enough +_ should the re-alloc of the drawing surface happen in beginDraw() +_ that way it won't blit to the screen until we have a fresh redraw? +_ otherwise it'll also be resizing on another thread.. badness +_ how to allocation image object w/ createGraphics() (since no surface) + + CORE / PShape +_ TRIANGLE_STRIP not working correctly with createShape() and default renderer +_ https://github.com/processing/processing/issues/4678 _ major refactoring for PShape/PShapeOpenGL _ https://github.com/processing/processing/issues/1623 _ PShape should be cached as well @@ -461,7 +398,7 @@ _ trying to remember why primitive was changed to kind? (better name?) _ these aren't per-vertex: _ get/setStrokeWeight _ get/setAmbient -_ get/setEmissive +_ get/setEmissive _ get/setShininess _ boolean isGL() -> now removed _ unapproved (made protected) @@ -472,7 +409,6 @@ _ void setParams() _ void setPath() _ colorCalc() methods added to PShape.. should just be used from PGraphics _ loadShape() needs to live in PApplet -_ make PShapeOpenGL a cache object _ don't allow things inside begin/endShape() that aren't possible _ better lockout inside beginShape() to keep other things from happening _ don't allow you to draw stroked items unless stroke() is called @@ -518,13 +454,76 @@ _ PShape getVertex() not implemented properly for SVG files _ https://github.com/processing/processing/issues/1596 -CORE / PVector +FX2D / Issues -_ add screen(PVector), model(PVector) and world(PVector)? -_ maybe screenVec()? or screenXYZ()? +_ many shift- keys not working properly in FX2D (added a test sketch) +_ https://github.com/processing/processing/issues/5317 +_ Fix Java 11 incompatibilities inside PSurfaceFX +_ https://github.com/processing/processing/issues/5286 +_ Hitting ESC in FX2D app on macOS throws IllegalStateException +_ https://github.com/processing/processing/issues/5249 +_ wrong window size with fullScreen() +_ https://github.com/processing/processing/issues/4737 +_ menu bar not hiding properly in exported applications with FX2D +_ https://github.com/processing/processing/issues/4527 +_ hideMenuBar() called from setup() works fine +_ just call it around setup time? +_ the --hide-stop option not working (FX only? traces?) +_ make wiki about quirks +_ starving the thread makes things really slow down +_ keyPressed() is always uppercase, keyTyped() will be correct +_ do we really need setTextFont/Size when we already have Impl? +_ need keyPressed() to do lower and upper case +_ static mode sketches (draw once and halt w/o closing window) +_ fix display handling, line up the device order with AWT +_ https://docs.oracle.com/javafx/2/api/javafx/stage/Screen.html +_ noLoop() +_ present mode not working at all +_ stage in the center, clear the rest of the screen +_ createGraphics() should probably create PGraphicsJava2D +_ or is Canvas specific to the PGraphics, and we get another Context2D? +_ http://docs.oracle.com/javafx/2/api/javafx/scene/canvas/Canvas.html +_ loadPixels() (also 2x) +_ text and fonts? +_ maybe helpful: https://wiki.openjdk.java.net/display/OpenJFX/Font+Setup +_ updatePixels() +_ save() and saveFrame() +_ get() and set() +_ clip/noClip +_ https://github.com/processing/processing/issues/3274 +_ getNative() in PImage problematic because it gives back a BufferedImage +_ move loadImage() into PGraphics, with AWT version the default +_ or pass createImage() through to renderer? +_ implement external messages (moving the window) +_ implement PSurfaceFX.setIcon() +_ javafx not supported with ARM (so we're screwed on raspberry pi) +_ https://www.linkedin.com/pulse/oracle-just-removed-javafx-support-arm-jan-snelders + + +OPENGL / Known Issues + +_ window must close when using file dialogs with OpenGL on Windows +_ https://github.com/processing/processing/issues/3831 +_ window loses focus after maximizing +_ https://github.com/processing/processing/issues/3339 + + +OPENGL / Questions + +_ option to disable OpenGL ES on Linux? +_ https://github.com/processing/processing/issues/4584 +_ exitCalled() and exitActual made public by Andres, breaks Python +_ also not API we want to expose, so sort this out +_ or maybe we're fine b/c now FX2D needs it as well +_ when did setPath() sneak into PShape? API is nothing like anything else +_ probably from the material stuff, but we need to fix that +_ why is createShape() implemented 4x (for P2D, P3D, and 2x versions)? +_ shouldn't be static, run it from the renderer, that's point of createXxx() +_ public createShape() method that takes another shape as param? +_ should just be the constructor doing this, or copy() -CORE / OpenGL (Andres) +OPENGL / Andres _ textureWrap(CLAMP / REPEAT) _ simple NPE in OpenGL causes really large, not useful, stack trace @@ -541,27 +540,14 @@ _ InvScreenX, Y, Z to convert screen (mouse) coordinates to model coordinates _ https://github.com/processing/processing/issues/1609 -CORE / Mac OS X - -_ set the application name to sketch name (not processing.core.PApplet) -_ System.setProperty("com.apple.mrj.application.apple.menu.about.name", ...) -_ -Xdock:name= -_ -Xdock:icon= - - -CORE / Events - -_ touch events.. can't do MouseEvent et al with Android -_ http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html -_ http://www.html5rocks.com/en/mobile/touch.html -_ decision: go with what looks like javascript/ios -_ touchEvent(), gestureEvent()? - - LIBRARIES / PDF +_ tint() not working in PDF (regression between 2.0.3 and 2.1) +_ https://github.com/processing/processing/issues/2428 +_ Implement blendMode() for PDF +_ https://github.com/processing/processing/issues/5438 _ beginRecord() doesn't use current settings of the sketch -_ sometimes reported as a bug, but probably not a good way to +_ sometimes reported as a bug, but probably not a good way to _ consistently carry these over _ pdf sketches exiting before writing has finished _ people have to call exit() (so that dispose() is called in particular) @@ -569,7 +555,7 @@ _ when using noLoop() and the PDF renderer, sketch should exit gracefully _ because isDisplayable() returns false, there's no coming back from noLoop -LIBRARIES / Video +LIBRARIES / Video _ remove dispose() being used in the Movie and Capture _ added warning notes, but shouldn't be necessary @@ -594,7 +580,7 @@ _ can we use String... for options? or does it screw up the method signature? _ and would we have to always concatenate arrays to prepend extensions, etc _ include Instant and Interval? (or just Time and TimeSpan) _ it's going to be File or Reader (mostly BufferedReader) everywhere -_ though TableODS needs an InputStream... +_ though TableODS needs an InputStream... _ and XML could use InputStream if we hope to be able to reflect doc encoding _ ok, so File, Reader, and InputStream (where needed) _ setMissingXxxx() -> should this live in PApplet? be static? @@ -611,7 +597,7 @@ _ that way we can do what's most efficient _ then we add keyIterator() and others to handle the other case (deletion) _ blogs.oracle.com/CoreJavaTechTips/entry/using_enhanced_for_loops_with _ means that JSON.keys() -> JSON.keyIterator(), JSON.keySet() -> JSON.keys() -_ what should they all return? +_ what should they all return? _ remove -> true/false based on whether it found something? _ remove all -> the number removed? _ List: remove(), append(), index(), etc all use values @@ -650,7 +636,7 @@ _ i.e. get unique tables based on a particular column _ or, get uniques, then grab rows that match a name in a particular col _ create table from TableRow iterator...allows for subset and find _ downside is types are not included -_ getMaxFloat() (whole table) or getMaxFloat(col) +_ getMaxFloat() (whole table) or getMaxFloat(col) _ that's max(getFloatColumn(n)) _ also important b/c can leave out missing values _ dictionary support @@ -675,12 +661,12 @@ _ that way, methods could use the information when reading _ loadBytes() needs optimization _ don't bother using a buffering stream, just handle internally. gah! _ can loadBytes() be improved by querying file size first? -_ background +_ background _ this would require a new version of createInput(), which would query _ the URL (or file) for an actual file size. the size is not always _ available, so it can't be relied upon, but would help in some cases. _ loadBytes() is used for images.. ouch -_ might be worth doing a test to see if it actually would help at all +_ might be worth doing a test to see if it actually would help at all _ before rewriting all of createInput() @@ -699,18 +685,15 @@ _ . Textblock _ \ Knob _ \ Progress bar _ \ Toggle -_ implement JSON class -_ http://www.xml.com/lpt/a/1658 -_ http://www.json.org/java/ _ add shader support _ createColor() instead of color()? _ route all exceptions through PException and catch method _ advanced users can override the method if they want _ or you can set an option to have PExceptions be raised -_ decision: just copy & paste the serial/net code.. +_ decision: just copy & paste the serial/net code.. _ until we can find a more compelling example _ actual shape api for things like rectangles and whatnot? -_ should we kill import xxxx syntax for libraries? +_ should we kill import xxxx syntax for libraries? _ just give up and use a gui for it _ cons: copy & paste breaks _ pro: there's no guaranteed 1:1 between packages and single libraries diff --git a/done.txt b/done.txt index e912bfeffc..ef2420519b 100644 --- a/done.txt +++ b/done.txt @@ -1,3 +1,702 @@ +0270 (3.5.4) +X use ctrl-page up/down for tabs on Windows +X https://github.com/processing/processing/issues/5794 +X fix potential highlighting issue that wasn't selecting portions of text +X update AppBundler to use newer SDK, recompile +X edit build.xml files and appbundler to preserve more attributes +X don't remove entries from Recent menu on Save As +X https://github.com/processing/processing/issues/5902 +o NPE in buildCoreModes() on startup +o https://github.com/processing/processing/issues/5823 +X not clear what was wrong here + +contrib manager +X contrib listing names should not be case sensitive +X libs in all caps appeared above those in lowercase +X ignore library subfolders +X don't unzip __MACOSX files with contribs +X don't do library subfolders +X show error when .properties file is missing from contribs +X clean up a lot of bad temp file handling in the contrib manager +X https://github.com/processing/processing/issues/5845 +X https://github.com/processing/processing/issues/5960 +X NPE in installPreviouslyFailed() on startup +X https://github.com/processing/processing/issues/5482 +X https://github.com/processing/processing/issues/5916 + +contribs +X tweak mode not working +X https://github.com/processing/processing/issues/5805 +X https://github.com/processing/processing/pull/5909 + + +0269 (3.5.3) +X added reference for circle(), square(), push(), pop() +X has the reference.zip file been fixed? (yep) +X redo key command for Windows screwed up +X https://github.com/processing/processing/issues/5773 +X fix an editor problem with plain text (css, etc) files +X https://github.com/processing/processing/issues/5628 +X default to using Desktop methods for URLs and files when available on Linux +X also cover a few weird cases that were failing silently +X The package "META" does not exist when .class files found in META-INF folder +X https://github.com/processing/processing/issues/5778 + +contrib +X update translation of "sketch" for Russian speakers +X https://github.com/processing/processing/pull/5673 + +cleaning +o modify line number color when no lines extend that far? +o https://github.com/processing/processing/pull/4560 +o when opening new editor window, open on the same display as current +o https://github.com/processing/processing/issues/4526 +X closing as dupe of the other issue + + +0268 (3.5.2) +X shortcuts not working on Windows/Linux (using meta) +X https://github.com/processing/processing/issues/5763 +X update https://github.com/processing/processing/wiki/Localization#shortcuts-and-key-bindings + + +0267 (3.5.1) +X size() command not working properly +X https://github.com/processing/processing/issues/5759 + + +0266 (3.5) +X update to Java 8u192 +o processing-java doesn't handle sketch exceptions by quitting the sketch +X https://github.com/processing/processing/issues/5375 +X this is by design/follows PDE behavior +X fix the link to the FAQ in the menu +X https://github.com/processing/processing/issues/5729 +X update to Java 8u202 +X "Sketch disappeared" infinite pop up dialogs +X https://github.com/processing/processing/pull/4808 +X https://github.com/processing/processing/issues/4805 +X text("test", 10, 10); is still slow with lots of fonts +X https://bugs.openjdk.java.net/browse/JDK-8179209 +X added a note to the Known Issues section in the Changes wiki +X update the about screen to 2019 +o report of a library or tool (probably includes 2.x? 1.x?) breaking things +o NoSuchFieldError: useNativeSelect +X https://github.com/processing/processing/issues/4821 +X closed, no response +X problems with non-US keyboards and some shortcuts +X https://github.com/processing/processing/issues/2199 +X https://github.com/processing/processing/wiki/Localization#shortcuts-and-key-bindings +o Determine new keyboard shortcut for Step Out +X https://github.com/processing/processing/issues/3538 +X all set based on #2199 +X settings() present and pixelDensity() is in setup(), nothing set/no error +X https://github.com/processing/processing/issues/4703 + +cleaning +X Could not initialize class com.sun.jna.Native on startup (Windows) +X https://github.com/processing/processing/issues/4929 +X closed earlier; fixed as best we could +X sharing usage metrics about libraries +X https://github.com/processing/processing/issues/4708 +X Determine shortcut for Export vs Use Selection for Find +X https://github.com/processing/processing/issues/2985 +o swap font smoothing for tab size? +o implement simple table for prefs? +X still requires restart of the software, so problematic +X need docs for translations +X https://github.com/processing/processing/issues/4018 +X setting a bad font/size in preferences.txt causes a crash on startup +X https://github.com/processing/processing/issues/4085 +o https://github.com/processing/processing/pull/4087 +X can't reproduce with current code + +contrib +X Updated russian translation, now can choose russian in preferences +X https://github.com/processing/processing/pull/5619 +X Turkish translation updates +X https://github.com/processing/processing/pull/5636 +X Examples dialog causes high CPU load +X https://github.com/processing/processing/issues/5246 +X https://github.com/processing/processing/pull/5654 +X console hiding button +X https://github.com/processing/processing/pull/5115 +X NullPointerException in Contribution Manager when installing +X https://github.com/processing/processing/issues/5524 +X https://github.com/processing/processing/pull/5742 +X Improvements to appdata.xml for Linux +X https://github.com/processing/processing/pull/5604 + +jakub +X Fix sketch exception getting hidden by warning +X https://github.com/processing/processing/pull/5486 +X https://github.com/processing/processing/issues/5412 +X EventQueue problems with "could not find sketch size" message +X https://github.com/processing/processing/issues/4893 +X https://github.com/processing/processing/pull/5708 +X https://github.com/processing/processing/issues/5030 (duplicate) +X size(0, 0) just freezes instead of showing an error +X https://github.com/processing/processing/issues/5233 (duplicate) + + +0265 (3.4) +X make it possible to override theme.txt with a file in the sketchbook folder +X https://github.com/processing/processing/issues/5445 +X https://github.com/processing/processing/wiki/Dark-Theme-for-PDE +X add 2018 to p5 launch screen +X also update the bmp version +X redesign the Rename window to be less ugly +X Close the Rename window when ESC pressed +X https://github.com/processing/processing/issues/5391 +X Set default operation for Rename window +X https://github.com/processing/processing/issues/5400 +X add select/copy to the status bar +X https://github.com/processing/processing/issues/5271 +o possible fix (just copies on click) +o https://github.com/processing/processing/pull/5345 +X in the docs: modify 'search.format=' in preferences.txt +X refactoring inside the completion code +X https://github.com/processing/processing/commit/7e3661e9f7a6df1569c8bebc683e7742f50caa25 +X https://github.com/processing/processing/commit/20c6f86c0d600806c991962eb208548ac45e9e2a +X https://github.com/processing/processing/commit/8dda8a4d02bc9a1d15e81fee3e6c183e4076a40e +X https://github.com/processing/processing/commit/ff7dc4d5094ccf1cc35189c9412adda93153b436 +X add pyde as a supported extension +X https://github.com/jdf/processing.py/issues/284 +o update to launch4j 3.11? +o http://launch4j.sourceforge.net/changelog.html +X update to Java 8u172 +X show alternate error message on windows when JNA breaks or core.jar is missing +X https://github.com/processing/processing/issues/5537 +X https://github.com/processing/processing/issues/4929 +X https://github.com/processing/processing/issues/5442 +X https://www.microsoft.com/en-us/wdsi/filesubmission +X update to Java 8u181 +X https://github.com/processing/processing/pull/5586 +X Contributed libraries/examples/etc that redirect to https are failing download +X https://github.com/processing/processing/issues/5554 + +welcome +o just remove the welcome dialog; but what should the default behavior be? +o or should it only show up for people who have used <=2 but not 3? +X click "show this welcome" text to check/uncheck the box +X https://github.com/processing/processing/issues/3912 +X submit the form (as if 'get started' clicked) when closing the window +X whether hitting ESC or the close box on the window +X https://github.com/processing/processing/issues/3911 +o Welcome dialog rewritten in Swing +X https://github.com/processing/processing/pull/5210 + +gohai +X additional I/O improvements +X https://github.com/processing/processing/pull/5581 +X rpi regressions in 3.3.7.1 +X https://github.com/processing/processing/issues/5582 +X OpenGL ES: Fix GLSL version number for 1.00 +X https://github.com/processing/processing/pull/5583 +X Add ADS1X15 Analog-to-Digital converter example +X https://github.com/processing/processing/pull/5590 + +gohai (from 3.3.7.1 special release) +X IO: pinMode() can now set pull-up and pull-down resistors on Raspbian +X thanks to @xranby for 64-bit help +X several new examples +X https://github.com/processing/processing/pull/5566 +X IO: New example sketch showing how to use a MPR121 capacitive touch sensor +X fun tutorial by @msurguy forthcoming +X IO: New example sketch showing how to use a BME280 environmental sensor +X contributed by @OlivierLD +X IO: New example sketch showing how to use a TSL2561 light sensor +X contributed by @OlivierLD +X IO: New example sketch showing how to use a PCA9685 Servo & PWM controller +X contributed by @OlivierLD +X IO: pinMode() got faster +X https://github.com/processing/processing/pull/5557 +X IO: I2C now supports talking to slower devices, such as Arduino boards +X https://github.com/processing/processing/pull/5567 +X Support for ARM Mali graphics was added to P2D/P3D +X thanks to seongwook from the forums for his help during bringup +X https://github.com/processing/processing/pull/5485 +X P3D now supports up to 4 lights on Pi using their OpenGL driver +X Serial library now supports Raspbian's port naming (such as "/dev/serial0") +X Enable exporting of Windows applications on ARM +X https://github.com/processing/processing/pull/5488 +X https://github.com/processing/processing/issues/5287 +X clarify SimpleInput example +X https://github.com/processing/processing/pull/5558 + +jakub +X Make sure editor is updated after reloading changes +X https://github.com/processing/processing/pull/5487 +X https://github.com/processing/processing/issues/5466 + +contrib +X updates to Japanese translation +X https://github.com/processing/processing/pull/5263 +X added Russian translation +X https://github.com/processing/processing/pull/5451 +X make "loadXML(String)" handle "file not found" +X https://github.com/processing/processing/pull/5144 +X Update java.lang.UnsupportedClassVersionError message +X https://github.com/processing/processing/pull/5459 + + +0264 (3.3.7) +X downloading the jre broken again +X https://github.com/processing/processing/issues/5284 +X the old 144 link must have been removed +X NullPointerException in ContributionManager.deleteFlagged() +X https://github.com/processing/processing/issues/5342 +X move to Java 8u162 +X menu bars broken in High Sierra +X https://github.com/processing/processing/issues/5272 +X no more responses, had to close +X include newlines at end of files (i.e. when saving .pde files) +X https://github.com/processing/processing/issues/5327 +X explanation: https://stackoverflow.com/a/729795 +X http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206 +X Rename dialog is unusable on high density screen +X https://github.com/processing/processing/issues/5368 +X windows defender blocks processing 3.3.6 +X https://github.com/processing/processing/issues/5329 +X this should be fixed, simply by a new release + +jakub +X Fix scrub comments for empty block comment /**/ +X https://github.com/processing/processing/pull/5265 +X https://github.com/processing/processing/issues/5219 +X Fix error checker crash when className contains [ or ] +X https://github.com/processing/processing/pull/5304 +X major fixes for the net library +X https://github.com/processing/processing/pull/5378 +X https://github.com/processing/processing/issues/4419 +X https://github.com/processing/processing/issues/5360 +X https://github.com/processing/processing/issues/3970 +X https://github.com/processing/processing/pull/5389 +X Output java files in UTF-8 and force compiler to use UTF-8 +X https://github.com/processing/processing/pull/5436 +X PdePreprocessor change is breaking current source +X https://github.com/processing/processing/issues/5413 + +contrib +X detect errors from curved quotation marks +X https://github.com/processing/processing/issues/5133 +X https://github.com/processing/processing/pull/5152 +X Refactor to use a few Java 8 features +X https://github.com/processing/processing/pull/5134 +X Remove "Pipe Organ" from exec javadoc +X https://github.com/processing/processing/pull/5282 +X typo in Italian translation +X https://github.com/processing/processing/issues/5365 + + +0263 (3.3.6) +X update to Java 8u144 +X fix issue with call to remove value instead of key in mode contrib hash +X this was only in the code used by the command line mode loader +o data folder not exporting on macOS? +o https://github.com/processing/processing/issues/5207 +X confirmed working with LoadDisplayImage example + +contrib +X add Italian translation +X https://github.com/processing/processing/pull/5169 +X Wrong tab for missing brace +X https://github.com/processing/processing/pull/5180 +X https://github.com/processing/processing/issues/5165 +X typo in German translation +X https://github.com/processing/processing/pull/5195 +X https://github.com/processing/processing/issues/5187 +X movie maker a little broken +X https://github.com/processing/processing/issues/5168 +X https://github.com/processing/processing/pull/5230 +X Add more build products to linux/.gitignore +X https://github.com/processing/processing/pull/5229 +X add issue template to the repo +X https://github.com/processing/processing/issues/5239 +X https://github.com/processing/processing/pull/5245 + +jakub +X Fix comment/uncomment adding slashes at wrong indent +X https://github.com/processing/processing/issues/5171 +X https://github.com/processing/processing/pull/5185 +X Add JavaFX runtime to error checker class path +X https://github.com/processing/processing/pull/5186 + + +0262 (3.3.5) +X use native Linux file choosers by default +X https://github.com/processing/processing/issues/5122 +X Console window losing text +X https://github.com/processing/processing/issues/5110 +X Linux 64-bit issues +X https://github.com/processing/processing/issues/5111 + +contrib +X display=-1 regression ("could not parse" message) +X https://github.com/processing/processing/issues/5118 +X https://github.com/processing/processing/pull/5141 + + +0261 (3.3.4) +X redo console handling to not use Timer, fixing freeze-up problems +o https://github.com/processing/processing/pull/4935 +X https://github.com/processing/processing/issues/4825 +X clean up error message for sketchbook location +X https://github.com/processing/processing/issues/4942 +X Application Exports report as "Damaged" on macOS Sierra +X https://github.com/processing/processing/issues/4705 +X could provide script to un-quarrantine +X xattr -d -r com.apple.quarantine +X https://github.com/steakknife/unsign +X https://developer.apple.com/library/content/technotes/tn2318 +X 'run sketches on display' message shows up on clean install +X should ant run launch the .app so that launchsvcs stuff works properly? +X double-clicking a .pde file won't open the app correctly +X add 'ant app' target, at least for macOS +X add null check to sketch loading +X discovered during https://github.com/processing/processing/issues/4980 + +gohai +X IO library updates +X https://github.com/processing/processing/pull/5044 +X Consider $SUDO_USER on Linux for locating the sketchbook folder +X https://github.com/processing/processing/pull/5055 +o https://github.com/processing/processing/pull/5054 + +jakub +X more updates to the change detector +X https://github.com/processing/processing/pull/5075 + +contrib +X Make the change detector not reload the sketch +X https://github.com/processing/processing/issues/4713 +X https://github.com/processing/processing/pull/5021 +X https://github.com/processing/processing/pull/4849 +X Warn user to use L when creating a number constant that won't fit into an int +X https://github.com/processing/processing/issues/4878 +X https://github.com/processing/processing/pull/5077 +X add install/uninstall scripts for Linux and correct mime types for IDE +X https://github.com/processing/processing/pull/5106 + + +0260 (3.3.3) +X no changes to the PDE for 3.3.3 + + +0259 (3.3.2) +X no changes to the PDE in this release + + +0258 (3.3.1) +X fix the JRE downloader +X https://gist.github.com/P7h/9741922 +X http://stackoverflow.com/q/10268583 +X move to 8u131 +X add another warning for a bad NVIDIA driver +X https://github.com/processing/processing/issues/4997 +X Gap between tab headers and text area at 125% and 150% scaling on Windows +X https://github.com/processing/processing/issues/4902 +X Math.ceil() helps +X Small tooltip text on high-dpi screens +X https://github.com/processing/processing/issues/4914 +X make the Error Table extend white to the bottom +X was making a gray box on Windows, probably Linux too +X some line heights are wrong on hidpi +X usage window +X examples window +X sketchbook window +X https://github.com/processing/processing/issues/4936 +X https://github.com/processing/processing/issues/5007 +X get rid of error message when exporting sketches with the video library +X https://github.com/processing/processing/issues/4971 +X use dialog font for processing.sans if using a non- or quirky Roman language +X make this a parameter of the language translation + +jakub +X Fix preprocessing of code with double backslash in string or char literal +X https://github.com/processing/processing/issues/4903 +X https://github.com/processing/processing/pull/4907 +X Ugly button images at 125% and 150% scaling on Windows +X https://github.com/processing/processing/issues/4901 +X https://github.com/processing/processing/pull/4906 +X Fix breakpoints in inner classes +X https://github.com/processing/processing/pull/5008 +X https://github.com/processing/processing/issues/2946 +X Fix preproc skipping one char after a block comment +X https://github.com/processing/processing/issues/4995 +X https://github.com/processing/processing/pull/4999 +X Synchronize input event processing +X https://github.com/processing/processing/pull/4998 +X Scrub comments: skip the second chracter in the escape sequence +X https://github.com/processing/processing/pull/5019 +X https://github.com/processing/processing/issues/5016 + +gohai +X Add support for 64-bit ARM boards +X https://github.com/processing/processing/pull/5002 +X Hardware I/O updates for ARM +X https://github.com/processing/processing/pull/4931 + +contrib +X Added Arabic translation +X https://github.com/processing/processing/pull/4970 +X add Jump to Declaration +X https://github.com/processing/processing/pull/4707 +X https://github.com/processing/processing/issues/4668 + +awaiting confirmation (fixed in 3.3) +X visual artifacts on Windows 10 when using menus +X https://github.com/processing/processing/issues/4700 +X Broken characters in the Welcome Page and the Contribution Manager +X https://github.com/processing/processing/issues/4747 +X looks like a failure to load the Source Sans font +X what happens if font loading fails? +X are there conflicts between version in lib and OS? +o are we still installing fonts into ext? +o fixed by rolling back to 8u92, broken since 8u102 in 3.1.2 +X NVIDIA driver problems (and means to check) +X https://github.com/processing/processing/issues/4853 +X blank window on startup where the "Welcome" screen should be +X this may be fixed (removed invokeLater() on startup), unconfirmed +X https://github.com/processing/processing/issues/3933 +X Olivia hasn't seen it, closing +X amazing blurry editor window +X https://github.com/processing/processing/issues/4892 + + +0257 (3.3) +X check for already-exported folders before trying to remove them +X was spewing 'file not found' errors into the console +X PDE and sketches are 2x smaller on high-res Windows machines +X https://github.com/processing/processing/issues/2411 +o System.setProperty("sun.java2d.dpiaware", "false"); +X though that seems broken in Java 8: http://superuser.com/a/1007783 +X until we fix it.. +o call this from JNA? https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx +o or modify the manifest/app? https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx +o hidpi scaling via font changes? +o http://stackoverflow.com/a/34152675 +X hi-dpi support on Linux +X https://github.com/processing/processing/issues/4183 + +cleaning +X Contribution Manager does not show all libraries until filter cleared +X https://github.com/processing/processing/issues/4840 +X fixed in 3.2.4 + +unconfirmed +X visual artifacts on Windows 10 when using menus +X https://github.com/processing/processing/issues/4700 +X Broken characters in the Welcome Page and the Contribution Manager +_ https://github.com/processing/processing/issues/4747 +X looks like a failure to load the Source Sans font +X what happens if font loading fails? +X are there conflicts between version in lib and OS? +o are we still installing fonts into ext? +o fixed by rolling back to 8u92, broken since 8u102 in 3.1.2 +X NVIDIA driver problems (and means to check) +_ https://github.com/processing/processing/issues/4853 +X blank window on startup where the "Welcome" screen should be +X this may be fixed (removed invokeLater() on startup), unconfirmed +X https://github.com/processing/processing/issues/3933 + + +0256 (3.2.4) +X only require reference.zip (and internet connection) when building dist +X set text style properly for Contribution Manager error message +X Detect changes to 'hosts' file in case users modify/remove localhost +X https://github.com/processing/processing/issues/4738 +X No sketch window opens after hitting Run if hosts file changed +X https://github.com/processing/processing/issues/1868 +X https://github.com/processing/processing/issues/3123 +X https://github.com/processing/processing/issues/4735 +X move the DEBUG flag into an external file or preferences.txt +X will help us with debugging w/ others as well +X change to debug.txt; too confusing with the folder thing +X replace java.util.logging code with built-in logging +X split gui and non-gui portions of console for earlier startup +X split EditorConsole into gui and non-gui code? +X otherwise System.err/out not going to a file unless we have GUI +X also can't debug before the GUI shows up +o gracefully recover from proxy problems +X https://github.com/processing/processing/issues/1601 +X JRE download fails during ant build +X https://github.com/processing/processing/issues/4823 +X changed headerType to console (make sure changed back) +X Spaces not handled correctly in when installing "processing-java" on macOS +X https://github.com/processing/processing/issues/4779 + +contrib +X Added the remove filter feature +X https://github.com/processing/processing/pull/3890 +X ctrl-J (for debugger) is inserting newline +X https://github.com/processing/processing/issues/3830 +X Replace keyChar with keyCode to prevent new line error when debugging +X https://github.com/processing/processing/pull/4806 +X https://github.com/processing/processing/issues/4804 + +jakub +X println(int(byte(245))) throwing error +X https://github.com/processing/processing/issues/4652 +X https://github.com/processing/processing/pull/4744 +X 'web colors' next to each other fail to parse in certain situations +X https://github.com/processing/processing/issues/4752 +X https://github.com/processing/processing/pull/4753 +X Pasting code from editor to empty editor produces Exception +X https://github.com/processing/processing/issues/4522 +X https://github.com/processing/processing/pull/4761 +X possible infinite loop on modified externally +X https://github.com/processing/processing/issues/3965 +X https://github.com/processing/processing/pull/4762 +X Report missing brace in correct tab, suppress other errors until fixed +X https://github.com/processing/processing/pull/4777 +X https://github.com/processing/processing/issues/4702 +X Improvements to sketch launching and stopping +X https://github.com/processing/processing/pull/4848 +X several Contribution Manager fixes +X https://github.com/processing/processing/pull/4844 +X Add missing equals() and hashCode() to Contribution +X https://github.com/processing/processing/pull/4843 +X Contribution Manager does not show all libraries until filter cleared +X https://github.com/processing/processing/pull/4843 +X https://github.com/processing/processing/issues/4840 +X Mode, requiring update, appears in Updates tab but not in Modes tab +X https://github.com/processing/processing/issues/4822 +X also fixed w/ https://github.com/processing/processing/pull/4843 +X Syntax highlighting issues (fixed with #4761) +X https://github.com/processing/processing/issues/4286 +X sketchbook window doesn't update when sketches are added, renamed, etc +X https://github.com/processing/processing/issues/2944 +X https://github.com/processing/processing/pull/4842 + +cleaning +X clean up 'ant doc' target to remove warnings +X https://github.com/processing/processing/issues/1492 +X fixed in 3.1.1 +X Horizontal scrollbar does not scroll textarea all the way +X https://github.com/processing/processing/issues/3591 +X mostly fixed in 3.0b7, opting to wait for RSyntaxArea or whatever +X possible PR for updating sketchbook stuff +o https://github.com/processing/processing/pull/3081 +X should be covered by other fixes +X longer PR about sketchbook stuff, but closed +X https://github.com/processing/processing/pull/3178 +X closed back in April 2015, issue was all over the place +X fix encodings, line endings, and mime types in the repo +X https://github.com/processing/processing/issues/2955 +X fixed 2015-11 https://github.com/processing/processing/pull/2977 +X need to handle the 2.x to 3.x sketchbook transition +X prefs are the same file, but sketchbook location pref is different +o performance +o video stinks.. java2d stinks.. macs stink +o note in the 'drawing in 2d' section of faq +o fastest machine possible +o turn off hyperthreading in the bios +o nice gfx card only helps opengl +o dual processor not particularly useful, unless you make more threads +o but making more threads is often more work than is useful +X too out of date +X why adding .0001 to a float doesn't work +X and how they're imprecise in general (use nf) +X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1130877990 +X long since added to the FAQ +X infinite "file changed" popups +X https://github.com/processing/processing/issues/3965 +o https://github.com/processing/processing/pull/4037 +X https://github.com/processing/processing/pull/4037 + + +0255 (3.2.3) +X ensure that update.id is set before checking for contrib updates +X if prettyVersion is blank (or null?), just use version (Firmata) +X clicking "Update" button in contrib manager shows non-retina version of icon +X https://github.com/processing/processing/issues/4715 +o problem is because AquaButtonUI is calling getImage() (not getIcon()) +o can be debugging from inside the getIconX() code in Toolkit +X just needed to use setPressedIcon(), setDisabledIcon() +X also found some other issues around the icon handling +X fix the library reporting scripts on the server +X missing version number putting 'null' in the ui +X https://github.com/processing/processing-docs/issues/478 +X https://github.com/processing/processing/issues/4696 +X https://github.com/processing/processing/pull/4712 +o replace appbundler with the Java 8 packager +o appbundler is no longer being developed by Oracle, switch to "packager" +X https://github.com/processing/processing/issues/3071 +X major clean-ups to the Contribution Manager code +X warn user to restart browser when it hangs on macOS +X https://github.com/fathominfo/processing-p5js-mode/issues/4 + +contribs +X Up-to-date status disappears after filter is removed +X https://github.com/processing/processing/issues/4084 +X Updates tab blank after adding, removing, updating a contribution +X https://github.com/processing/processing/issues/4082 +X https://github.com/processing/processing/issues/4704 +X Fixes the removal of redundant contribution and update related issues +X https://github.com/processing/processing/pull/4086 + + +0254 (3.2.2) +X Find in reference for size() opens StringList.size() +X https://github.com/processing/processing/issues/4224 +X though that's still imperfect: +X https://github.com/processing/processing/issues/4655 +X limit rollovers on EditorStatus to the text portion +X clicking the status area when it has a url is problematic +X because it's also the vertical separator +X at least change it to only cover the text? +X add a rollover so people know what it's doing? +X switch to 8u112 for building +X switch down to 8u111 because of different build numbers +X https://github.com/processing/processing/commit/8a3a183f327a5ee680e1932dd9f123491f75a8b9 +X more font tweaks to make mono fonts work properly after #4639 +X update the Linux notes based on where we land on this +X https://github.com/processing/processing/wiki/Supported-Platforms#linux +X "Could not open the url" when clicking on the error message +X https://github.com/processing/processing/issues/4695 +X fix extensions handling in CFBundleDocument code from appbundler +X https://github.com/processing/processing/issues/4615 +X update launch4j to 3.9 +X https://sourceforge.net/projects/launch4j/files/launch4j-3/3.9/ +X exported application doesn't work with latest jre +X https://github.com/processing/processing/issues/4682 +X string comparison fix +X https://github.com/processing/processing/issues/4670 + +gohai +X Simplify font situation to make it possible to use vanilla JRE trees +X https://github.com/processing/processing/pull/4639 +X Trivial updates for ARM +X https://github.com/processing/processing/pull/4640 +X Remove all the extra hoops for loading fonts +X https://github.com/processing/processing/pull/4641 + +contrib +X Chinese translation updates +X https://github.com/processing/processing/pull/4661 +X Spanish translation updates +X https://github.com/processing/processing/pull/4697 +X Spanish "open sketch folder" fix +X https://github.com/processing/processing/pull/4710 +X Contribution Manager showing 'null' for PeasyCam version +X https://github.com/processing/processing/pull/4712 +X https://github.com/processing/processing/issues/4696 + + +0253 (3.2.1) +X "Could not replace preferences.old" error message +X https://github.com/processing/processing/issues/4626 +X Version 3.2 won't run from paths with spaces on Windows +X https://github.com/processing/processing/issues/4623 +X might be ext.dirs trouble with spaces in path names? +X or the backwards slashes? +X fixes for Python Mode crashing on startup +X disable ext.dirs on Linux export and set jna.nosys as well +X Java not included properly with 32-bit Linux export +X JavaInputHandler not registering + + 0252 (3.2) X Processing .jar files in CLASSPATH can cause startup crash X https://github.com/processing/processing/issues/4128 @@ -318,7 +1017,7 @@ X Add i18n support for the PopUp menu X https://github.com/processing/processing/pull/4060 X Add Turkish to the list of languages X https://github.com/processing/processing/pull/4073 -X Make the error message for stack overflows clearer +X Make the error message for stack overflows clearer X https://github.com/processing/processing/pull/4152 X get rid of dt_socket message, making command line run a little better X https://github.com/processing/processing/issues/4098 @@ -473,7 +1172,7 @@ X implement side gradient on the editor X if fewer lines in sketch than can be shown in window, show ticks adjacent X error/warning location is awkward when no scroll bar is in use X when only one screen-full, show ticks at exact location -X simpler/less confusing to not show at all? +X simpler/less confusing to not show at all? X MarkerColumn.recalculateMarkerPositions() X https://github.com/processing/processing/pull/3903 X Update status error/warning when changing the line @@ -510,7 +1209,7 @@ X change selection highlight color o put some margin around it X https://github.com/processing/processing/issues/3906 X completion panel -X what should the background color be? +X what should the background color be? X test fg/bg color on other operating systems J fix icon sizes/design X set a better minimum size for the number of updates available @@ -578,7 +1277,7 @@ X need to check if "save as" thing is causing trouble X "Your sketch has been modified externally" with encrypted OS X volumes X https://github.com/processing/processing/issues/3650 o add this to the preferences? -o use watcher service after all? +o use watcher service after all? o https://docs.oracle.com/javase/tutorial/essential/io/notification.html jna problems @@ -616,7 +1315,7 @@ o Contributions Manager UI design X https://github.com/processing/processing/issues/3482 X closing in favor of separate issues X updates tab has ugly horizontal line at top -X CM selected tabs are too tall +X CM selected tabs are too tall X https://github.com/processing/processing/issues/3598 X why the aqua background when opening the window? X get rid of gross italic subheads on the Updates page @@ -660,7 +1359,7 @@ X https://github.com/processing/processing/pull/3856 X Red error underline is sometimes at wrong location X https://github.com/processing/processing/issues/3759 X https://github.com/processing/processing/pull/3848 -X using "new color()" instead of "color()" results in "color type detected" +X using "new color()" instead of "color()" results in "color type detected" X happens when user does 'new color' instead of 'color' X https://github.com/processing/processing/issues/3739 X https://github.com/processing/processing/pull/3850 @@ -673,8 +1372,8 @@ X problem was that the example was creating files inside Processing.app X Casey reports that exported app still asks to download Java X could this be a JOGL bug (linking against the app stub?) X ran otool -L on the binaries and saw nothing -X deal with ConcurrentModificationException in Editor -X "Error repainting line range" and ConcurrentModificationException +X deal with ConcurrentModificationException in Editor +X "Error repainting line range" and ConcurrentModificationException X https://github.com/processing/processing/issues/3726 X repairs to prevent memory leak in EditorConsole o Claim that an exported application does not copy data directory @@ -816,7 +1515,7 @@ o need an "install library" option to deal with urls.. X need better platform designation setup for libs X library installation should use the sketchbook folder, not the p5 folder o actually enforce this, give users a warning about other libs -o versioning info +o versioning info o http://java.sun.com/j2se/1.5.0/docs/guide/extensions/versioning.html X changing the sketchbook folder will make libraries show up o but it won't reload the library mapping table @@ -899,7 +1598,7 @@ X Comment/Uncomment should ignore leading whitespace X https://github.com/processing/processing/issues/1961 X Export unsaved sketch > agree to save prompt > export doesn't finish X https://github.com/processing/processing/issues/2724 -X Add disconnectEvent() to Server +X Add disconnectEvent() to Server X https://github.com/processing/processing/issues/2133 X False positive for mixing active/static mode in Tweak Mode 3.0 alpha 5 X https://github.com/processing/processing/issues/3140 @@ -951,7 +1650,7 @@ o Invalid code signature on OS X X https://github.com/processing/processing/issues/3575 X cannot reproduce -gsoc +gsoc X Breakpoints don't 'jump' after hitting Enter on blank line X https://github.com/processing/processing/issues/3552 X https://github.com/processing/processing/pull/3571 @@ -1240,7 +1939,7 @@ X https://github.com/processing/processing/issues/498 X should be able to build p5 without a JDK install, just a JRE X https://github.com/processing/processing/issues/1840 X need to have ecj.jar accessible to ant, then modify build.xml to use this: -X X http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-ant_javac_adapter.htm @@ -1351,7 +2050,7 @@ X https://github.com/processing/processing/issues/3209 X sketchbook window is completely empty w/ no sketches X requires restart of p5 before it updates X https://github.com/processing/processing/issues/3214 -X Replace & Find was reading "Find & Replace" +X Replace & Find was reading "Find & Replace" X https://github.com/processing/processing/issues/3247 X "one file added to sketch" message when two files added X turned out to be really messy ProgressFrame code @@ -1365,7 +2064,7 @@ X https://github.com/processing/processing/wiki/Running-without-a-Display X write up code guidelines for project X make proper Eclipse style prefs to reinforce X https://github.com/processing/processing/wiki/Style-Guidelines -X change preproc to write settings() method instead of sketchXxxx() +X change preproc to write settings() method instead of sketchXxxx() cleaning X better text editor / live debugging (integrate Eclipse JDT) @@ -1452,7 +2151,7 @@ X https://github.com/processing/processing/pull/3216 0233 (3.0a6) X post a note about the "help" stuff X https://github.com/processing/processing/labels/help -X Deal with ctrl-alt-n regression +X Deal with ctrl-alt-n regression X https://github.com/processing/processing/issues/2979 X don't add a ^M to files when writing X https://github.com/processing/processing/issues/3014 @@ -1490,7 +2189,7 @@ X was because of the readSettings() change integration of pdex/debug o make the tabs have a default minimum size o multiple sizes as they get smaller (web browser style) -X merge experimental into the main Java mode +X merge experimental into the main Java mode X thereby removing Java 2.0 mode from the next release X otherwise redoing the design for 2 modes X changed JLS4 to JLS8 (but make sure it doesn't introduce anything too weird) @@ -1523,7 +2222,7 @@ o update ld and windres: https://github.com/processing/processing/tree/master/ o also xstream.jar https://github.com/processing/processing/tree/master/java/application/launch4j/lib earlier -X any problems with new code signing crap? +X any problems with new code signing crap? X issues raised around the symlink (just replace with a copy of the binary?) X fixed the short-term problem, filed an issue for the rest X https://developer.apple.com/library/prerelease/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG205 @@ -1652,7 +2351,7 @@ X https://github.com/processing/processing/issues/3133 X https://github.com/processing/processing/pull/3177 X Fix ColorChooser cursor X https://github.com/processing/processing/pull/3186 -X Improve Spanish localization +X Improve Spanish localization X https://github.com/processing/processing/pull/3185 X internationalization of editor error messages and greek translations X https://github.com/processing/processing/pull/3189 @@ -1723,7 +2422,7 @@ pulls (net) X NullPointerException message when Server writes to a disconnected client X https://github.com/processing/processing/issues/2577 X https://github.com/processing/processing/pull/2578 -X Implement the active() method for Serial and Server +X Implement the active() method for Serial and Server X https://github.com/processing/processing/issues/2364 X https://github.com/processing/processing/pull/2588 @@ -1768,7 +2467,7 @@ X closed by Dan post-3.0a3 X move sketchbook into its own window X move recent into the sketchbook menu X try installing 10.7.3 on Mac Mini and check whether things run -X make sure it's only running on 64-bit machines? +X make sure it's only running on 64-bit machines? gsoc X remove dependency on oscp5 library for tweak mode @@ -1920,7 +2619,7 @@ X fix "No such file or directory" error when exporting an application on OSX X this also resulted in the application not being signed at all X https://github.com/processing/processing/issues/2614 X this is a fairly major issue... -X possible to open a sketch multiple times +X possible to open a sketch multiple times X by double-clicking one of its files instead of the main pde file X user opens non-main pde of already open sketch, it'll open again X https://github.com/processing/processing/issues/2506 @@ -1937,7 +2636,7 @@ X some aren't being removed properly X fix the build scripts to include the examples X https://github.com/processing/processing/issues/2652 X all examples are out of "processing/java" and are now in "processing-docs/content/". The Book examples have been removed entirely from our repositories. -o "Platform is ${platform}" message during 'ant clean' +o "Platform is ${platform}" message during 'ant clean' o on OS X, but not Windows (haven't checked Linux) X this was in pdex/build.xml X remove welcome message from the sound library @@ -1979,7 +2678,7 @@ X https://github.com/processing/processing/pull/2657 pulls X insert tabs properly when prefs set for tabs mode X https://github.com/processing/processing/pull/2607 -X improve look of Nimbus LAF +X improve look of Nimbus LAF X https://github.com/processing/processing/pull/2671 earlier @@ -1992,7 +2691,7 @@ X https://github.com/processing/processing/issues/2141 o double-clicking a .pde file doesn't open properly on OS X o https://github.com/processing/processing/issues/2639 X moving p5 examples to the web repo -X move examples into web repo +X move examples into web repo o OS X not opening a sketch at all on pde double-click? (though opening the app) X Chinese text is overlapped in Processing 2.1 editor X https://github.com/processing/processing/issues/2173 @@ -2013,7 +2712,7 @@ X https://github.com/processing/processing/issues/2545 earlier X cpu usage when nothing happening (unmarked duplicate) -X https://github.com/processing/processing/issues/1074 +X https://github.com/processing/processing/issues/1074 gsoc X Line coloring incorrect for filtered contribution listings @@ -2061,7 +2760,7 @@ X missing 'version' in contrib causes NPE X https://github.com/processing/processing/issues/2517 X bring back setIcon(Frame) for PDE X and others X https://github.com/processing/processing-experimental/issues/64 -X how was PDE X able to crash 2.2? +X how was PDE X able to crash 2.2? X add additional code to rework how this is handled X Auto Format patch mess X https://github.com/processing/processing/pull/2271 @@ -2103,7 +2802,7 @@ X fix for Windows command line X fix for Linux launcher X fix for Linux export X fix for Linux command line -X fix for OS X launcher +X fix for OS X launcher X fix for OS X export X fix for OS X command line X import static causes exception (with fix) @@ -2250,7 +2949,7 @@ G Handle the UnsatisfiedLinkError when loading the native library fails G https://github.com/processing/processing/pull/2266 fixed in 2.1 -X init() not called on tools until later +X init() not called on tools until later X https://github.com/processing/processing/issues/1859 X Finish changes so the PDE can use an unmodified JRE X https://github.com/processing/processing/issues/1840 @@ -2258,8 +2957,8 @@ X https://github.com/processing/processing/issues/1840 0223 pde (2.1) X reset font smoothing for everyone to its default by changing the pref -X To reset everyone's default, replaced editor.antialias with editor.smooth -X for 2.1. Fonts are unusably gross on OS X (and Linux) w/o smoothing and +X To reset everyone's default, replaced editor.antialias with editor.smooth +X for 2.1. Fonts are unusably gross on OS X (and Linux) w/o smoothing and X the Oracle JVM, and many longtime users have anti-aliasing turned off. X https://github.com/processing/processing/issues/2164 X https://github.com/processing/processing/issues/2160 @@ -2331,7 +3030,7 @@ X spacing problem with large sizes (on retina?) X not just retina, was problem with non-mono text from Java X control text size in console o why aren't prefs from theme.txt showing up in preferences.txt? hrm -o or rather, why can't they be overridden? +o or rather, why can't they be overridden? X because theme.txt data is a different animal / that's part of the point X should fonts at least be in prefs.txt? X http://code.google.com/p/processing/issues/detail?id=226 @@ -2359,7 +3058,7 @@ X had already been closed X serial ports missing from list (OS X) X http://code.google.com/p/processing/issues/detail?id=52 X also was marked fixed... -X Serial.write problem with Bluetooth SPP virtual serial port +X Serial.write problem with Bluetooth SPP virtual serial port X http://code.google.com/p/processing/issues/detail?id=318 X was marked duplicate of #52 X Serial silently fails when invalid port entered as string @@ -2491,7 +3190,7 @@ X fix submitted by hamoid 0220 pde (2.0.2) -X fix "less less" typo +X fix "less less" typo X https://github.com/processing/processing/issues/1928 X slash breaks syntax highlighting (with spaces) X https://github.com/processing/processing/issues/1681 @@ -2509,11 +3208,11 @@ X https://github.com/processing/processing/issues/1908 X Update JNA from 3.2.4 to 3.5.2 X https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/3.5.2/jna-3.5.2.jar X https://maven.java.net/content/repositories/releases/net/java/dev/jna/platform/3.5.2/platform-3.5.2.jar -X problem with associating .pde files +X problem with associating .pde files X https://github.com/processing/processing/issues/286 X http://code.google.com/p/processing/issues/detail?id=247 o In regedit: Navigate to Computer\HKEY_CLASSES_ROOT\Applications and find your .exe name. Navigate under its name to shell>open>command. In the Default change its location to the actual location of the executable, hit okay and then try and reassociate the file type as you normally would. -X UnsatisfiedLinkError causes huge message... +X UnsatisfiedLinkError causes huge message... X error report cleanups haven't been fixed yet X reported by Dan X this should be better now @@ -2631,7 +3330,7 @@ o check if libraries folder does not exist o check to see if other libraries are installed X warn user about moving libraries and restarting X add "pretty menu name" to the export.txt file -o move export.txt to xml? +o move export.txt to xml? X nah, it's only flat information X tools -> get library X library url: [ http://blahblah.org/something ] @@ -2711,7 +3410,7 @@ o also send pull request for Florian manager X "New version available" mesage is showing html tags around it X https://github.com/processing/processing/issues/1684 -X shift color of installed items when selected +X shift color of installed items when selected X was ugly gray over selection color X fix layout of the update button X get update text to align vertically @@ -2725,7 +3424,7 @@ X MovieMaker tool will not start on Windows 8 X make a little less fragile by not launching as separate process X http://code.google.com/p/processing/issues/detail?id=1447 X clean up the code and interface for the Movie Maker tool -X http://code.google.com/p/processing/issues/detail?id=836 +X http://code.google.com/p/processing/issues/detail?id=836 X on Windows, the Help menu seems to start with a separator X add 6u37 as the Java runtime o TextAreaDefaults - is editable in use? @@ -2749,7 +3448,7 @@ X NSHighResolutionCapable X true X add basics of retina support to the toolbar and header X getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor"); -X paper over ArrayIndexOutOfBoundsException in JEditTextArea.xToOffset() +X paper over ArrayIndexOutOfBoundsException in JEditTextArea.xToOffset() X Fix IllegalStateException on Windows/Linux in Save prompt X happened when hitting ESC or otherwise closing the window X "Find in Reference" largely broken in 2.0b7 @@ -2758,7 +3457,7 @@ X discern variable vs function with Find in Reference X if no selection, attempt to expand the selection for Find in Reference X add cmd-shift-O to "Open Examples" on OS X with no window open X go through vida examples to make sure extra imports are not being used -o do command line to run through all examples? +o do command line to run through all examples? X remove Quaqua X http://code.google.com/p/processing/issues/detail?id=1509 X remove separate launch of QT movie creator @@ -2822,7 +3521,7 @@ tool manager X from Casey X list in the PDE would be updated automatically by querying a web service X list on the website would be generated using the same web service -X All I would need to do is update web/contrib_generate/sources.conf +X All I would need to do is update web/contrib_generate/sources.conf X and the rest would happen automatically. X general cleanup of the visuals/layout X extra files still being left around during install @@ -2842,7 +3541,7 @@ X http://code.google.com/p/processing/issues/detail?id=1387 0215 pde (2.0b7) -X "expecting EOF, found 'import'" on previously working sketch +X "expecting EOF, found 'import'" on previously working sketch X http://code.google.com/p/processing/issues/detail?id=1376 X changing default imports to only cover those we have in the reference X also on the Android side as well @@ -2903,7 +3602,7 @@ X http://code.google.com/p/processing/issues/detail?id=1426 X double textMode() error message with P3D: X textMode(SCREEN) has been removed from Processing 2.0. X textMode(256) is not supported by this renderer. -X errors that cannot be placed (i.e. missing brace) +X errors that cannot be placed (i.e. missing brace) X this makes things to jump to the last tab X also happens with stray characters sometimes... X casey: accidentally typing a letter at the top of the tab @@ -2969,7 +3668,7 @@ X (stubbing things in for artwork update later) 0212 pde (2.0b4) -M implement find & replace over multiple tabs +M implement find & replace over multiple tabs M http://code.google.com/p/processing/issues/detail?id=25 M added to the projects list X change all build.xml files to use Java 6 as both source and target @@ -3038,7 +3737,7 @@ X make Mode menu into a radio button, so it cannot be de-selected X http://code.google.com/p/processing/issues/detail?id=1227 X no response with registerMethod keyEvent when key pressed or released X http://code.google.com/p/processing/issues/detail?id=1225 -o running at size(7000, 4000) followed by size(100, 100) +o running at size(7000, 4000) followed by size(100, 100) X http://code.google.com/p/processing/issues/detail?id=1213 X won't fix, too hairy and messy X clean up handling of untitled sketches @@ -3059,7 +3758,7 @@ X no changes 0209 pde (2.0b1) X require Mac OS X 10.6.8 as the minimum -X replace/find need to dim out the buttons +X replace/find need to dim out the buttons X i.e. hitting 'replace' multiple times causes weirdness X and replace/replace+find buttons shouldn't be active until after a find X http://code.google.com/p/processing/issues/detail?id=1056 @@ -3081,11 +3780,11 @@ X problem was 'extends' after 'implements' X "Open" dialog on Linux wasn't showing directories X http://code.google.com/p/processing/issues/detail?id=1151 X switch Platform to just use java.awt.Desktop classes -X for Java 1.6, replace com.apple.eio.FileManager.openURL(url); +X for Java 1.6, replace com.apple.eio.FileManager.openURL(url); X with java.awt.Desktop.browse() and java.awt.Desktop.open() X causes a deprecation warning whenever building on osx o instead of "show sketch folder" method, use: -The com.apple.eio.FileManager now has two new desktop interaction methods, revealInFinder(File) and moveToTrash(File). You can use revealInFinder() to open a Finder window in the parent directory of of a file and select it. You can use moveToTrash() to move a file to the most appropriate Trash directory for the volume that contains that file. +The com.apple.eio.FileManager now has two new desktop interaction methods, revealInFinder(File) and moveToTrash(File). You can use revealInFinder() to open a Finder window in the parent directory of of a file and select it. You can use moveToTrash() to move a file to the most appropriate Trash directory for the volume that contains that file. X added 64-bit RXTX for Mac OS X X http://blog.iharder.net/2009/08/18/rxtx-java-6-and-librxtxserial-jnilib-on-intel-mac-os-x/ X bufferUntil() with values above 127 do not work properly @@ -3115,18 +3814,18 @@ o shift-tab with no selection should go back two spaces cleaning o switching into present mode in info.plist o LSUIPresentationMode -o 4 +o 4 o errors with serial and libraries Exception in thread "Thread-2" java.lang.NoClassDefFoundError: processing/core/PApplet - at processing.serial.Serial.(Serial.java:156) + at processing.serial.Serial.(Serial.java:156) generally, that error means that something is missing from the CLASSPATH. the NoClassDefError gives erroneous feedback about *what* class is actually missing, as of java 1.3+ (yay!) so perhaps conflicting versions of a library in the sketchbook (solve this by setting to an empty sketchbook temporarily) or files might be installed in the CLASSPATH variable or something conflicting in -/System/Library/Extensions. +/System/Library/Extensions. F add processing.js export tool from florian F http://github.com/fjenett/processingjstool/ F http://github.com/fjenett/processingjstool/zipball/v0.0.6 @@ -3182,7 +3881,7 @@ o this would take care of nasty macosx 1.4 vs 1.5 issues o /System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Commands/java o /System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Commands/java o /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java -o canonical path for +o canonical path for o /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK o will return 1.5.0 (or maybe 1.6 for others?) X nope, just using a local JRE/JDK from now on @@ -3207,7 +3906,7 @@ X http://code.google.com/p/processing/issues/detail?id=72 X doesn't seem to be a problem on modern machines X in rebuild sketch menu - disable subfolders working as libraries X if a sketch, don't allow subfolders -o or maybe just that libraries must be in the root? +o or maybe just that libraries must be in the root? o nah, cuz that would mean can't make subfolder called "libraries" X no longer possible since separate libraries folder is in use X is the 'hide' option for code dumb? i've never used it @@ -3228,8 +3927,8 @@ X http://code.google.com/p/processing/issues/detail?id=32 X http://code.google.com/p/processing/issues/detail?id=958 X decided not to: simple workaround available o setting sketchbook to a folder on a network mounted drive -o does this work? test on both on mac and pc.. -o or if not, should recommend people against it +o does this work? test on both on mac and pc.. +o or if not, should recommend people against it o (i.e. folders disappearing if net has trouble) X http://code.google.com/p/processing/issues/detail?id=33 X decided wontfix, nobody has ever followed up @@ -3273,7 +3972,7 @@ o http://dev.processing.org/bugs/show_bug.cgi?id=562 X Monaco can no longer be disabled X modes have their own methods for digging through sketch & libraries folders o therefore it need only check the sketch.txt file to see if it's ok -o (between android and java) +o (between android and java) o but more importantly, if it's something totally different (.py) then o that'll be ok, and work fine o need another extension for the p5 py stuff @@ -3374,7 +4073,7 @@ o don't re-open new window on top of another X changing how this is handled X detect mode and library example folders for recent menu o with the same sketch open, a handleOpen() might open a second on top of it -X should be fixed up +X should be fixed up applets o tool to run in appletviewer? sun.applet.Main is appletviewer @@ -3385,11 +4084,11 @@ o courseware o export sketch as applet when uploading o save sketch zip files o have a means to load them from "teacher" version of p5 -o figure out how to use the +o figure out how to use the o items from the 'code' folder not included with applet export o add tool to "Add custom html to sketch" -o that copies applet.html, -o opens sketch folder, +o that copies applet.html, +o opens sketch folder, o and gives info about what to do next (how to edit) o http://dev.processing.org/bugs/show_bug.cgi?id=143 @@ -3428,7 +4127,7 @@ X not seen for a while, closed o multiple entries in file menu o http://dev.processing.org/bugs/show_bug.cgi?id=1260 X should be fixed, not seen -o "src/processing/xxxx/Xxxxxxxx.java uses unchecked or unsafe operations." +o "src/processing/xxxx/Xxxxxxxx.java uses unchecked or unsafe operations." X http://code.google.com/p/processing/issues/detail?id=101 o use pack200/unpack200 to make p5 download smaller X http://code.google.com/p/processing/issues/detail?id=95 @@ -3467,7 +4166,7 @@ X export and export to application fail with umlauts in folder name X http://dev.processing.org/bugs/show_bug.cgi?id=252 X fixed in 0140, but no confirmation o stop button needs to update itself and work properly -o also editor buttons to light up and clear properly +o also editor buttons to light up and clear properly X http://dev.processing.org/bugs/show_bug.cgi?id=396 o need someone to go out and test all scenarios of this X this particular version was fixed (though broken again later) @@ -3510,8 +4209,8 @@ X marked cantfix o using a processing keyword as a variable name gives unhelpful error message X http://dev.processing.org/bugs/show_bug.cgi?id=213 X fixed issue specific to handleDisplay -o not enough args for triangle (or args in general) -o throws out bizarre message +o not enough args for triangle (or args in general) +o throws out bizarre message o http://dev.processing.org/bugs/show_bug.cgi?id=17 X fixed up later X expecting RPAREN messages are ugly @@ -3519,7 +4218,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=15 o unchecking 'use external editor' sketch should not set modified o dangerous if a version that hasn't been re-loaded has possibility o to overwrite. i.e. make a change and save in external editor, -o don't actually +o don't actually o comments shown as code / code shown as comments o http://code.google.com/p/processing/issues/detail?id=164 X merged into new editor issue @@ -3527,7 +4226,7 @@ o program sometimes goes gray because it thinks everything is in a comment o http://code.google.com/p/processing/issues/detail?id=564 X merged into new editor issue o failed export still copies random files -o Failed compile on Export or Export to Application +o Failed compile on Export or Export to Application o still creates folder and leaves mess behind X http://dev.processing.org/bugs/show_bug.cgi?id=1050 X opted not to fix (rationale in the report) @@ -3581,8 +4280,8 @@ o http://dev.processing.org/bugs/show_bug.cgi?id=114 o when drawing large video, the two triangles for the rect are out of sync o only shows up in P3D o pause and frameRate aren't working -o framerate does set the frequency which movieEvent will be called, -o but it is not setting the "available" field corrrectly. +o framerate does set the frequency which movieEvent will be called, +o but it is not setting the "available" field corrrectly. o in fact, speed() should be used to set the rate, not frameRate o sketch .zip file in casey's email message X http://dev.processing.org/bugs/show_bug.cgi?id=370 @@ -3594,11 +4293,11 @@ o include a separate video class to handle just playback o video playback can be much faster if not messing with pixels o could instead use texsubimage in opengl, etc o only supports tint() (to set alpha or color) and drawing? just drawing? -o stop button won't kill a video sketch (bug 150 example does this) +o stop button won't kill a video sketch (bug 150 example does this) X although ESC seems to work? (not sure, didn't test) o or audio won't stop even after hitting stop o when an exception comes through during cameraEvent, not printed -o need to show an actual stack trace (InvocationTargetEx) +o need to show an actual stack trace (InvocationTargetEx) o because otherwise it's impossible to debug this stuff o video library not working on export to web o http://dev.processing.org/bugs/show_bug.cgi?id=1421 @@ -3613,7 +4312,7 @@ o fix "reply" garbage added o fix "back to bug# 778" o remove patch designation o make severity a radio button (people aren't using it) -o change to just ( ) Problem ( ) Feature Request (remove 'severity') +o change to just ( ) Problem ( ) Feature Request (remove 'severity') o remove 'platform' dropdown o specify some versions? also add back a "target version" for fix? o explanation of P1 through P5 @@ -3639,7 +4338,7 @@ o layout problems with attachments page o http://dev.processing.org/bugs/show_bug.cgi?id=254 o layout problems with logout page o http://dev.processing.org/bugs/show_bug.cgi?id=255 -o bug duplicate text field doesn't retain focus +o bug duplicate text field doesn't retain focus o http://dev.processing.org/bugs/show_bug.cgi?id=256 o finish putting all the bugs into bugzilla o add a notation to the bugs site re: reading the faq and searching first @@ -3750,7 +4449,7 @@ X and fixed again for non-greedy regex X make note of when library is not available (serial) with error msg X i.e. if running in 64-bit mode on OS X, can't do serial X update to Java 6u29 for Linux and Windows (OS X now updated) -X don't show library conflict warning until someone tries to build +X don't show library conflict warning until someone tries to build X with code that actually calls on one of those packages X too many people seem to think this is an error X work on code to quit if multiple instances are running @@ -3869,7 +4568,7 @@ o add deployJava.js to local sketch folder (causes internet requirement) X http://code.google.com/p/processing/issues/detail?id=650 X http://www.java.com/js/deployJava.js X bad idea, since it adds 17k to every download -X make examples window respond to ESC +X make examples window respond to ESC X and double-click events to expand/collapse nodes X examples window placed off-screen when PDE window is maximized X http://code.google.com/p/processing/issues/detail?id=669 @@ -3879,7 +4578,7 @@ X New/Rename Tab commands inhibited when Console/Message Area is hidden X http://code.google.com/p/processing/issues/detail?id=745 X make sketch.properties usable elsewhere by loading/reloading X http://code.google.com/p/processing/issues/detail?id=722 -X Export to Application reports "Could not copy source file:" +X Export to Application reports "Could not copy source file:" X http://code.google.com/p/processing/issues/detail?id=638 X automatically insert the 'import processing.opengl' when P3D used X add support for automatically including OpenGL when asking for P3D @@ -3889,8 +4588,8 @@ X http://code.google.com/p/processing/issues/detail?id=747 cleanup X how is autoformat doing? good now -X catch 1.5 code in libraries - is this still an issue for 1.6 on 1.5? -X Exception in thread "main" java.lang.UnsupportedClassVersionError: quicktime/QTException (Unsupported major.minor version 49.0) +X catch 1.5 code in libraries - is this still an issue for 1.6 on 1.5? +X Exception in thread "main" java.lang.UnsupportedClassVersionError: quicktime/QTException (Unsupported major.minor version 49.0) o javascript and liveconnect to preload applets o http://code.google.com/p/processing/issues/detail?id=66 X let's not bother @@ -3901,7 +4600,7 @@ o package cc.arduino.* X no thanks, they've abandoned it o add page numbers and file name to printing in p5 o also add something to control the font & font size -X -> jer: "can we put fax support in there too?" +X -> jer: "can we put fax support in there too?" o prevent people from setting the font size too small in the editor o how do we figure out what "too small" is? X -> everyone thinks this is funny @@ -3953,7 +4652,7 @@ X http://code.google.com/p/processing/issues/detail?id=627 X file-save stops running sketch X http://dev.processing.org/bugs/show_bug.cgi?id=810 X http://code.google.com/p/processing/issues/detail?id=100 -X fix bug in loadfile2 example +X fix bug in loadfile2 example X http://code.google.com/p/processing/issues/detail?id=522 o when running with external editor, hide the editor text area o http://dev.processing.org/bugs/show_bug.cgi?id=20 @@ -3974,7 +4673,7 @@ X run the javadoc for 1.5 X remove opengl2 for 1.5 and examples for the final 1.5 X need to get a new stable release out there, the docs/ref are out of sync -from peter n lewis +from peter n lewis X Use Selection For Find X http://code.google.com/p/processing/issues/detail?id=571 X double-clicking whitespace selects adjacent chars @@ -4121,7 +4820,7 @@ o can make full screen work via Info.plist key o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1135921427;start=7#7 X added to export defaults in a much earlier version X when running externally, set window frame title to the sketch name -X is this only a problem on macosx? +X is this only a problem on macosx? console, preferences X removed build.path from preferences.txt @@ -4269,7 +4968,7 @@ X don't keep repeating them 0190 (pre) X be more specific about linux/sun/java error messages X allow 'oracle' in java version name string -X the open button on the toolbar is goofed up +X the open button on the toolbar is goofed up X http://code.google.com/p/processing/issues/detail?id=323 X changed how "Save As" works, now copies everything in the folder X but ignores applet, application.*, screen-* files/folders @@ -4279,9 +4978,9 @@ X also fixed unicode entities earlier X add warning message when not using a version of sun java w/ p5 on linux -X Ctrl-Z will undo, but not scroll to where the undo happens. +X Ctrl-Z will undo, but not scroll to where the undo happens. X is this now somehow fixed? (or only on os x?) -X so user thinks nothing is happening and overundo. +X so user thinks nothing is happening and overundo. X http://dev.processing.org/bugs/show_bug.cgi?id=35 X http://code.google.com/p/processing/issues/detail?id=15 @@ -4299,7 +4998,7 @@ X update the about screens (about.jpg and about.bmp) 0187 pde (pre) X don't require an editor window to be open at all times X The com.apple.eawt.Application now has a setDefaultMenuBar(JMenuBar) method -X that sets a default menu bar when no other Frames are open. +X that sets a default menu bar when no other Frames are open. X could check for availability of method X and if it's there, don't require people to quit X Prevent horizontal scroll offset from disappearing @@ -4309,7 +5008,7 @@ o http://dev.processing.org/bugs/show_bug.cgi?id=23 X Fix NullPointerException when making a new sketch on non-English systems X http://code.google.com/p/processing/issues/detail?id=283 X show warning message on linux if sun java is not in use -X there isn't a perfect way to detect whether sun java is in use, +X there isn't a perfect way to detect whether sun java is in use, X so please report false positives (or negatives, for that matter) X bad strlen() problem in windows launcher.cpp X http://code.google.com/p/processing/issues/detail?id=303 @@ -4330,7 +5029,7 @@ X thanks to Larry Kyrala X http://dev.processing.org/bugs/show_bug.cgi?id=1549 X fix for PDF library to support createFont() on Linux X http://dev.processing.org/bugs/show_bug.cgi?id=1566 -X thanks to Matthias Breuer +X thanks to Matthias Breuer X add option to change the formatting for untitled sketch naming X http://dev.processing.org/bugs/show_bug.cgi?id=1091 X Can't input full-width space when Japanese IME is on. @@ -4354,7 +5053,7 @@ X http://code.google.com/p/processing/issues/detail?id=245 0184 pde (pre) X other libraries that use opengl weren't using the jnlp launcher -X fix OpenGL detection in sketches so that proper version of +X fix OpenGL detection in sketches so that proper version of X export template is used X http://dev.processing.org/bugs/show_bug.cgi?id=1530 X single-line html comments not handled properly on export @@ -4457,11 +5156,11 @@ J casting problems in the parser J straighten out int() -> toInt() conversions J float u = float(x)/width; works. J float u = (float(x)/width); doesn't work: "unexpected token: float". -J float u = (x/float(width)); works! +J float u = (x/float(width)); works! J http://dev.processing.org/bugs/show_bug.cgi?id=4 J return (int(5.5)) causes an error J preprocessor error if last line of code is a comment with no CR after it, -J an OutOfMemoryError wants to happen, +J an OutOfMemoryError wants to happen, J but right now there's a hack to add a CR in PdePreprocessor J http://dev.processing.org/bugs/show_bug.cgi?id=5 J preproc can't handle labels to break/continue nested loops @@ -4547,7 +5246,7 @@ X fix this for windows and linux X PApplet.main() overwritten X http://dev.processing.org/bugs/show_bug.cgi?id=1446 o need to do a better job of error handling inside main() -X applets now use the deployjava.js file +X applets now use the deployjava.js file X not opengl, but the others do X NullPointerException in JOGLAppletLanucher with Java 6 Update 18 on Windows X switching to more efficient JNLP export @@ -4561,7 +5260,7 @@ X processing 0142 japanese input problem X http://dev.processing.org/bugs/show_bug.cgi?id=854 X update JNA to version 3.2.4 to support Windows 7 64-bit X http://dev.processing.org/bugs/show_bug.cgi?id=1424 -X fix LITERAL_class in PDE code (help from Christian Thiemann) +X fix LITERAL_class in PDE code (help from Christian Thiemann) X http://dev.processing.org/bugs/show_bug.cgi?id=1466 X replace applet.html and applet-opengl.html X http://dev.processing.org/bugs/show_bug.cgi?id=1057 @@ -4729,7 +5428,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=1260 X try adding a space to the name of the help menu for beachball problems X this works, might be useful to make the switch (done) X remove isManagingFocus problem inside JEditTextArea -X IDE crashed when changing color scheme on windows +X IDE crashed when changing color scheme on windows X http://dev.processing.org/bugs/show_bug.cgi?id=1237 X space in front of linux shell script prevents it from running X http://dev.processing.org/bugs/show_bug.cgi?id=1250 @@ -4748,7 +5447,7 @@ X update to java 6u14 on linux 0165 pde (1.0.3) -X no changes in this release +X no changes in this release 0164 pde (1.0.2) @@ -4791,11 +5490,11 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=986 0163 pde (1.0.1) X ArrayIndexOutOfBoundsException with File > New (Processing 1.0) -X maybe a /tmp permissions problem? +X maybe a /tmp permissions problem? X are we not checking errors properly on this route? X http://dev.processing.org/bugs/show_bug.cgi?id=1067 X need to look into why this didn't give a better error message -X "[JavaAppLauncher Error] CallStaticVoidMethod() threw an exception" +X "[JavaAppLauncher Error] CallStaticVoidMethod() threw an exception" X on startup with OS X X http://dev.processing.org/bugs/show_bug.cgi?id=1063 X http://dev.processing.org/bugs/show_bug.cgi?id=1078 @@ -4810,13 +5509,13 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=1073 X "space-import-space-quote-semicolon" Causes Error in String or Comment X http://dev.processing.org/bugs/show_bug.cgi?id=1064 X the changes page doesn't have a toc entry for the 1.0 release notes -X add minim to the changes page +X add minim to the changes page 0162 pde (1.0) X update revisions.html X write revisions.txt -X in 0149, removed /System/Library/Java +X in 0149, removed /System/Library/Java X http://dev.processing.org/bugs/show_bug.cgi?id=1045 X do we need to shore up server setup for 1.0 release pounding? o what's the deal with disk space? @@ -4944,7 +5643,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=886 X rename GettingStarted_Shape example invalid -o launch4j "An error occurred while starting the application" +o launch4j "An error occurred while starting the application" o http://dev.processing.org/bugs/show_bug.cgi?id=986 o tabs menu not working on osx ppc (can't confirm) o http://dev.processing.org/bugs/show_bug.cgi?id=993 @@ -4972,9 +5671,9 @@ X bug report: X create a new sketch, write something in it X create a new tab, name it "something.java", write something into it X rename main tab (sketch) to "something" (without ".java") -X the contents in the files are not the same, but the main-tab is -X showing the contents of the .java tab, so if you press save -X you will overwrite your original code from the main-tab. +X the contents in the files are not the same, but the main-tab is +X showing the contents of the .java tab, so if you press save +X you will overwrite your original code from the main-tab. X com.sun.jdi.AbsentInformationException when running a sketch X http://dev.processing.org/bugs/show_bug.cgi?id=971 @@ -4987,7 +5686,7 @@ X include javac? would this be a good solution for linux? X http://dev.processing.org/bugs/show_bug.cgi?id=8 X an empty .java tab will throw an error X http://dev.processing.org/bugs/show_bug.cgi?id=10 -X warn about writing non-1.1 code. +X warn about writing non-1.1 code. X http://dev.processing.org/bugs/show_bug.cgi?id=11 X java.lang.NoClassDefFoundError: quicktime/std/StdQTException X people not installing qt? no QTJAVA set? @@ -4995,7 +5694,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=669 o simulate this by removing qtjava.zip, then make a handler for it o which will open the reference for it X use the registry key, and warn the user when it's not there -X mouse wheel broken in the text editor? (windows jdk 1.5?) +X mouse wheel broken in the text editor? (windows jdk 1.5?) X http://dev.processing.org/bugs/show_bug.cgi?id=24 @@ -5086,7 +5785,7 @@ o sketch must be saved to use a constructor X http://dev.processing.org/bugs/show_bug.cgi?id=929 X reference bug, example cannot have same name as an inner class -structural +structural X processing.candy has been removed X processing.xml is now part of core.jar, no need to import X user-contributed tools and libraries should only be placed in the sketchbook @@ -5103,13 +5802,13 @@ X createInput() (nee openStream), createInputRaw(), createOutput() cleanup o how to grab the java2d object from PGraphics2D -o example for using mediatracker to load images -o simple example for threaded image loading "load several" +o example for using mediatracker to load images +o simple example for threaded image loading "load several" o (rather than blocking on each) o maybe add a loadImages(String files[]) function? o use a MediaTracker that's shared, so that while an image is still o loading, other calls to loadImage might be able to add things to the -o queue. or maybe beginImage() and endImage()? or a mode that lets +o queue. or maybe beginImage() and endImage()? or a mode that lets o you wait for the images to download (size is zero until they're ready) o MediaTracker blocking is prolly making jar download really slow o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1089914280 @@ -5225,13 +5924,13 @@ o 3 column input file o regexp to find, to replace, human readable description o (void\s+)loop(\s+{) -> $1draw$2 (maintain all whitespace stuff) o "The loop() method is now called draw() as of beta" -o "angleMode no longer exists, use radians() around your angles" +o "angleMode no longer exists, use radians() around your angles" o (comment out the line) X this would only fix the minor stuff, not the important stuff X it also has a lot of potential problems and corner cases X just not worth the effort X tools api -X need to support the basic set of functions that are expected +X need to support the basic set of functions that are expected X to be used, otherwise it's gonna be total hell when we make a real api X getEditor() X get/setSelStart/End @@ -5257,7 +5956,7 @@ X no, bad idea.. don't want a zillion submenus on things 0146 pde -X fix problem with comment/uncomment and indent/outdent +X fix problem with comment/uncomment and indent/outdent X when no selection, and on the first pos of the line X on comment/uncomment, need to check if *all* lines are commented X otherwise should be comment (never uncomment unless all selected) @@ -5269,11 +5968,11 @@ X also highlighting the correct line X Exceptions not being reported properly to the PDE X lines with errors not highlighting X http://dev.processing.org/bugs/show_bug.cgi?id=877 -X was ok in 0144, but 0145 things broke +X was ok in 0144, but 0145 things broke X probably b/c not catching ex inside the run() method X getMessage() not sufficient for exceptions coming through X get actual message text, plus the exception itself -X now using actual sketch name (instead of temp name) +X now using actual sketch name (instead of temp name) X this should be safe since launching an external vm to run X make the p5 icon show up for the window X when launching a new sketch @@ -5289,7 +5988,7 @@ X http://processing.org/bugs/show_bug.cgi?id=42 X exceptions in draw() apps aren't caught X the program resize(200, 200); just does nothing (doesn't complain) X http://dev.processing.org/bugs/show_bug.cgi?id=81 -X exception in setup() on external app doesn't kill run button +X exception in setup() on external app doesn't kill run button X also doesn't kill external vm X http://dev.processing.org/bugs/show_bug.cgi?id=79 X fixed in the 0140s @@ -5347,7 +6046,7 @@ o this is particularly bad with threaded applications 0143 pde X fixed build problems with macosx and linux, thanks to reports -o need to compare with localized version of javac strings +o need to compare with localized version of javac strings X http://dev.processing.org/bugs/show_bug.cgi?id=828 X just moving to ecj instead of javac X preproc code showing through since it's on line 0: @@ -5385,7 +6084,7 @@ o 2) its mod date is earlier than when p5 0125 was installed o point the user to Tools -> Reload sketch with local encoding o then re-save the file to update the mod date o ...or, when first running p5 0125, offer to update sketches -o this is a bad idea--since it's probably +o this is a bad idea--since it's probably X need to set a default charset for use in files (utf8) X add option to change charset or specify as part of loading X need to specify the default encoding @@ -5407,12 +6106,12 @@ X can't seem to verify this X occasional division by zero on windows X http://dev.processing.org/bugs/show_bug.cgi?id=777 X should be fixed, but need to verify once a release candidate is ready -X two fixes for readBytesUntil() and bufferUntil() +X two fixes for readBytesUntil() and bufferUntil() X also not calling serialEvent() X http://dev.processing.org/bugs/show_bug.cgi?id=96 X fix goof with console preference in preferences.txt X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1213042400 -X need to add usequartz when running externally? +X need to add usequartz when running externally? X no, tested and it seems to be working cleaning @@ -5466,14 +6165,14 @@ X xml.getIntAttribute() returns a float X http://dev.processing.org/bugs/show_bug.cgi?id=790 X include memory settings with exported applications on macosx X http://dev.processing.org/bugs/show_bug.cgi?id=803 -X error highlighting broken +X error highlighting broken X http://dev.processing.org/bugs/show_bug.cgi?id=795 0138 pde X importing a library results in "expecting EOF, found ..." error X http://dev.processing.org/bugs/show_bug.cgi?id=788 -X remove console variable from preferences.txt +X remove console variable from preferences.txt X run only works with primary window in 0136, 0137 X http://dev.processing.org/bugs/show_bug.cgi?id=784 X throwing a stackoverflowexception because the console is broken @@ -5486,7 +6185,7 @@ X remove debug messages from export 0137 pde -X move to multiple jars whenever +X move to multiple jars whenever X 1) a lib is in use, 2) code folder, 3) multiple files X remove oro.jar dependency (not needed with PApplet.match) X this is kind of messy and requires a bit of testing to ensure proper @@ -5498,7 +6197,7 @@ X applet export fails with opengl/code folder X http://dev.processing.org/bugs/show_bug.cgi?id=714 X synchronized (something) { } is horking up the preproc X http://dev.processing.org/bugs/show_bug.cgi?id=136 -o inside the preproc +o inside the preproc o change the arrays of default imports (now using 1.5+, so no 1.1,1.3,1.4) X don't bother, they're cumulative X improvements to the linux startup script @@ -5523,13 +6222,13 @@ X fixed in newer qtjava o http://dev.processing.org/bugs/show_bug.cgi?id=496 X add to p5 app bundle X mention re: apple slowness -X -Dapple.awt.graphics.UseQuartz=true +X -Dapple.awt.graphics.UseQuartz=true X net library dies unceremoniously on "Connection Refused" X just need to catch another exception X http://dev.processing.org/bugs/show_bug.cgi?id=751 X ctrl-/ to comment block X eeepc support for environment: -X splitPane.setMinimumSize(new Dimension(600, 600)); +X splitPane.setMinimumSize(new Dimension(600, 600)); X change to: splitPane.setMinimumSize(new Dimension(600, 400)); o prolly need to have a param for this guy X switch to nanoxml instead of nanoxml-lite (29k vs. 5k) @@ -5537,19 +6236,19 @@ X check against ods X http://dev.processing.org/bugs/show_bug.cgi?id=757 X space after OPENGL param breaks export X http://dev.processing.org/bugs/show_bug.cgi?id=769 -X svg demos are broken +X svg demos are broken X because of weird ENTITY setup X because of weird (default?) filling problem X remove support for random .class files in code and library folders X need to put everything in jar files X opengl currently broken in svn (probably the native libs not included?) -X mistakes wrt 'library.path' +X mistakes wrt 'library.path' X also, don't add /library/ for each lib to the classpath X remove unused libraries from default run path X note that this will hose svg b/c xml not available X so when this change is made, the lib depends needs to be implemented too -X changing to java 1.5 +X changing to java 1.5 o switch to java 1.4.2_16 on linux and windows (now that osx is there?) X change to 1.5+ (instead of 1.4*) in Info.plist for Processing.app X updated linux to java 1.5.0_15 @@ -5589,7 +6288,7 @@ X change software to point at correct reference locations 0135 pde -o opening a file from right-click in osx +o opening a file from right-click in osx o opens the new thing directly behind an untitled document X improve how fonts are parsed from the preferences file X this was causing strange errors as prefs files became corrupted @@ -5614,14 +6313,14 @@ o "reload sketchbook" option o "show sketchbook folder" X start removing pre-1.4 support X multiple windows -o what happens when p5 is launched without all its pieces? +o what happens when p5 is launched without all its pieces? o both on windows and mac... is there a way put up useful message o if everything moved into the .app file, how do you add applet.html? o can we use useragent to determine whether java 1.4 is in use? o for mac, could see if it's an old safari (1.3) or firefox (also 1.3) o for windows, the classid will take care of it all (firefox too?) o for linux, everyone's using 1.4/1.5 anyway -X rewrite section on versions of java +X rewrite section on versions of java X we're dropping support for anything before 1.4 X and don't recommend anything before 1.4.2 X we'll support 1.5 a little more now, but only libraries, not syntax @@ -5705,7 +6404,7 @@ X when new/open from menu, creates a new window o don't bug the user about new release of p5 when they have it o add prefs option for "latest version run" o something also to track--people going to older releases -X keeping this behavior, it's also the only way to know you're +X keeping this behavior, it's also the only way to know you're X running the wrong version when you accidentally open an oldie X createFont() needs to run 1.3+, and not in applets X where is the bug reference for this.. and can it be fixed? @@ -5795,7 +6494,7 @@ X move examples folder to top-level menu X move open menu to its own X BGraphics, BImage, void loop() -> give an error saying it's old code X better yet, only do this when "not found" errors come up -X need to fix changes.html because it lists out of date alpha->beta changes +X need to fix changes.html because it lists out of date alpha->beta changes X added getChild(name/path), getChildren(name/path) to xml library o add notes about these to the reference o needs a better example that includes subitems @@ -5893,7 +6592,7 @@ X add documentation X add() or addFrame()? X find/replace - replace should do auto find next(?) X or have a replace & find button -X placing "replace" next to "find" ... (hitting "replace all" by accident) +X placing "replace" next to "find" ... (hitting "replace all" by accident) X have a button "replace & find next" X http://dev.processing.org/bugs/show_bug.cgi?id=68 X only rebuild sketchbook on "save as" or "rename" of sketch @@ -5918,7 +6617,7 @@ X do a trim() on the selection for find in reference X reorganize find in reference commands X add setDTR() method from tom hulbert X moviemaker is broken -X updatePixels reference was cut off +X updatePixels reference was cut off X double-check this after rebuild of reference X examples X animated sprite example should use tabs @@ -5949,12 +6648,12 @@ X slight improvements to some preproc/compiler error messages X http://dev.processing.org/bugs/show_bug.cgi?id=12 X http://dev.processing.org/bugs/show_bug.cgi?id=13 X http://dev.processing.org/bugs/show_bug.cgi?id=15 -X deal with strange problem with KeyListener and {} on same line +X deal with strange problem with KeyListener and {} on same line X http://dev.processing.org/bugs/show_bug.cgi?id=484 -X copy custom applet.html file on "Save As" +X copy custom applet.html file on "Save As" X http://dev.processing.org/bugs/show_bug.cgi?id=485 o preferences file gone corrupt (on osx only?) -o changing font size, +o changing font size, o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1160057791 X http://dev.processing.org/bugs/show_bug.cgi?id=406 o temporarily added log4j and jalopy (for the autoformatter) @@ -6016,7 +6715,7 @@ X finish draw(x, y, c, d) 0121 pde -X fix button fatness on osx +X fix button fatness on osx X quaqua already takes care of this for us X implement page setup and print X pretty printing of code in project @@ -6075,7 +6774,7 @@ X add PGraphicsOpenGL change to revisions.txt and the changes faq 0116 pde -o including function outlines in the code? +o including function outlines in the code? o i.e. make setup() and draw() for people? seems silly.. not much to do o when importing a library, insert 'captureEvent'? o again, seems to fraught with potential problems @@ -6111,13 +6810,13 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=233 o external apps should inherit memory settings from p5 itself X too confusing to set the memory in two places X or perhaps, have a setting in the ide for it -o and allow a checkbox for "always run externally" +o and allow a checkbox for "always run externally" X that way people don't have to adjust the memory settings for p5 itself X perhaps the memory setting should be enabled/disabled X that way if it's enabled, will always run externally o menu weirdness (benelek) o when you've got a menu open, move a cursor over the text area -o and back over the menu, the text-area cursor type remains. +o and back over the menu, the text-area cursor type remains. X mark this as wontfix, since it's just a java bug X http://dev.processing.org/bugs/show_bug.cgi?id=30 X remove the second movie from the movie playback example @@ -6186,7 +6885,7 @@ X add more information about setting the memory X move memory setting to troubleshooting page on bugs db X the source code to the libs are included X this makes them easy to modify (in another app) -X or you can remove the package statements and embed them +X or you can remove the package statements and embed them X serial is a little trickier since you'd have to put stuff in code/ X windows, may need to install new version of video drivers X add to opengl doc/faq @@ -6222,7 +6921,7 @@ X move troubleshooting page to the reference faq / platforms X add notes about running processing on various platforms -o directions for rebuilding jikes, etc (where is this?) +o directions for rebuilding jikes, etc (where is this?) o and then link to posts on the discourse site about how to do it faq / export @@ -6278,7 +6977,7 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=315 0111 pde X switch back to rev b3 of jogl so that applets will work -X fix color picker: +X fix color picker: X http://dev.processing.org/bugs/show_bug.cgi?id=308 X also add esc/ctrl-w for closing the picker X update information on mactels in the faq, also java 1.6 @@ -6312,12 +7011,12 @@ X adding dxf library to distribution X fix bug with drag & drop of files to sketch on macosx X need space between bullet points in faq css X also need the absolute url stuff to work -X add discourse formatter tool +X add discourse formatter tool 0107 pde X fix yet another save bug, context menu paste/cut not setting modified -X undoing to the code's original state won't unset it as "modified" +X undoing to the code's original state won't unset it as "modified" X http://dev.processing.org/bugs/show_bug.cgi?id=248 @@ -6334,7 +7033,7 @@ X removed "yep yep yep" when using "Create Font" X p5 not saving changes on quit, even if you say 'yes' X http://dev.processing.org/bugs/show_bug.cgi?id=276 _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1139519266 -X update osx for intel binary (if necessary) +X update osx for intel binary (if necessary) X if running on 10.4, univerals jikes installed in /usr/bin/jikes X updated the jikes included with p5 to be the universal version X add notes to the faq about status @@ -6391,7 +7090,7 @@ X make editor save button highlight on ctrl-s X same goes for the other editor buttons X http://dev.processing.org/bugs/show_bug.cgi?id=242 X deal with "could not delete stderr.txt" messages -X probably screwed up the temp folder stuff +X probably screwed up the temp folder stuff X build folder is randomized, being recreated on each build X mark temp build folder for deletion on exit X properly remove console files on exit @@ -6402,9 +7101,9 @@ X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action tab handling X indent/outdent with curly braces -X tab to just indent lines properly, +X tab to just indent lines properly, X rather than having it convert to spaces -X need a smarter handler (rather than the editor listener) +X need a smarter handler (rather than the editor listener) X could look at previous line for its indent X and when hitting } do a proper outdent (if only spaces before it) X http://dev.processing.org/bugs/show_bug.cgi?id=22 @@ -6512,7 +7211,7 @@ X console text selection immediately de-selects X suspect console is updated every 250 ms even when the app isn't running X simplest to just not update the console if nothing is waiting in buffer X http://dev.processing.org/bugs/show_bug.cgi?id=180 -X problem with using qtjava is probably the quotes.. +X problem with using qtjava is probably the quotes.. X remove them because they're matching quotes elsewhere X drag & drop implementation to add files to sketch X http://dev.processing.org/bugs/show_bug.cgi?id=21 @@ -6535,7 +7234,7 @@ X need to figure out threading etc X problem with it launching a new thread for every single update! X http://processing.org/bugs/show_bug.cgi?id=19 X make a note that video doesn't currently work in applets in the faq -X scanning sketchbook folder may be extremely slow +X scanning sketchbook folder may be extremely slow X when lots of frames saved out, takes forever to scan the folder X some dumb sorting code was responsible X and each file was being treated as a directory. oops. @@ -6548,9 +7247,9 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=48 o auto-run the javadoc in dist.sh o doctor a copy of the css file to use p5 defaults o and re-copy the css in after generating the doc each time -X timing fix introduce regression on linux +X timing fix introduce regression on linux X extra (NUL?) chars are added -X i.e. on first run, the ten blank lines each have a li'l box +X i.e. on first run, the ten blank lines each have a li'l box X http://dev.processing.org/bugs/show_bug.cgi?id=118 X faq: "my applet doesn't work on export"... where to check for errors X very common: cached version is being used @@ -6565,18 +7264,18 @@ fixed in previous releases X closing window w/o first hitting stop() causes freak out X opengl gives an OutOfMemoryError X java2d just goes into a lock -X could also be code that's in an infinite loop (i.e. text error) +X could also be code that's in an infinite loop (i.e. text error) X which then causes a full lock X something really bad happened with println() in this release X perhaps only without a code folder and/or running in java2d mode? -X this may also be what's hosing +X this may also be what's hosing X external apps don't stop at all when 'stop' is hit X worker thread is halting the app ala code folder bug -X could this be dealt with by using nio? +X could this be dealt with by using nio? X host environment will be running 1.4 so... o make note that changing screen config requires restart of processing o static { checkScreens(); } -o static void PApplet.checkScreens() { } +o static void PApplet.checkScreens() { } o to run explicitly later o this seems too complicated.. just make people restart o convert spaces to underscores and vice versa for sketch/tab names @@ -6585,7 +7284,7 @@ o only needs to be underscored when passed off to java o although then if people *want* underscores, there's gonna be trouble o http://dev.processing.org/bugs/show_bug.cgi?id=76 o if in full java mode -o if extends PApplet.. or rather, put PApplet cast into a +o if extends PApplet.. or rather, put PApplet cast into a o try/catch block.. if it doesn't work, try applet. if that o doesn't work, try using the class' main() to run it X not gonna do this, p5 is not a java editor @@ -6604,11 +7303,11 @@ X buglist.cgi X replace the platform column with the os column (uses icons for os) X sorting based on any of the headings gives an error X "102 bugs found. 102 bugs found." -X remove the severity column +X remove the severity column X it's normal or enhanced, and enhanced is already gray -X make os into: Mac OS, Windows, Linux, Other +X make os into: Mac OS, Windows, Linux, Other X while other categories might exist, it's too confusing for minimal benefit -o make things that are P5 into "enhancement" +o make things that are P5 into "enhancement" o unless a P6 can be added? or something called "enhancement"? X is there a way to list "all" bugs (especially sorted by priority?) X or at least the first 20 listed by priority? @@ -6638,7 +7337,7 @@ X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115787397;start=0 X wasn't using runner stop button color X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1116166897;start=0 -X fix up the video crap because nobody reads the faq +X fix up the video crap because nobody reads the faq X and no cameras means that the list comes back null X can't seem to find build dir on operating systems w/ non-ascii chars X or rather, when user accounts have non-ascii chars in the name @@ -6669,7 +7368,7 @@ X not seen for a long time o this may be fixed? o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1076358432;start=0 o package processing.app for PdeBase, PdeEditor.. -o if NullPointerEx on a line that includes a "pixels[" +o if NullPointerEx on a line that includes a "pixels[" o give an error message saying "you may need to call loadPixels" discuss with casey @@ -6689,7 +7388,7 @@ X we've attempted for less confusion over speed in some cases X get(), set() and red() et al are one such example X web colors with alpha: 0xffcc0080 or unhex("ffcc0080") `X the draw() method must exist, otherwise the sketch won't run -X i.e. can't just have mousePressed() +X i.e. can't just have mousePressed() o make a sketch that shows loading from the web o make another sketch that shows loading from a file X make notes about preproc @@ -6785,15 +7484,15 @@ o System.err was getting cut off before finishing o no transformations before background() is called o implementation specific, may cause trouble o must call depth() for 3D applications -o lights cannot be enabled/disabled throughout +o lights cannot be enabled/disabled throughout o lighting will be based on what's left at endFrame() X images should be a power of 2, or call modified() -X document the use of "die" +X document the use of "die" X can override the method to do your own handling X sketches no longer require a "data" folder X example that uses loop/noLoop, or redraw? X talk to creas about making html files for bugs, readme, revisions. -X or how they should relate to the 'faq'.. readme -> faq? +X or how they should relate to the 'faq'.. readme -> faq? X loadImage() mixed case problems @@ -6823,7 +7522,7 @@ X righthand max isn't being updated for that second line X or it's getting written over by the line below it X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1113932608 X include platform information when checking for updates -X send over the int as long hex number? +X send over the int as long hex number? X 64 bits hex is gonna be 16 digits.. much cleaner o when people are running 1.5, warn them? o if p5 is running 1.5, let them know to use the standard install @@ -6832,9 +7531,9 @@ X nah, this seems like overkill.. problems haven't been *that* bad (yet) X make sure that when running ext, using the local java X macosx 10.2 needs libiconv to run jikes X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114113204;start=0 -o either compile jikes not to use it: +o either compile jikes not to use it: o http://jikes.sourceforge.net/faq/dev-win32.shtml -o or maybe include an installer: +o or maybe include an installer: o http://www.bluem.net/downloads/libiconv_en/ o gnu page for libiconv o http://www.gnu.org/software/libiconv/ @@ -6873,15 +7572,15 @@ X wontstart wasn't properly linked X watch out for upper/lowercase changes X methods and functions always start lowercase, and have inner caps X faq - java 1.5 -X seems to run things more slowly.. +X seems to run things more slowly.. X if using p5 standard, will be running 1.4 X but if 1.5 installed, browser will probably use that X opengl only runs with 1.4 X opengl not tested for applets X to get to opengl functions, put this after size: X GL gl = ((PGraphicsGL)g).gl; -X and then can make opengl calls. this is not supported, -X and if things don't work, sorry. +X and then can make opengl calls. this is not supported, +X and if things don't work, sorry. X faq - known bugs X 1 pixel stroke weight in opengl (temporary) X make clear that P2D is not working if not clear enough @@ -6919,7 +7618,7 @@ X a bunch of stuff from revisions.txt on 84 and 82 o how to deal with bugs, since there are so many known... save as... bugs -X always make sure that the sketch folder still exists +X always make sure that the sketch folder still exists X otherwise editor gets into a weird state (v74) if a project folder is made (with save as), and then deleted while processing is still open, there is an error (of course). but @@ -6932,7 +7631,7 @@ saving a project over an already existing project does not get rid of the .pde files that arent overwritten. not sure if this is feature or bug, but it took me by surprise. it seemed to only overwrite .pde files with the same name, but everything else in that project folder -stays as is. +stays as is. X sketch renaming fixed X rename, change, was asking about the old sketch name @@ -6950,7 +7649,7 @@ File>Open some other file File>Open original file file is empty. the only way to make File>Save As actually save new files, as far as i -can tell, is to Save As once, make at least one change, then Save. +can tell, is to Save As once, make at least one change, then Save. X fix hide/unhide bug... just was dumb code create a new sketch @@ -6966,7 +7665,7 @@ where did "a_2" go ? 0083 pde X move everything to packages, and start auto-javadoc X how to get preproc to automatically prepend packages -o only build preproc from preproc/make.sh? +o only build preproc from preproc/make.sh? o and check in the preproc'd code to cvs? X need to add classes dir to cp for jikes make (on win and linux) X get both versions of size() properly detected on export @@ -7011,9 +7710,9 @@ o should loadPixels be grabPixels? (nope) saturday evening X update processing/build/howto.txt X add 'make' to list of things that should be installed -X update libraries/howto.txt +X update libraries/howto.txt o should we queue lib events until the end of loop? -X nope, libraries can handle that themselves, +X nope, libraries can handle that themselves, X and queue events by registering for draw or whatever they'd like X lib could call queueEvent with the args X then call them inside post() @@ -7061,7 +7760,7 @@ o fix for 78 since not sure when simon's new version is happening X requires because uses 3D.. oh well o "draw" is not highlighted as a keyword.. other keywords? o draw(), PGraphics(), NO_DEPTH_TEST, PMovie(), PMovie.repeat() -o PClient(), PClient.available(), PClient.read(), +o PClient(), PClient.available(), PClient.read(), o PServer(), PServer.dispose(), PServer.write(), attach(), length o round() is not colored @@ -7115,7 +7814,7 @@ X include "you need to install java" text on default export page X make compatible with jikes 1.22 X fix all warnings generated by the new jikes X update windows version of jikes.exe -X update macosx version of jikes +X update macosx version of jikes X get source and build on osx (or is it shipped by default?) X make sure that fink is not in the path when building X what are the args to configure a release version? @@ -7157,7 +7856,7 @@ X is PdeEditorHeader one pixel too tall X move the tabs over just slightly X resize box intrudes on the scroller for the console area X need to set grow boxes intruding to false -X 1.3 version (deprecated): +X 1.3 version (deprecated): X -Dcom.apple.mrj.application.growbox.intrudes=false X 1.4 version (much nicer): -Dapple.awt.showGrowBox=false X add mkdmg script to macosx build process @@ -7197,11 +7896,11 @@ X also put something in lib/preferences.txt for default location X this way a course admin can change the default location o need to check if volume is read-only, notify and quit if it is o people are trying to run off the disk image -o actually that should be fine.. +o actually that should be fine.. o but make sure the prefs location can be written o need to pay attention to when running from read-only drive o reported by brandenberg -o "p5 will launch from the disk image, but will +o "p5 will launch from the disk image, but will o not draw the sketch name bar doesn't appear" X include preferences.txt option to write to p5 folder first X this can be altered by instructors and re-packaged @@ -7210,7 +7909,7 @@ X put 'play' on a SwingWorker thread X test this on a pc to see how it goes, especially with opengl X doesn't seem to help anything X PdeRuntime -> SystemOutSiphon, removed MIN_PRIORITY setting -o hack to not use console on the code folder +o hack to not use console on the code folder o no errors will propogate, but it should run fine X lib/build should not be a subfolder of p5 X p5 environment installed to /Applications on lab machines @@ -7218,7 +7917,7 @@ X instead use a temp folder X maybe when running on lab machines in that case, always java mode? X or is it possible to add to java.class.path while app is running? X have to use a special class loader -X new class loader for single files +X new class loader for single files X if more than one class defined, forces it to run externally X (basically any time it sees "class" in the code.. X may be subject to errors, but errs on side of just running ext) @@ -7235,7 +7934,7 @@ X make preproc only build once (across osx, windows, linux) X preproc: making all functions public that have no specifier X this will make draw() etc all much easier X as well as the library events -X focusGained/focusLost was added.. +X focusGained/focusLost was added.. o if a data file is in the sketch (not data) folder export breaks o works fine in the editor, but on export gets a nullpointer ex X no way around this, because needs to be able to read from local dir @@ -7263,10 +7962,10 @@ X serialEvent, clientEvent, serverEvent X if videoEvent exists, don't auto-read? X though for serial this would only grab the last byte X video bug on osx? an error message when quitting video sketches: -X java.io.IOException: Bad file descriptor -X at java.io.FileInputStream.readBytes(Native Method) etc... ). +X java.io.IOException: Bad file descriptor +X at java.io.FileInputStream.readBytes(Native Method) etc... ). o bring back some form of beginSerial/beginVideo -o openSerial(), serial().. +o openSerial(), serial().. o should it prompt or use the first available if none specified? X run library destroy after hitting 'stop' X quicktime audio doesn't stop after hitting 'stop' @@ -7290,7 +7989,7 @@ X keypressed hanging on applets with a code folder X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081450102 X problems running external vm/vm is hanging X seems to be happening because of virus scanning software (norton) -o may need to launch the applet (using 'start') +o may need to launch the applet (using 'start') o and talk over a socket instead X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1067867520;start=0 X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1067643186 @@ -7305,18 +8004,18 @@ output to the console and see if it'll still crash. run via a disconnected process, using "cmd /c start java", the thing will never hang. in that instance, the process terminates almost immediately, and no i/o needs to happen (since it's a cmd prompt that -never shows up). +never shows up). * it could also be a graphics sync bug that just gets more testy because the environment, a second java process, is running at the same time. mis.newPixels() may hork since it's over in the applet's thread, and it might be calling repaint() or Toolkit.sync() to update the -image on-screen. +image on-screen. * shows up on key presses.. not sure if this is because of the actual key press, or if it's because they're often accompanied by a println() * blank spaces in filenames/parent folder often cause trouble.. not sure if related. same for PATH and CLASSPATH. * some virus scanning software, particularly older NAV versions cause -the trouble. +the trouble. 0074 pde @@ -7350,14 +8049,14 @@ X uppercase being capitalized before lowercase X need to mix case.. use toLowerCase before compare X add a little gap on editor frame at the left X http://processing.org/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1097363967;start=0 -X add to readme or bugs.. +X add to readme or bugs.. X menus that are too long just get clipped on the screen X can't be fixed because it's a java/os issue X also strange menu behavior for popups, especially on osx we can't fix o if applet.html is present, open that in the editor too. o or do we make people use dreamweaver? o nixed by casey, we're not dreamweaver -X macosx not exporting core.jar +X macosx not exporting core.jar X the jar is buried Contents/Resources/Java X don't enable externalRuntime with multiple code files that are pde X no longer separate classes @@ -7375,7 +8074,7 @@ X remove grow box from applet frame macosx X verify that export is working from processing.app -o check into ryan's macosx java bug.. +o check into ryan's macosx java bug.. o see why coords are going negative @@ -7396,11 +8095,11 @@ X sketch is changing before the "save changes?" is complete X as a result, 'cancel' does nothing X always ask save changes, even if nothing changed -040620 sunday +040620 sunday X remove 'sketchbook.prompt' (comment it out) X not really needed X remove prompt stuff from the preferences panel -X clean up the "more options" in prefs panel +X clean up the "more options" in prefs panel X to use JLabel instead of JTextArea X font was wrong on windows X start working on "save as" @@ -7441,7 +8140,7 @@ X reads sketchbook properly from other folder X but creates a new folder for new sketches to go into X sketchbook.dir not properly read or written X install sketchbook into another location on person's machine -X use System.getProperty("user.home"); +X use System.getProperty("user.home"); X remove the 'default' for sketchbook X bring this up on bboard and get votes X win2k: my documents, macosx: ~/Documents, linux: ~/sketchbook @@ -7490,14 +8189,14 @@ X sometimes nice just to have it create an unnamed sketch quickly X shift-new will always prompt with filedialog X dashes shouldn't be allowed in filenames for sketches X actually, lost the naming stuff because now using FileDialog -X this also needs to be checked when building the sketch menu +X this also needs to be checked when building the sketch menu X rewrite sketchbook.clean() X prompt user if they don't have it set to auto X add a pref to the preferences window 040622 monday late night X set handleOpen to use editor as its parent frame -X what happens when the .pde file isn't named +X what happens when the .pde file isn't named X the same as the enclosing folder? X maybe put up a window saying no way, and ask: X ( ) rename enclosing or ( ) add a subfolder @@ -7505,7 +8204,7 @@ X or maybe even ( ) rename the sketch file X also double-check to see if there *is* a proper pde in the folder X in which case, default to that (maybe show a message?) X it's useful to have loose .pde files be runnable.. -X i.e. when double-clicking on them.. downloaded off web.. +X i.e. when double-clicking on them.. downloaded off web.. X but need to deal with simply, not providing a new exception case X begin writing 'new text file' @@ -7549,7 +8248,7 @@ X what should the prefs file be named? X horizontal buttons? need final decision [yes] X remove underscores from the tab title? X nope, casey says not necessary -X need nice yes/no dialog boxes, also +X need nice yes/no dialog boxes, also o does "Open" go at the beginning or end of the sketch popup X we need opengl support in there X otherwise we're going to be stuck behind director @@ -7577,7 +8276,7 @@ X add .java to file name in the tab X change name of prefs to Processing Preferences.txt X implement clone for BImage X api name changes for imaging functions -X constant SUBSTRACT -> SUBTRACT +X constant SUBSTRACT -> SUBTRACT 040707 afternoon X minor bug with when setting sketchbook to a bad location @@ -7615,7 +8314,7 @@ X modify preproc to handle "void setup" -> "public void setup" o preproc bug: text(String.valueOf(i+1), left + i*20, top); o unexpected token "String" X make more things public (i.e. pixels) -X get casting working properly.. int() maps to toInt()? +X get casting working properly.. int() maps to toInt()? X what is performance hit for this thing? X remove substitute_image/font X remove String casting @@ -7661,7 +8360,7 @@ X processing.serial -> PSerial, [PUsb] other stuff / cleaning up X don't allow apostrophe (i.e. casey's_cells) when naming sketch! -X when exporting applet, line numbers will be off.. +X when exporting applet, line numbers will be off.. o when not exporting with new preproc code, imports all on same line o make preproc keep track of how many lines were added X rewrite video, net, serial libraries to be separate @@ -7687,7 +8386,7 @@ o ability to include other .java and .pde code from sketchbook folder o 'add files' for .java or .pde pulls into the folder X split to take strings (ie. for ", ") o image(BImage, x, y, float scale) (found in illustrator stuff) -o begin/end.. beginSerial/endSerial -> +o begin/end.. beginSerial/endSerial -> o openSerial/closeSerial ? o startSerial/stopSerial X punting on api @@ -7725,8 +8424,8 @@ X load that before the other stuff X -> was already implemented like that o fix the problem causing all the "couldn't delete" messages o class naming from dan -o If you name a class the same name as the sketch project, -o you get an error about contained classes with duplicate names +o If you name a class the same name as the sketch project, +o you get an error about contained classes with duplicate names o when you try to export for web. o quick fix inside PdeRuntime o if (loop == false) and (draw == false) then provide an error @@ -7748,7 +8447,7 @@ shape class Something { void setup() { // not used, or called on first draw - // but maybe required (even if behind the scenes) + // but maybe required (even if behind the scenes) // so that this can use "implements ShapeInterface" } @@ -7771,7 +8470,7 @@ shape(ShapeInterface o) { X run java mode when large 'data' folder is in use X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081542378 -X fixed one bug in PdeRuntime error message stuff +X fixed one bug in PdeRuntime error message stuff X was this the big one? a big one? 040715 late @@ -7796,15 +8495,15 @@ X i.e. cut -> new file -> paste doesn't mark any as changed X "include all chars" and all the bugs it represents X working on datatype conversions -040717 +040717 o dll and jnilib files have to be in the p5 folder (confirmed by amit) -o there should be other places that they work.. +o there should be other places that they work.. o could even copy the dll to the p5 folder from the code folder o already fixed with LD_LIBRARY_PATH stuff 040902 -X building Processing from scratch -X not able to write "preferences.txt" on the first run +X building Processing from scratch +X not able to write "preferences.txt" on the first run 040903 X examples should be in a submenu of open @@ -7819,14 +8518,14 @@ o need to be able to select between which to include o auto-resolve by saying java.* wins, others ask X make built-in libraries read-only -040912 -X several menu changes as discussed with casey +040912 +X several menu changes as discussed with casey X (capitalization, export/export app, tools) X add preference for showing library stuff 040913 morning X figure out why user libraries not being added -X in lib mode, show internal libraries as part of the 'open' menu +X in lib mode, show internal libraries as part of the 'open' menu X make a note that p5 has to be restarted for libs X import all libraries into classpath X all libs found during sketchbook build + all libs in libraries @@ -7840,7 +8539,7 @@ X "Processing" folder not properly created on new install X add noLoop() to static mode apps X remove "loop" from special inserts on preproc -040921 afternoon +040921 afternoon o when running externally, build into sketch folder? X add all imported libs to hash table of jars @@ -7866,7 +8565,7 @@ X errorMessage in PSerial/PClient/PServer are all using System.out X write handler for loop() error, warning user to rename loop to draw X c:/fry/processing/build/windows/work/lib/build/Temporary_1452_9170.java:29:6:29:11: Semantic Error: The method "void loop();" with default access cannot replace the accessible method "void loop();" with public access declared in type "processing.core.PApplet". -040925 +040925 X change how export.txt works X make p2 dist for amit X break out BSerial as separate object like BVideo @@ -7881,7 +8580,7 @@ o http://docs.info.apple.com/article.html?artnum=93414&sessionID=anonymous%7C2 o "Type quicktime.std.stdQTConstants was not found" o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1066358763 o http://docs.info.apple.com/article.html?artnum=120255 -X split classes to BVideo and BMovie ? +X split classes to BVideo and BMovie ? X don't force install of qtjava X this requires a separate version of bagel that doesn't use video X or a version that loads video dynamically. that kinda sucks. @@ -7910,7 +8609,7 @@ X selecting input source (wintv board and quickcam installed.. problem) network o don't send unicode data -X when you stop the client, it freezes +X when you stop the client, it freezes X until you quit the processing running the server X (the server starts and stops fine) X add constants for building NET, move stuff around in bagel dir @@ -7928,7 +8627,7 @@ X remove fonts from distribution X be able to link against, but not export, certain parts of lib X jsyn.jar not needed on export, netscape libs not needed on export o crap.. libraries need to be in packages for this to work -o but annoying: attach("simong.particlesystem.ParticleSystem") +o but annoying: attach("simong.particlesystem.ParticleSystem") X disable "export application" X font builder X properly update the font on new selection @@ -7973,7 +8672,7 @@ X go through the board and move messages X a garbage filled classpath can cause trouble X http://processing.org/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1096302833;start=0 X processing won't start.. -X people with non-ascii chars in the folder name +X people with non-ascii chars in the folder name X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1062794781;start=0 X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1067764732 X other errors with spinning and not doing much @@ -8000,7 +8699,7 @@ X update to new shell runner (old mrj guy was ancient) 0070p7 X fix run.bat and run-expert.bat X remove library path debug message -X catch error message for "quicktime.std" +X catch error message for "quicktime.std" X move packages to processing.video, processing.serial, etc. X need to update the set of new examples X make sure the library features are disabled by default @@ -8018,7 +8717,7 @@ X update with other examples 0070p8 (final) X height for applets wasn't working properly X debug font stuff in processing.core -X mbox wasn't set properly (not a power of 2) +X mbox wasn't set properly (not a power of 2) X debug framerate() stuff with noLoop() X re-enabled printarr(Object[]) X remove SystemOutSiphon: i just died message @@ -8031,7 +8730,7 @@ X examples updated 0069 pde -X font builder +X font builder X crashing on small sizes for many fonts X make the text area not selectable or highlightable X add a few more rows @@ -8189,7 +8888,7 @@ X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs 0066 X BImage.replicate for straight 1:1 copy, blend() for blended version -X remove the blendMode function because it's confusing +X remove the blendMode function because it's confusing X big changes to image code from toxi X repaired smoothing so that it doesn't crush the last line X bresenham ellipses/circle ignore alpha @@ -8211,7 +8910,7 @@ X if saveas/rename names match, use renameTo X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1066495952;start=0 X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1066497131;start=0 X include JSObject with p5's pde.jar -X jaws.jar is already included on mac.. +X jaws.jar is already included on mac.. X check to see if ok on pc (empty project -> new JSObject()) X files are in jaws.jar: JSObject, JSException and JSUtil X curvePoint not initializing @@ -8245,7 +8944,7 @@ X fix SMOOTH_IMAGES problem with how text had been modified X include version number in the about box X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1064220242 X Ctrl-B will beautify the code and send the cursor back to the -X beginning of the the text. Then you have to scroll back to +X beginning of the the text. Then you have to scroll back to X where you were... ok, so maybe I am a heavy user of Ctrl-B. X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1064220242;start=0 @@ -8261,9 +8960,9 @@ X removed the cancel button 0063 X beautify menu became disabled when moved X BImage(int width, int height) constructor -X trying to track down sluggishness with applets.. +X trying to track down sluggishness with applets.. X beginShape/endShape.. 3D scenes with boxes.. -X newPixels is in BGraphics.endFrame, +X newPixels is in BGraphics.endFrame, X screen.drawImage is in BApplet.paint X need to move both to BApplet.paint() X external applet stuff @@ -8320,7 +9019,7 @@ X open applet folder after exporting sketch X switch back to red instead of yellow for errors. whups. from carlos' contract, but implemented by fry -X get font things sewn up +X get font things sewn up X create a simple generator for grayscale bdf fonts X document the change and make several of them X font smoothing (unless hint SMOOTH_IMAGES enabled) is broken @@ -8391,16 +9090,16 @@ X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display; X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1062483060;start=0 X if there's a bug in bagel, PdeRuntime.message() ignores it X just says "NullPointerException" but provides no info -X now at least spews the exception +X now at least spews the exception X removed ugly white borders from ui on macosx java 1.3 X is there anything better that can be done for osx java 1.3 X setInsets() to zero or something? -X font.stringWidth -> font.width(char c) or width(String s) +X font.stringWidth -> font.width(char c) or width(String s) X removed extra push()/pop() in text(String s) that may save time X bezier error, goes up at the end X also when using bezierMode, doesn't draw the first vertex X size(300,200); -X bezier(0,100,width/3,100,2*width/3,100,3*width/3,100); +X bezier(0,100,width/3,100,2*width/3,100,3*width/3,100); X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1064166242;start=0 X add note to tga spec X http://organicbit.com/closecombat/formats/tga.html @@ -8425,12 +9124,12 @@ X resize is maybe goofy, so just size() for all? X color() with alpha now works properly X removed SMOOTH_IMAGES X removed shearX and shearY -X toxi image code (!) +X toxi image code (!) X need background(BImage) and scaling, copy area, etc. X vertex(x, y, u, v) and vertex(x, y, z, u, v) X don't cast color() X since more important for color(v1, v2, v3) to work -X getPixel/setPixel -> get/set.. +X getPixel/setPixel -> get/set.. X get(x, y, w, h) is nice but no set(x,y,w,h) X though set(x,y,w,h) could be nice X and copy() to copy a section of pixels @@ -8462,11 +9161,11 @@ X some flag to know whether applet is online or not X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1051758365;start=0 X colorMode is defaulting to 255, 255, 255, 1.. oops X though setting it differently hoses everything (clears everything) -X setup (200, 200) causes the default size to be used +X setup (200, 200) causes the default size to be used X be able to draw something inside setup (?) X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1044689650;start=0 X no time to ask for "save changes" before quit -X PdeEditor, around line 910.. not blocking until input +X PdeEditor, around line 910.. not blocking until input X read up on how to properly block for input in a java app X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1064165653;start=0 X do not delete sketch folder if empty sketch but non-empty data dir @@ -8498,9 +9197,9 @@ X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display; fixes because of dmose parser dm X move to antlr -dm X float z= float(x) + float(y); +dm X float z= float(x) + float(y); dm X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1062471182;start=0 -dm X compiler barfs on: float[] moo = new int[10]; +dm X compiler barfs on: float[] moo = new int[10]; dm X although no error comes through to p5 (benelek) dm X this was a kjc error, so it's fixed with jikes dm X int() doesn't work inside other functions @@ -8513,7 +9212,7 @@ dm X setup( ){} has an error, setup(){} does not dm X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1062461971;start=0 dm X weird comments bug (// on last line causes oro trouble) dm X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1062462227;start=0 -dm X unexpected token 'void' in letters sketch.. +dm X unexpected token 'void' in letters sketch.. dm X being parsed as static mode app dm X extra parens confusing things (toxi message) bf X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1064165730;start=0 @@ -8562,7 +9261,7 @@ X textureImage() -> texture() X textureMode() IMAGE_SPACE or NORMAL_SPACE X vertexNormal() -> normal(); X vertexTexture -> vertex(... u, v); -X bezier(... t) -> bezierPoint() +X bezier(... t) -> bezierPoint() X curveTangent and bezierTangent are in there X curve(... t) -> curvePoint() X bezierMode -> bezierSegments @@ -8586,8 +9285,8 @@ X ALIGN_XXXX becuase LEFT already used for keys X implement text(int something) and text(float something) o and perhaps others? X textSpace SCREEN_SPACE and OBJECT_SPACE -X strokeMode/strokeWidth -> -X strokeWeight, strokeJoin, strokeMiter +X strokeMode/strokeWidth -> +X strokeWeight, strokeJoin, strokeMiter X param(), online(), and status() functions X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1064166444;start=0 @@ -8641,7 +9340,7 @@ o jre icon not appearing in the systray o http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1030538508 o getting mouse movement outside the window o http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1051916278;start=0 -X building releases from scratch +X building releases from scratch X this is a useful developer task before release X build all releases from a clean cvs X tries to make work/ without bagel serial existing and blows up @@ -8672,13 +9371,13 @@ X optimize color() when in colorMode(RGB, 255) to just pack the int X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1062072434;start=0 X imageMode() shouldn't affect fonts X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1060207942;start=0 -X replacing spaces with underscores.. +X replacing spaces with underscores.. X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1062103523;start=0 X patch keyTyped event instead of keyPressed X remove reference in readme about macosx problem w/ it X test on macosx X test on linux -X Event.consume() doesn't work on entry fields +X Event.consume() doesn't work on entry fields X manifests itself in sketch naming, can't be constrained X may not be the case under swing? X it's probably because of keyTyped() being the important one @@ -8701,7 +9400,7 @@ X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs known issues/bugs * quicktime for java is *required* on windows.. it's installed by -default on macosx, and not used at all on linux. +default on macosx, and not used at all on linux. * QTJAVA environment variable is used to find quicktime. if that's not properly set, then you won't be able to run. * lots of 'cannot delete ...' messages @@ -8750,7 +9449,7 @@ X write proper build instructions for bagel X email about bagel doesn't have proper build instructions X need to install cygwin, set CLASSPATH to build X specific version of jikes (currently) -X make mac version require head/tail from fink ? +X make mac version require head/tail from fink ? X test to see if /sw/bin/head exists, if so use it X get dmose's new launcher running X cleanup cvs bunk @@ -8809,12 +9508,12 @@ X removes a random ArrayIndexOutOfBoundsException X Thread.stop is deprecated (and has been since 1.2) X http://java.sun.com/products/jdk/1.2/docs/guide/misc/threadPrimitiveDeprecation.html X remove finished in favor of just setting thread to null in BApplet -X check to see if setting threads to null works on windows +X check to see if setting threads to null works on windows X the multiple thread killing code was in there for a reason -X not tested on macos9.. +X not tested on macos9.. X hiding the cursor. noCursor(), cursor()/cursor(ARROW), cursor(HAND), cursor(CROSS), cursor(image_file) X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1059485109 -X default size of console is bad.. +X default size of console is bad.. o prolly need to stuff in 4 blank lines o runtime exceptions not coming through on either mac or windows X works fine on windows @@ -8858,20 +9557,20 @@ X seems that file names changed between 1.3 and 1.4 X sorted this issue out, now it's re-enabled X change default font for jdk 1.4 X reference launching working properly -X reference doesn't launch on mac (mKoser) +X reference doesn't launch on mac (mKoser) X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1038424448 -X tweak for java 1.4 +X tweak for java 1.4 X need to add a line to the properties file o include a note about this in the readme, include url for download o connect.apple.com X bug on p5 bboard: http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1037829938;start=0 running 1.4 from the command line: -/System/Library/Frameworks/JavaVM.framework/Versions/1.4.1/Commands/java +/System/Library/Frameworks/JavaVM.framework/Versions/1.4.1/Commands/java Info.plist, setting JVMVersion -* 1.3.1 - only use JDK 1.3.1, even if later versions are available. +* 1.3.1 - only use JDK 1.3.1, even if later versions are available. * 1.3* - use any version of JDK 1.3.x. Do not use JDK 1.4 even if it's dflt. -* 1.3+ - use the latest JDK version from JDK 1.3 onward, up to default JDK. -* 1.4+ - use JDK 1.4 or later, even if an earlier JDK is the default. +* 1.3+ - use the latest JDK version from JDK 1.3 onward, up to default JDK. +* 1.4+ - use JDK 1.4 or later, even if an earlier JDK is the default. o and then edit Info.plist to include the following lines: o JVMVersion 1.3.1 X control-click (right-click?) for macosx doesn't show popup @@ -8886,7 +9585,7 @@ X currently the only fix is to switch to java 1.3 X update the readme to note that macos9 is suspended X why doesn't processing.app work anymore X machine was screwy -X perlin noise 1D. noise() +X perlin noise 1D. noise() X double-check to see if wheel mouse is working X macosx quit handler takes over ctrl-q X so file->quit doesn't get called on close @@ -8918,7 +9617,7 @@ X puts a couple dots on random lines X modify build scripts for rxtx on osx X libs from 2.1.6 download for osx seem to work X write script to handle installation, etc. -X (maybe do this from inside p5?) +X (maybe do this from inside p5?) X get jikes118 in there.. also in cvs o add note to instructions for how to use X change Proce55ing.app to Processing.app @@ -8973,7 +9672,7 @@ dm X write handlers for jikes-style of error messages post-0057c1 -X deal with spaces in user.dir (!) +X deal with spaces in user.dir (!) X affects reference, and prolly compiling too X alt key pressed spews errors about components X prolly because of swing/awt component problems @@ -9005,7 +9704,7 @@ X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs X String wasn't colored, so added parts of java.lang X BFont was allocating too much memory for fonts (found by arielm) X modified all scripts to unpack the new reference -X simage() has been enabled again +X simage() has been enabled again X https://sourceforge.net/tracker/index.php?func=detail&aid=750867&group_id=63445&atid=504000 X image_mode has been ironed out X https://sourceforge.net/tracker/index.php?func=detail&aid=750886&group_id=63445&atid=504000 @@ -9057,7 +9756,7 @@ bf X reported by benelek hb X patch for server makes netEvent messages -moved to sourceforge by arielm +moved to sourceforge by arielm BAGEL / Bugs @@ -9068,7 +9767,7 @@ BAGEL / Bugs b _ image(img, x, y) in CENTER_DIAMETER is actually center radius b _ should make sure that x, y just makes it proper size - b _ simage() is screwy.. + b _ simage() is screwy.. b _ its invocation is broken (image_mode can't be two things at once) b _ doesn't actually use image_mode for placement b _ also doesn't support RGBA @@ -9090,7 +9789,7 @@ BAGEL / Bugs b _ single pixel lines have no alpha and no z b _ fix all the random line types to support alpha - b _ anti-aliasing. smooth(), noSmooth() + b _ anti-aliasing. smooth(), noSmooth() b _ need to verify that this works consistently throughout b _ alpha. fill(r, g, b, a), stroke(r, g, b, a), @@ -9105,7 +9804,7 @@ X use nfs (number format signed), with a bool for + or spc X does a[3] == Float.NaN work? (for testing with splitFloats) X no, if NaN, then comparison will always return false X sort() functions for arrays of ints, floats, doubles, and Strings -X add casey to sourceforge with admin privileges as 'reas' +X add casey to sourceforge with admin privileges as 'reas' X fix wheel mouse handler so that it works under jdk 1.3 X no difference between 1.3 and 1.4 code X add WheelHandler to cvs @@ -9140,7 +9839,7 @@ X image of 256x256 doesn't draw the last line of pixels X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1045697665;start=0 X weird line in showing in the center of an image X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1044901171;start=0 -X color() should work for alpha.. +X color() should work for alpha.. X also #rrggbbaa X http://proce55ing.net/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1049141984 X blend() (or any other 'final' functions) is causing trouble @@ -9163,17 +9862,17 @@ X modelX or objectX could do the amit style thing X creas says object X better access to projX et al X what's a better name? calcX? or write to an array? -X projectX, projectY, .. or projectedX ? +X projectX, projectY, .. or projectedX ? X also projectSize should just be project() X smooth() and noSmooth() X possible dist() and constrain() functions -X reas: I like people making these themselves and then later +X reas: I like people making these themselves and then later X they can be added to their code libraries X join() like split X also add additional item for NaN data X add doubles and longs for genome stuff X numberFormat (formerly zeroPad) -X numberFormat(float num, int left, int right) +X numberFormat(float num, int left, int right) X zero means any number of digits, don't pad X numberFormat(int num, int left) for 27 -> 0027 X camera work @@ -9286,10 +9985,10 @@ X new colors chosen by casey (replace pde.properties and buttons.gif) / works in 'insert' mode X just disabled it ever hiding.. we'll see if it fixes X flush() after every println() -X incremental printout +X incremental printout X uncovered bug with long line lengths in console / pmouseX problem reported by casey (in bugs.txt) -o images don't load during setup [reas] +o images don't load during setup [reas] X //This is not a problem -- Casey X framerate() and framerate(15) X delay() should sleep the thread [glen murphy] @@ -9300,13 +9999,13 @@ X add framerate to colored things list MISC (pruned from crusty todo list) -X text editor? jedit's textarea class? hmm? hmm? // Yeah for jedit! +X text editor? jedit's textarea class? hmm? hmm? // Yeah for jedit! X document imageMode, planeMode, ellipseMode X 'rot' example not working in release 18 X make note in documentation about getting access to pixel array X pixels[] is in ProcessingApplet X build a linux/x86 release -X fix buzz.pl to not create ../../bagel +X fix buzz.pl to not create ../../bagel X how to use ssh identity file to maintain auth for brancusi X write dist.bat for releases X don't forget to update 'export' dir with processing releases @@ -9317,7 +10016,7 @@ X bug in paren balancing X paren problems comes from overusing parens (too many closing) X image[first[i], 0, 0) hitting last paren causes jump to top X beautify is broken // I think this is fixed -X sketch: sketch-000 is dumb +X sketch: sketch-000 is dumb X // Just number successively 0001, 0002 like a digital camera X color won't set for fonts //This works o 'image' is too generic a variable to have inside BApplet @@ -9343,12 +10042,12 @@ X include note in the readme that 1.4 is not supported X is sketch.properties saving properly under macosx? X text in editor is anti-aliased, allow to turn off (franklin_mint) X also make text courier instead of monospaced -public void paint(Graphics g) -{ - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - super.paint(g2); +public void paint(Graphics g) +{ + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + super.paint(g2); } pde @@ -9366,24 +10065,24 @@ X add -Xmx128m -Xms128m because people running out of memory (pitaru) X tried with a 3k x 1k image and things broke o maybe command line read properties from a file in lib -macos9 +macos9 X do some font tweaking (monaco 9 or 10 might be good) 0047 X reported by fdb and brendanberg -After creating about 27 sketches, proce55ing (0046 on OS X) no longer would startup, giving me the following error: -Exception in thread "main" java.lang.NullPointerException - at PdeBase.addSketches(PdeBase.java:598 ) - at PdeBase.addSketches(PdeBase.java:615) - at PdeBase.rebuildSketchbookMenu(PdeBase.java:575) - at PdeBase.(PdeBase.java:362) - at PdeBase.main(PdeBase.java:102) -Removing all sketches would solve the problem. +After creating about 27 sketches, proce55ing (0046 on OS X) no longer would startup, giving me the following error: +Exception in thread "main" java.lang.NullPointerException + at PdeBase.addSketches(PdeBase.java:598 ) + at PdeBase.addSketches(PdeBase.java:615) + at PdeBase.rebuildSketchbookMenu(PdeBase.java:575) + at PdeBase.(PdeBase.java:362) + at PdeBase.main(PdeBase.java:102) +Removing all sketches would solve the problem. / lots of problems in moving sketches over - i managed to run p5 from the applications folder once, but i think when i moved my sketches over from 0044 it broke: "uncaught exception in main method: java.lang.NullPointerException" - i tried reinstalling and running 'java -cp lib:lib/build: ...' and it worked fine (and would open from the icon afterwards) -again, after i moved my sketches over it broke permanently... + i managed to run p5 from the applications folder once, but i think when i moved my sketches over from 0044 it broke: "uncaught exception in main method: java.lang.NullPointerException" + i tried reinstalling and running 'java -cp lib:lib/build: ...' and it worked fine (and would open from the icon afterwards) +again, after i moved my sketches over it broke permanently... / 46 dies when run from desktop on some machines [jes] / spaces in the dir name? o is sketch.properties getting mangled on the mac? @@ -9455,7 +10154,7 @@ X method to set a folder for the sketchbook X when trying to use serial, provide error if things not installed -0046 +0046 X install new swing-based textarea with syntax highlighting X improve the flicker problems (re-enable backing store?) X set better defaults for coloring @@ -9496,20 +10195,20 @@ X preprocessor tweaks X "http://acg.media.mit.edu" doesn't work because of // X "color.jpg" -> "int.jpg" causes trouble X why does this line cause an error? -// String url = "http:\u002f\u002fwww.Proce55ing.net"; +// String url = "http:\u002f\u002fwww.Proce55ing.net"; X it's not in the preprocessor, but kopi seems to be having trouble -X seems that file i/o may be picking up lots of extra \r +X seems that file i/o may be picking up lots of extra \r X perhaps when doing setText, it's goobering things up -X when renaming a sketch, select the text in the field, -X so you can type the new name immediately. +X when renaming a sketch, select the text in the field, +X so you can type the new name immediately. X added 'rename' command X also the default for clicking on the sketch's title o option to rename when doing a 'save as' (remove old files) X remove .class files on save as [dimitre] X remove .jar, .class, and .java files from the 'applet' dir -When I am working in a project and I save it with another name, -all the old files are copyied to new directory, and some of the old -unused .class files and images remains inside new project JAR files. +When I am working in a project and I save it with another name, +all the old files are copyied to new directory, and some of the old +unused .class files and images remains inside new project JAR files. X serial port X better message for PortInUseException (full explanation) X better message for when serial port code not available/not installed @@ -9519,42 +10218,42 @@ X this was previous unknown, but likely several found it (!) X macosx - check to see if swing is working properly X macosx - update build script to work with new layout X Add an Edit menu containing Undo/Redo/Cut/Copy/Paste/Select - All. It's standard Mac behaviour. + All. It's standard Mac behaviour. X long list from frederik (fdb) -X If the cursor is at the last character of the last line of the - text area, moving the cursor up or down using the arrow keys throws - the following exception: - java.lang.ArrayIndexOutOfBoundsException - at PdeEditorListener.keyPressed(PdeEditorListener.java:86) - at java.awt.Component.processKeyEvent(Component.java:3673) +X If the cursor is at the last character of the last line of the + text area, moving the cursor up or down using the arrow keys throws + the following exception: + java.lang.ArrayIndexOutOfBoundsException + at PdeEditorListener.keyPressed(PdeEditorListener.java:86) + at java.awt.Component.processKeyEvent(Component.java:3673) X If the cursor is at the last character of the first line of the text area, moving the cursor up using the arrow keys throws the same - exception. However, moving the cursor down doesn't throw one. + exception. However, moving the cursor down doesn't throw one. X Double-clicking a word doesn't select it, but the character after - it. (however, sometimes the behaviour is correct) + it. (however, sometimes the behaviour is correct) X Scrolling action when using cursor keys is not consistent with other editors: The window should only scroll when it needs to; it now tries - to keep the cursor on the current line. (or one line below it) + to keep the cursor on the current line. (or one line below it) X Using Apple-shift-arrowLeft to select from the cursor pos to the beginning of the line, selects one character too little at the right side. Apple-shift-arrowRight has the same issue (selects one char too - little at the left side). + little at the left side). X Using Apple-shift-arrowDown selects only from the beginning of this line to the end of the following line. It doesn't extend the selection when pressed twice. It also selects the line under the - current line. + current line. X Pressing the tab key moves to the bottom of the text area. X hopefully fixed, but needs to be tested -? Select All (Apple-A) closes the application - (Ctrl-Q) on Azerty-keyboards -X use date in the sketch name sketch_021104 +? Select All (Apple-A) closes the application + (Ctrl-Q) on Azerty-keyboards +X use date in the sketch name sketch_021104 X with a _2 if needed or '021104a' '021104b' etc X when using save as, allow to remove the old (numbered) sketch X better default size than 300x300 when starting up first time X bug report from the site resizing the editor window in Mac OS X leaves the status bar in place. The result is an editor window with a grey bar layered on top, -obscuring the editable text. +obscuring the editable text. X fix default fonts, font size on mac X fix lots of annoying crap about highlighting lines on errors X re-enable console, add synchronized (hrmph) @@ -9597,7 +10296,7 @@ X for now, disallow the / or : characters X there was a bug that required a noop() b/c of jikes or 1.3 problems X is problem w/ beautify that it has no menu event handler? X write event handler, and make sure it doesn't work for external ed -X don't popup offscreen if editor window is way left. +X don't popup offscreen if editor window is way left. X just make sure the x coord > 10 or so (if not presenting) X if so, pop up window 50, 50 from upper left corner X if it still won't fit, center the window on screen @@ -9634,7 +10333,7 @@ X escape on presentation mode--no key events seem to be coming through X make default font size for editor the next size smaller X include names of all people who submitted bugs X use self-extractor and make sure no 8.3 filenames -X use a .dmg to distribute +X use a .dmg to distribute X make sure no DS_Store files are included @@ -9686,7 +10385,7 @@ X remove projects if created but nothing happens to them X maybe do this on open or quit? X first a syntax error, when fixed, causes NullPointerException  X quitting the app makes things all better. argh. -X this just started with version37, it happens extrememely +X this just started with version37, it happens extrememely X frequently and should be easy to reproduce the error X images with imageMode set for simage() weren't working @@ -9710,7 +10409,7 @@ X some method for getting list of serial ports X pde menu item for listing serial ports available o could just println them to the console X import javax.comm stuff as standard in kjc (but not export) -X can't get fonts to load - tested working ok +X can't get fonts to load - tested working ok X bagel complaint: could not load font Univerx76.vlw.gz X why the x? what's going on? X try using serial on macosx @@ -9773,7 +10472,7 @@ X how to make double-clickable version for osx X might be as simple as combined jar with manifest and symlink X jar doesn't like opening pde.properties b/c getClass fails X app title comes up as PdeBase -X -Xdock:name property or +X -Xdock:name property or X com.apple.mrj.application.apple.menu.about.name (gulp) X -XDock:icon (lowercase dock?) to set icon, or X .icns file in the Contents/Resources of the bundle @@ -9783,7 +10482,7 @@ X serial works poorly for starting/stopping applets X appears to be fixed through use of static object in bagel X breaks on every 2nd run when using serial apps (or others?) X try calling gc on stop as well -X make it simpler to build the code.. +X make it simpler to build the code.. X buzz.pl actually no longer needed (no ifdefs) o use a regular makefile for everything X getResource stuff breaks, sketch.properties can't save @@ -9830,7 +10529,7 @@ X tested, seems to be fine? X console - convert tabs to spaces o line wrapping (but save info for resize? noo..) X fix to line numbers being off for KjcEngine exception highlights -X changed error color slightly for console to fit status error +X changed error color slightly for console to fit status error X size() not being called in setup is gonna cause lots of headaches X hack: put exception handler around setup and re-call if necessary X linefeeds were wrong in BApplet @@ -9841,7 +10540,7 @@ X mark each as 'save', 'autosave', 'failed' or 'successful' compile X also include a timestamp X if a selection is made from the menu: X autosave, replace text, mark as edited -X if there have been no edits, and last thing was hist change, +X if there have been no edits, and last thing was hist change, X should *not* do another autosave X ensure this by historyLast being set on change.. heh. nice. X write message to people who signed up for p5 alpha @@ -9862,11 +10561,11 @@ X same under windows, just wasn't being set properly before X header font needed to be set each time as well X introduce pde.properties_OSNAME X tested to make sure it joins with the other pde.properties ok -X setPixel(i, j, #99CC00); +X setPixel(i, j, #99CC00); X not working anymore Syntax error: unexpected token: CC00 -X problem was substitute only worked along with = +X problem was substitute only worked along with = X perl should be ok to be cygwin perl.. try deinstalling activestate -o should fix paren balancing bug.. +o should fix paren balancing bug.. X just disable by default for alpha o background() not working X checked but couldn't duplicate @@ -9892,7 +10591,7 @@ X just removed the listeners on the window.. don't seem to be needed 0035 -X fixed a NullPointerException on startup +X fixed a NullPointerException on startup X when sketch.properties didn't exist, shouldn't print error X fix status standard message color text color X mousePressed() not working, also mouseReleased @@ -9938,7 +10637,7 @@ X in progress working on presentation mode 0032 already finished -X need to update PdeKeyListener for new ui.. +X need to update PdeKeyListener for new ui.. X remove open, add d for duplicate, r for rename, others ? X 'open' button is a switch-to button X pops up list of everything in the sketchbook @@ -9988,7 +10687,7 @@ X make close() work to kill applet in kjc X save window x, y, width, height to pde.properties on exit X stderr in red color X 'data' directory for all media -X make included media part of the .jar file +X make included media part of the .jar file X it's really a pain to use external files in processing X getStream sucks (zach rewrote) X should be able to work for application or applets @@ -10131,7 +10830,7 @@ X font file names are getting mangled on mac (too long) X new set of fonts, make sure the names are ok -0024 +0024 X bug fixes (lighting was broken) @@ -10161,7 +10860,7 @@ o also problem filling on beginShape() triangle stuff X z coordinates are backwards from gl (at least from mazo) X looked into it, this doesn't appear to be the case.. X how did this happen? what's the appropriate way to fix? -X in gl, positive z goes into the screen +X in gl, positive z goes into the screen X may be able to do a scale(0, 0, -1) that doesn't affect dims X then when dims set to 3, will fix the z coords X this will also affect zbuffer ordering @@ -10174,9 +10873,9 @@ X introduce pImage, pFont, pGraphics, pConstants (pSound) 0019 questions answered.. -X is day, month, year overkill inside processingapplet? +X is day, month, year overkill inside processingapplet? X decided no -X loadImage or getImage? +X loadImage or getImage? X loadImage sounds better to ben and casey X circle/square functions X doesn't seem necessary @@ -10199,7 +10898,7 @@ X beginShape() defaults to POLYGON X introduce constants for other poly modes X add ellipseMode(), rectMode() X CENTER_RADIUS, CENTER_DIAMETER, CORNER, TWO_CORNERS -X bezier and catmullrom aren't setting ndim to at least two +X bezier and catmullrom aren't setting ndim to at least two X ?? not sure why they would X translate(x, y) doesn't seem to affect a rect() X flat_rect was being used where ndim was 2, not 0 @@ -10248,7 +10947,7 @@ X switched to ibm java vm 0014 -X fix z coordinate, ndims not being set to 3 +X fix z coordinate, ndims not being set to 3 X put bezierCurve and catmullRomCurve back in X examples - setting background using a full screen image X uses System.arraycopy for speed @@ -10264,14 +10963,14 @@ X may have fixed OutOfMemoryError problems X run.bat had included -ms256m -mx256m -0013 +0013 X ellipse draws in the opposite direction of the origin X actually fix the bug with extends X wasn't included in previous release X option to set full screen background color X uses fullscreen.bgcolor in lib/pde.properties X remove 'colorScale' from the default program in pde -X fix color cube applet +X fix color cube applet X make it run in current version of processing X fix background from showing up black X screenGrab() code (single frame to tif) @@ -10310,14 +11009,14 @@ X got rid of colorscale and using colormode for all instead X make changes in documentation X 'ellipse' instead of 'oval'? X make note in documentation -X catmullrom is broken +X catmullrom is broken X write documentation for new curve functions o make note in docs about removal of LINE from LINES X setting origins X should shapes draw from center or from upper left? X should ovals use radius or diameter? X should shapes use x1, y1 - x2, y2 or x, y, w, h? -X nice to have a random number generator between -1..1 +X nice to have a random number generator between -1..1 X as well as an integer random; instead of just 0..1 X show creas how to get access to cvs X documentation says 'mouseDown' even though it's 'mousePressed' @@ -10337,9 +11036,9 @@ X worked fine for me 0009 X bagel fixes -X beginShape(POINTS) is not working, no marks are appearing +X beginShape(POINTS) is not working, no marks are appearing X this was a pain in the ass to fix -X beginShape(LINE_LOOP) is not looping around +X beginShape(LINE_LOOP) is not looping around X stroked POLYGON should emulate a LINE_LOOP X fill white, stroke black, background white default in bagel X remove duplicates: LINE/LINES etc @@ -10389,7 +11088,7 @@ X or copy bagel's image, and kill that too? 0004 -X put debugging stuff back into Kjc (i disabled some stuff) +X put debugging stuff back into Kjc (i disabled some stuff) 0001 diff --git a/java/application/launch4j/bin/ld-linux-armv6hf b/java/application/launch4j/bin/ld-linux-armv6hf new file mode 100755 index 0000000000..032cd917a8 Binary files /dev/null and b/java/application/launch4j/bin/ld-linux-armv6hf differ diff --git a/java/application/launch4j/bin/windres-linux-armv6hf b/java/application/launch4j/bin/windres-linux-armv6hf new file mode 100755 index 0000000000..41b2223800 Binary files /dev/null and b/java/application/launch4j/bin/windres-linux-armv6hf differ diff --git a/java/application/launch4j/head/guihead.o b/java/application/launch4j/head/guihead.o index 9cc215d9ac..7cff132218 100644 Binary files a/java/application/launch4j/head/guihead.o and b/java/application/launch4j/head/guihead.o differ diff --git a/java/application/launch4j/head/head.o b/java/application/launch4j/head/head.o index a8522f7c83..d5d63d6666 100644 Binary files a/java/application/launch4j/head/head.o and b/java/application/launch4j/head/head.o differ diff --git a/java/application/launch4j/launch4j.jar b/java/application/launch4j/launch4j.jar index 7b3d72287c..6daad70f7a 100644 Binary files a/java/application/launch4j/launch4j.jar and b/java/application/launch4j/launch4j.jar differ diff --git a/java/build.xml b/java/build.xml index 32932744b5..0fda9c2c55 100644 --- a/java/build.xml +++ b/java/build.xml @@ -1,15 +1,15 @@ - + - + - + @@ -23,12 +23,12 @@ - - - - - - + + + + + + @@ -37,9 +37,9 @@ - + @@ -49,28 +49,24 @@ - + - + - + - + @@ -86,38 +82,37 @@ - - + + https://github.com/processing/processing/issues/1792 --> + debug="on" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> - diff --git a/java/keywords.txt b/java/keywords.txt index fb8da82ade..b71cbf66ba 100644 --- a/java/keywords.txt +++ b/java/keywords.txt @@ -1,17 +1,18 @@ -# THE TEXT BELOW IS HAND WRITTEN AND FOUND IN THE FILE "keywords_base.txt" -# IN THE PROCESSING-DOCS REPO. DON'T EDITS THE keywords.txt FILE DIRECTLY. +# THIS TEXT IS FROM keywords_base.txt IN THE PROCESSING-DOCS REPO: +# https://github.com/processing/processing-docs/blob/master/generate/keywords_base.txt +# MAKE CHANGES THERE: DO NOT EDIT THE keywords.txt FILE DIRECTLY. -# For an explanation of these tags, see Token.java +# For an explanation of these tags, see Token.java # trunk/processing/app/src/processing/app/syntax/Token.java ADD LITERAL2 blend_ -ALIGN_CENTER LITERAL2 -ALIGN_LEFT LITERAL2 -ALIGN_RIGHT LITERAL2 +ALIGN_CENTER LITERAL2 +ALIGN_LEFT LITERAL2 +ALIGN_RIGHT LITERAL2 ALPHA LITERAL2 ALPHA_MASK LITERAL2 ALT LITERAL2 -AMBIENT LITERAL2 +AMBIENT LITERAL2 ARC LITERAL2 createShape_ ARROW LITERAL2 cursor_ ARGB LITERAL2 @@ -24,7 +25,7 @@ BLUR LITERAL2 filter_ BOTTOM LITERAL2 textAlign_ BOX LITERAL2 createShape_ BURN LITERAL2 blend_ -CENTER LITERAL2 +CENTER LITERAL2 CHATTER LITERAL2 CHORD LITERAL2 arc_ CLAMP LITERAL2 @@ -88,7 +89,7 @@ GIF LITERAL2 GRAY LITERAL2 filter_ GREEN_MASK LITERAL2 GROUP LITERAL2 -HALF LITERAL2 +HALF LITERAL2 HALF_PI LITERAL2 HALF_PI HAND LITERAL2 cursor_ HARD_LIGHT LITERAL2 blend_ @@ -97,7 +98,7 @@ HSB LITERAL2 colorMode_ IMAGE LITERAL2 textureMode_ INVERT LITERAL2 filter_ JAVA2D LITERAL2 size_ -JPEG LITERAL2 +JPEG LITERAL2 LEFT LITERAL2 keyCode LIGHTEST LITERAL2 blend_ LINE LITERAL2 createShape_ @@ -105,18 +106,18 @@ LINES LITERAL2 beginShape_ LINUX LITERAL2 MACOSX LITERAL2 MAX_FLOAT LITERAL2 -MAX_INT LITERAL2 +MAX_INT LITERAL2 MIN_FLOAT LITERAL2 MIN_INT LITERAL2 MITER LITERAL2 stokeJoin_ MODEL LITERAL2 textMode_ MOVE LITERAL2 cursor_ MULTIPLY LITERAL2 blend_ -NORMAL LITERAL2 +NORMAL LITERAL2 NORMALIZED LITERAL2 textureMode_ NO_DEPTH_TEST LITERAL2 NTSC LITERAL2 -ONE LITERAL2 +ONE LITERAL2 OPAQUE LITERAL2 filter_ OPEN LITERAL2 ORTHOGRAPHIC LITERAL2 @@ -127,13 +128,13 @@ P2D LITERAL2 size_ P3D LITERAL2 size_ PERSPECTIVE LITERAL2 PI LITERAL2 PI -PIE LITERAL2 +PIE LITERAL2 PIXEL_CENTER LITERAL2 POINT LITERAL2 -POINTS LITERAL2 +POINTS LITERAL2 POSTERIZE LITERAL2 filter_ PRESS LITERAL2 -PROBLEM LITERAL2 +PROBLEM LITERAL2 PROJECT LITERAL2 strokeCap_ QUAD LITERAL2 createShape_ QUAD_STRIP LITERAL2 beginShape_ @@ -146,23 +147,23 @@ RECT LITERAL2 RED_MASK LITERAL2 RELEASE LITERAL2 REPEAT LITERAL2 -REPLACE LITERAL2 +REPLACE LITERAL2 RETURN LITERAL2 RGB LITERAL2 colorMode_ RIGHT LITERAL2 keyCode ROUND LITERAL2 strokeCap_ SCREEN LITERAL2 blend_ -SECAM LITERAL2 +SECAM LITERAL2 SHAPE LITERAL2 textMode_ SHIFT LITERAL2 -SPAN LITERAL2 fullScreen_ +SPAN LITERAL2 fullScreen_ SPECULAR LITERAL2 SPHERE LITERAL2 createShape_ SOFT_LIGHT LITERAL2 blend_ SQUARE LITERAL2 strokeCap_ SUBTRACT LITERAL2 blend_ SVG LITERAL2 -SVIDEO LITERAL2 +SVIDEO LITERAL2 TAB LITERAL2 keyCode TARGA LITERAL2 TAU LITERAL2 TAU @@ -181,17 +182,17 @@ TWO LITERAL2 TWO_PI LITERAL2 TWO_PI UP LITERAL2 keyCode WAIT LITERAL2 cursor_ -WHITESPACE LITERAL2 +WHITESPACE LITERAL2 # Java keywords (void, import, , etc.) - + abstract KEYWORD1 break KEYWORD1 break class KEYWORD1 class continue KEYWORD1 continue -default KEYWORD1 default -enum KEYWORD1 +default KEYWORD1 default +enum KEYWORD1 extends KEYWORD1 extends false KEYWORD1 false final KEYWORD1 final @@ -199,17 +200,17 @@ finally KEYWORD1 implements KEYWORD1 implements import KEYWORD1 import instanceof KEYWORD1 -interface KEYWORD1 +interface KEYWORD1 native KEYWORD1 new KEYWORD1 new null KEYWORD1 null -package KEYWORD1 +package KEYWORD1 private KEYWORD1 private -protected KEYWORD1 +protected KEYWORD1 public KEYWORD1 public static KEYWORD1 static -strictfp KEYWORD1 -throws KEYWORD1 +strictfp KEYWORD1 +throws KEYWORD1 transient KEYWORD1 true KEYWORD1 true void KEYWORD1 void @@ -220,7 +221,7 @@ volatile KEYWORD1 assert KEYWORD6 case KEYWORD6 case -return KEYWORD6 return +return KEYWORD6 return super KEYWORD6 super this KEYWORD6 this throw KEYWORD6 @@ -230,18 +231,17 @@ throw KEYWORD6 Array KEYWORD5 Array ArrayList KEYWORD5 ArrayList -Boolean KEYWORD5 -Byte KEYWORD5 +Boolean KEYWORD5 +Byte KEYWORD5 BufferedReader KEYWORD5 BufferedReader -Character KEYWORD5 +Character KEYWORD5 Class KEYWORD5 class -Double KEYWORD5 -Float KEYWORD5 -Integer KEYWORD5 +Float KEYWORD5 +Integer KEYWORD5 HashMap KEYWORD5 HashMap PrintWriter KEYWORD5 PrintWriter String KEYWORD5 String -StringBuffer KEYWORD5 +StringBuffer KEYWORD5 StringBuilder KEYWORD5 Thread KEYWORD5 boolean KEYWORD5 boolean @@ -252,7 +252,6 @@ double KEYWORD5 double float KEYWORD5 float int KEYWORD5 int long KEYWORD5 long -short KEYWORD5 # Flow structures @@ -315,6 +314,14 @@ substring FUNCTION2 String_substring_ toLowerCase FUNCTION2 String_toLowerCase_ toUpperCase FUNCTION2 String_toUpperCase_ +getDouble FUNCTION2 +getLong FUNCTION2 +getColumnTitles FUNCTION2 +getColumnTypes FUNCTION2 +getColumnType FUNCTION2 +setDouble FUNCTION2 +setLong FUNCTION2 + length KEYWORD2 String @@ -378,544 +385,554 @@ pixelHeight KEYWORD4 pixelHeight # # THE TEXT BELOW IS AUTO-GENERATED # -# SO -# DON'T -# TOUCH +# SO +# DON'T +# TOUCH # IT -abs FUNCTION1 abs_ -acos FUNCTION1 acos_ -alpha FUNCTION1 alpha_ -ambient FUNCTION1 ambient_ -ambientLight FUNCTION1 ambientLight_ -append FUNCTION1 append_ -applyMatrix FUNCTION1 applyMatrix_ -arc FUNCTION1 arc_ -arrayCopy FUNCTION1 arrayCopy_ -asin FUNCTION1 asin_ -atan FUNCTION1 atan_ -atan2 FUNCTION1 atan2_ -background FUNCTION1 background_ -beginCamera FUNCTION1 beginCamera_ -beginContour FUNCTION1 beginContour_ -beginRaw FUNCTION1 beginRaw_ -beginRecord FUNCTION1 beginRecord_ -beginShape FUNCTION1 beginShape_ -bezier FUNCTION1 bezier_ -bezierDetail FUNCTION1 bezierDetail_ +JSONObject KEYWORD5 JSONObject +cross FUNCTION2 PVector_cross_ +hasValue FUNCTION2 StringList_hasValue_ +PVector KEYWORD5 PVector +endCamera FUNCTION1 endCamera_ +min FUNCTION1 min_ +printCamera FUNCTION1 printCamera_ +strokeWeight FUNCTION1 strokeWeight_ +scale FUNCTION1 scale_ +copy FUNCTION2 PImage_copy_ +get FUNCTION2 IntList_get_ +mouseDragged FUNCTION4 mouseDragged +setString FUNCTION2 JSONArray_setString_ +setString FUNCTION2 TableRow_setString_ +keyReleased FUNCTION4 keyReleased +frameRate FUNCTION1 frameRate_ +PShape KEYWORD5 PShape +hasKey FUNCTION2 FloatDict_hasKey_ +randomSeed FUNCTION1 randomSeed_ +sortReverse FUNCTION2 FloatList_sortReverse_ +getParent FUNCTION2 XML_getParent_ +loadPixels FUNCTION2 PImage_loadPixels_ +save FUNCTION2 PImage_save_ +increment FUNCTION2 IntList_increment_ +hue FUNCTION1 hue_ bezierPoint FUNCTION1 bezierPoint_ -bezierTangent FUNCTION1 bezierTangent_ -bezierVertex FUNCTION1 bezierVertex_ -binary FUNCTION1 binary_ -blend FUNCTION1 blend_ -blendColor FUNCTION1 blendColor_ -blendMode FUNCTION1 blendMode_ -blue FUNCTION1 blue_ -box FUNCTION1 box_ -brightness FUNCTION1 brightness_ -camera FUNCTION1 camera_ -ceil FUNCTION1 ceil_ -clear FUNCTION1 clear_ -clip FUNCTION1 clip_ -color FUNCTION1 color_ -colorMode FUNCTION1 colorMode_ -concat FUNCTION1 concat_ -constrain FUNCTION1 constrain_ -copy FUNCTION1 copy_ -cos FUNCTION1 cos_ -createFont FUNCTION1 createFont_ -createGraphics FUNCTION1 createGraphics_ -createImage FUNCTION1 createImage_ -createInput FUNCTION1 createInput_ -createOutput FUNCTION1 createOutput_ -createReader FUNCTION1 createReader_ -createShape FUNCTION1 createShape_ -createWriter FUNCTION1 createWriter_ +getFloat FUNCTION2 JSONArray_getFloat_ +degrees FUNCTION1 degrees_ +loadPixels FUNCTION1 loadPixels_ cursor FUNCTION1 cursor_ -curve FUNCTION1 curve_ +beginContour FUNCTION1 beginContour_ +loadTable FUNCTION1 loadTable_ +keyPressed KEYWORD4 keyPressed +resetMatrix FUNCTION2 PShape_resetMatrix_ +dist FUNCTION1 dist_ +sub FUNCTION2 IntList_sub_ +removeColumn FUNCTION2 Table_removeColumn_ +updatePixels FUNCTION1 updatePixels_ +set FUNCTION2 FloatDict_set_ +disableStyle FUNCTION2 PShape_disableStyle_ +saveStream FUNCTION1 saveStream_ +mask FUNCTION2 PImage_mask_ +set FUNCTION2 StringList_set_ +createWriter FUNCTION1 createWriter_ +join FUNCTION1 join_ +findRow FUNCTION2 Table_findRow_ +append FUNCTION2 IntList_append_ +loadXML FUNCTION1 loadXML_ +splice FUNCTION1 splice_ +mult FUNCTION2 IntList_mult_ +mult FUNCTION2 PVector_mult_ +noiseDetail FUNCTION1 noiseDetail_ curveDetail FUNCTION1 curveDetail_ -curvePoint FUNCTION1 curvePoint_ -curveTangent FUNCTION1 curveTangent_ -curveTightness FUNCTION1 curveTightness_ -curveVertex FUNCTION1 curveVertex_ +textLeading FUNCTION1 textLeading_ +noCursor FUNCTION1 noCursor_ +sphere FUNCTION1 sphere_ day FUNCTION1 day_ -degrees FUNCTION1 degrees_ -directionalLight FUNCTION1 directionalLight_ -displayDensity FUNCTION1 displayDensity_ -displayHeight KEYWORD4 displayHeight -displayWidth KEYWORD4 displayWidth -dist FUNCTION1 dist_ -draw FUNCTION4 draw -ellipse FUNCTION1 ellipse_ -ellipseMode FUNCTION1 ellipseMode_ -emissive FUNCTION1 emissive_ -endCamera FUNCTION1 endCamera_ -endContour FUNCTION1 endContour_ -endRaw FUNCTION1 endRaw_ -endRecord FUNCTION1 endRecord_ -endShape FUNCTION1 endShape_ -exit FUNCTION1 exit_ -exp FUNCTION1 exp_ +month FUNCTION1 month_ +IntDict KEYWORD5 IntDict +popMatrix FUNCTION1 popMatrix_ +size FUNCTION2 StringList_size_ +loadImage FUNCTION1 loadImage_ +shininess FUNCTION1 shininess_ +setJSONArray FUNCTION2 JSONObject_setJSONArray_ +values FUNCTION2 IntDict_values_ +scale FUNCTION2 PShape_scale_ +ceil FUNCTION1 ceil_ +getFloat FUNCTION2 TableRow_getFloat_ +randomGaussian FUNCTION1 randomGaussian_ +setContent FUNCTION2 XML_setContent_ +size FUNCTION1 size_ +clear FUNCTION2 StringList_clear_ +mouseX KEYWORD4 mouseX expand FUNCTION1 expand_ -fill FUNCTION1 fill_ -filter FUNCTION1 filter_ -FloatDict KEYWORD5 FloatDict -add FUNCTION2 FloatDict_add_ -clear FUNCTION2 FloatDict_clear_ -div FUNCTION2 FloatDict_div_ -get FUNCTION2 FloatDict_get_ -hasKey FUNCTION2 FloatDict_hasKey_ -keyArray FUNCTION2 FloatDict_keyArray_ -keys FUNCTION2 FloatDict_keys_ -mult FUNCTION2 FloatDict_mult_ -remove FUNCTION2 FloatDict_remove_ -set FUNCTION2 FloatDict_set_ -size FUNCTION2 FloatDict_size_ -sortKeys FUNCTION2 FloatDict_sortKeys_ -sortKeysReverse FUNCTION2 FloatDict_sortKeysReverse_ -sortValues FUNCTION2 FloatDict_sortValues_ -sortValuesReverse FUNCTION2 FloatDict_sortValuesReverse_ -sub FUNCTION2 FloatDict_sub_ -valueArray FUNCTION2 FloatDict_valueArray_ -values FUNCTION2 FloatDict_values_ -FloatList KEYWORD5 FloatList -add FUNCTION2 FloatList_add_ -append FUNCTION2 FloatList_append_ +sort FUNCTION2 Table_sort_ +setBoolean FUNCTION2 JSONArray_setBoolean_ +pushMatrix FUNCTION1 pushMatrix_ +mouseY KEYWORD4 mouseY +lerpColor FUNCTION1 lerpColor_ array FUNCTION2 FloatList_array_ -clear FUNCTION2 FloatList_clear_ -div FUNCTION2 FloatList_div_ -get FUNCTION2 FloatList_get_ -hasValue FUNCTION2 FloatList_hasValue_ -max FUNCTION2 FloatList_max_ -min FUNCTION2 FloatList_min_ +ellipse FUNCTION1 ellipse_ +stroke FUNCTION1 stroke_ +imageMode FUNCTION1 imageMode_ +settings FUNCTION4 settings +pixelWidth FUNCTION4 pixelWidth +getName FUNCTION2 XML_getName_ +setVertex FUNCTION2 PShape_setVertex_ mult FUNCTION2 FloatList_mult_ remove FUNCTION2 FloatList_remove_ -reverse FUNCTION2 FloatList_reverse_ -set FUNCTION2 FloatList_set_ -shuffle FUNCTION2 FloatList_shuffle_ -size FUNCTION2 FloatList_size_ -sort FUNCTION2 FloatList_sort_ -sortReverse FUNCTION2 FloatList_sortReverse_ -sub FUNCTION2 FloatList_sub_ -floor FUNCTION1 floor_ +createGraphics FUNCTION1 createGraphics_ +min FUNCTION2 IntList_min_ +rows FUNCTION2 Table_rows_ focused KEYWORD4 focused -frameCount KEYWORD4 frameCount -frameRate KEYWORD4 frameRate -frameRate FUNCTION1 frameRate_ -frustum FUNCTION1 frustum_ -fullScreen FUNCTION1 fullScreen_ +endContour FUNCTION1 endContour_ +hasValue FUNCTION2 IntList_hasValue_ +setString FUNCTION2 Table_setString_ +sortKeysReverse FUNCTION2 FloatDict_sortKeysReverse_ +saveStrings FUNCTION1 saveStrings_ +resetMatrix FUNCTION1 resetMatrix_ +set FUNCTION2 PImage_set_ +add FUNCTION2 IntList_add_ +removeChild FUNCTION2 XML_removeChild_ +key KEYWORD4 key +requestImage FUNCTION1 requestImage_ +array FUNCTION2 StringList_array_ +saveBytes FUNCTION1 saveBytes_ get FUNCTION1 get_ -green FUNCTION1 green_ -HALF_PI LITERAL2 HALF_PI -hex FUNCTION1 hex_ -hint FUNCTION1 hint_ +emissive FUNCTION1 emissive_ +getColumnCount FUNCTION2 Table_getColumnCount_ +noStroke FUNCTION1 noStroke_ +textureWrap FUNCTION1 textureWrap_ +addChild FUNCTION2 XML_addChild_ +setMag FUNCTION2 PVector_setMag_ +FloatDict KEYWORD5 FloatDict +matchRow FUNCTION2 Table_matchRow_ +div FUNCTION2 FloatList_div_ +getBoolean FUNCTION2 JSONObject_getBoolean_ +vertex FUNCTION1 vertex_ +setFloat FUNCTION2 JSONObject_setFloat_ +copy FUNCTION2 PVector_copy_ +remove FUNCTION2 StringDict_remove_ +lower FUNCTION2 StringList_lower_ +format FUNCTION2 XML_format_ +setStroke FUNCTION2 PShape_setStroke_ +clear FUNCTION2 FloatList_clear_ +isNull FUNCTION2 JSONObject_isNull_ +mousePressed FUNCTION4 mousePressed +sortValuesReverse FUNCTION2 FloatDict_sortValuesReverse_ +sortValuesReverse FUNCTION2 StringDict_sortValuesReverse_ +selectInput FUNCTION1 selectInput_ +lerp FUNCTION2 PVector_lerp_ +div FUNCTION2 IntList_div_ +sort FUNCTION2 FloatList_sort_ +setInt FUNCTION2 JSONArray_setInt_ +createReader FUNCTION1 createReader_ +strokeJoin FUNCTION1 strokeJoin_ hour FUNCTION1 hour_ -hue FUNCTION1 hue_ -image FUNCTION1 image_ -imageMode FUNCTION1 imageMode_ -IntDict KEYWORD5 IntDict -add FUNCTION2 IntDict_add_ -clear FUNCTION2 IntDict_clear_ -div FUNCTION2 IntDict_div_ -get FUNCTION2 IntDict_get_ -hasKey FUNCTION2 IntDict_hasKey_ -increment FUNCTION2 IntDict_increment_ -keyArray FUNCTION2 IntDict_keyArray_ -keys FUNCTION2 IntDict_keys_ -mult FUNCTION2 IntDict_mult_ -remove FUNCTION2 IntDict_remove_ -set FUNCTION2 IntDict_set_ -size FUNCTION2 IntDict_size_ -sortKeys FUNCTION2 IntDict_sortKeys_ -sortKeysReverse FUNCTION2 IntDict_sortKeysReverse_ -sortValues FUNCTION2 IntDict_sortValues_ +getRowCount FUNCTION2 Table_getRowCount_ +hasAttribute FUNCTION2 XML_hasAttribute_ +setFloat FUNCTION2 TableRow_setFloat_ +values FUNCTION2 FloatDict_values_ +getInt FUNCTION2 TableRow_getInt_ +getString FUNCTION2 JSONObject_getString_ +round FUNCTION1 round_ +strokeCap FUNCTION1 strokeCap_ +sortKeysReverse FUNCTION2 StringDict_sortKeysReverse_ +ortho FUNCTION1 ortho_ +getVertexCount FUNCTION2 PShape_getVertexCount_ +parseJSONObject FUNCTION1 parseJSONObject_ +textFont FUNCTION1 textFont_ +clear FUNCTION1 clear_ +getChildren FUNCTION2 XML_getChildren_ +loadBytes FUNCTION1 loadBytes_ +ambient FUNCTION1 ambient_ sortValuesReverse FUNCTION2 IntDict_sortValuesReverse_ -sub FUNCTION2 IntDict_sub_ -valueArray FUNCTION2 IntDict_valueArray_ -values FUNCTION2 IntDict_values_ -IntList KEYWORD5 IntList -add FUNCTION2 IntList_add_ -append FUNCTION2 IntList_append_ -array FUNCTION2 IntList_array_ -clear FUNCTION2 IntList_clear_ -div FUNCTION2 IntList_div_ -get FUNCTION2 IntList_get_ -hasValue FUNCTION2 IntList_hasValue_ -increment FUNCTION2 IntList_increment_ -max FUNCTION2 IntList_max_ -min FUNCTION2 IntList_min_ -mult FUNCTION2 IntList_mult_ +keyTyped FUNCTION4 keyTyped +HALF_PI LITERAL2 HALF_PI +loadFont FUNCTION1 loadFont_ +frameRate FUNCTION1 frameRate_ +map FUNCTION1 map_ +min FUNCTION2 FloatList_min_ +mag FUNCTION1 mag_ +minute FUNCTION1 minute_ +beginRecord FUNCTION1 beginRecord_ +add FUNCTION2 FloatList_add_ +alpha FUNCTION1 alpha_ +clear FUNCTION2 StringDict_clear_ +noClip FUNCTION1 noClip_ +TWO_PI LITERAL2 TWO_PI +normalize FUNCTION2 PVector_normalize_ +abs FUNCTION1 abs_ remove FUNCTION2 IntList_remove_ +saveXML FUNCTION1 saveXML_ +blend FUNCTION2 PImage_blend_ +sortKeys FUNCTION2 FloatDict_sortKeys_ +blue FUNCTION1 blue_ reverse FUNCTION2 IntList_reverse_ -set FUNCTION2 IntList_set_ -shuffle FUNCTION2 IntList_shuffle_ -size FUNCTION2 IntList_size_ -sort FUNCTION2 IntList_sort_ -sortReverse FUNCTION2 IntList_sortReverse_ -sub FUNCTION2 IntList_sub_ -join FUNCTION1 join_ -JSONArray KEYWORD5 JSONArray -append FUNCTION2 JSONArray_append_ -getBoolean FUNCTION2 JSONArray_getBoolean_ -getFloat FUNCTION2 JSONArray_getFloat_ -getInt FUNCTION2 JSONArray_getInt_ +getContent FUNCTION2 XML_getFloatContent_ +keys FUNCTION2 StringDict_keys_ +clear FUNCTION2 FloatDict_clear_ +year FUNCTION1 year_ +nfc FUNCTION1 nfc_ +rotate FUNCTION1 rotate_ +getChild FUNCTION2 XML_getChild_ +parseJSONArray FUNCTION1 parseJSONArray_ +pixels KEYWORD4 pixels getIntArray FUNCTION2 JSONArray_getIntArray_ +saveFrame FUNCTION1 saveFrame_ +getFloat FUNCTION2 JSONObject_getFloat_ +size FUNCTION2 StringDict_size_ +splitTokens FUNCTION1 splitTokens_ +mult FUNCTION2 IntDict_mult_ +atan FUNCTION1 atan_ +setName FUNCTION2 XML_setName_ +XML KEYWORD5 XML +circle FUNCTION1 circle_ +bezierDetail FUNCTION1 bezierDetail_ +draw FUNCTION4 draw +getContent FUNCTION2 XML_getContent_ +cos FUNCTION1 cos_ +sq FUNCTION1 sq_ +TAU LITERAL2 TAU +delay FUNCTION1 delay_ +fullScreen FUNCTION1 fullScreen_ +endRaw FUNCTION1 endRaw_ +setVisible FUNCTION2 PShape_setVisible_ +increment FUNCTION2 IntDict_increment_ +shuffle FUNCTION2 IntList_shuffle_ getJSONArray FUNCTION2 JSONArray_getJSONArray_ -getJSONObject FUNCTION2 JSONArray_getJSONObject_ -getString FUNCTION2 JSONArray_getString_ -getStringArray FUNCTION2 JSONArray_getStringArray_ -remove FUNCTION2 JSONArray_remove_ -setBoolean FUNCTION2 JSONArray_setBoolean_ +translate FUNCTION1 translate_ +sort FUNCTION2 IntList_sort_ setFloat FUNCTION2 JSONArray_setFloat_ -setInt FUNCTION2 JSONArray_setInt_ -setJSONArray FUNCTION2 JSONArray_setJSONArray_ -setJSONObject FUNCTION2 JSONArray_setJSONObject_ -setString FUNCTION2 JSONArray_setString_ -size FUNCTION2 JSONArray_size_ -JSONObject KEYWORD5 JSONObject -getBoolean FUNCTION2 JSONObject_getBoolean_ -getFloat FUNCTION2 JSONObject_getFloat_ -getInt FUNCTION2 JSONObject_getInt_ -getJSONArray FUNCTION2 JSONObject_getJSONArray_ -getJSONObject FUNCTION2 JSONObject_getJSONObject_ -getString FUNCTION2 JSONObject_getString_ +nfp FUNCTION1 nfp_ +upper FUNCTION2 StringList_upper_ +setInt FUNCTION2 TableRow_setInt_ +hasKey FUNCTION2 IntDict_hasKey_ +blendMode FUNCTION1 blendMode_ +sin FUNCTION1 sin_ +mouseButton KEYWORD4 mouseButton +QUARTER_PI LITERAL2 QUARTER_PI +clip FUNCTION1 clip_ +sub FUNCTION2 FloatList_sub_ +getInt FUNCTION2 JSONArray_getInt_ +getBoolean FUNCTION2 JSONArray_getBoolean_ +set FUNCTION2 IntDict_set_ +displayHeight KEYWORD4 displayHeight +findRows FUNCTION2 Table_findRows_ +hex FUNCTION1 hex_ +TableRow KEYWORD5 TableRow +PI LITERAL2 PI +updatePixels FUNCTION2 PImage_updatePixels_ +beginShape FUNCTION1 beginShape_ +StringDict KEYWORD5 StringDict +mult FUNCTION2 FloatDict_mult_ +append FUNCTION2 FloatList_append_ +trim FUNCTION1 trim_ +pmouseX KEYWORD4 pmouseX +textDescent FUNCTION1 textDescent_ +createShape FUNCTION1 createShape_ +keyArray FUNCTION2 FloatDict_keyArray_ +get FUNCTION2 FloatList_get_ +getStringColumn FUNCTION2 Table_getStringColumn_ +pmouseY KEYWORD4 pmouseY +pixels KEYWORD2 PImage_pixels +nfs FUNCTION1 nfs_ setBoolean FUNCTION2 JSONObject_setBoolean_ -setFloat FUNCTION2 JSONObject_setFloat_ -setInt FUNCTION2 JSONObject_setInt_ -setJSONArray FUNCTION2 JSONObject_setJSONArray_ -setJSONObject FUNCTION2 JSONObject_setJSONObject_ -setString FUNCTION2 JSONObject_setString_ -key KEYWORD4 key -keyCode KEYWORD4 keyCode +JSONArray KEYWORD5 JSONArray +displayDensity FUNCTION1 displayDensity_ +createFont FUNCTION1 createFont_ +applyMatrix FUNCTION1 applyMatrix_ keyPressed FUNCTION4 keyPressed -keyPressed KEYWORD4 keyPressed -keyReleased FUNCTION4 keyReleased -keyTyped FUNCTION4 keyTyped -launch FUNCTION1 launch_ -lerp FUNCTION1 lerp_ -lerpColor FUNCTION1 lerpColor_ -lightFalloff FUNCTION1 lightFalloff_ -lights FUNCTION1 lights_ -lightSpecular FUNCTION1 lightSpecular_ -line FUNCTION1 line_ -loadBytes FUNCTION1 loadBytes_ -loadFont FUNCTION1 loadFont_ -loadImage FUNCTION1 loadImage_ -loadJSONArray FUNCTION1 loadJSONArray_ -loadJSONObject FUNCTION1 loadJSONObject_ -loadPixels FUNCTION1 loadPixels_ -loadShader FUNCTION1 loadShader_ -loadShape FUNCTION1 loadShape_ -loadStrings FUNCTION1 loadStrings_ -loadTable FUNCTION1 loadTable_ -loadXML FUNCTION1 loadXML_ -log FUNCTION1 log_ -loop FUNCTION1 loop_ -mag FUNCTION1 mag_ -map FUNCTION1 map_ -match FUNCTION1 match_ +getColumnTitle FUNCTION2 TableRow_getColumnTitle_ +getString FUNCTION2 XML_getString_ +point FUNCTION1 point_ +background FUNCTION1 background_ +pixelDensity FUNCTION1 pixelDensity_ +set FUNCTION2 PVector_set_ +triangle FUNCTION1 triangle_ +rect FUNCTION1 rect_ +shape FUNCTION1 shape_ +saveTable FUNCTION1 saveTable_ matchAll FUNCTION1 matchAll_ +get FUNCTION2 StringDict_get_ +noLights FUNCTION1 noLights_ max FUNCTION1 max_ -millis FUNCTION1 millis_ -min FUNCTION1 min_ -minute FUNCTION1 minute_ -modelX FUNCTION1 modelX_ -modelY FUNCTION1 modelY_ -modelZ FUNCTION1 modelZ_ -month FUNCTION1 month_ -mouseButton KEYWORD4 mouseButton -mouseClicked FUNCTION4 mouseClicked -mouseDragged FUNCTION4 mouseDragged -mouseMoved FUNCTION4 mouseMoved -mousePressed FUNCTION4 mousePressed -mousePressed KEYWORD4 mousePressed -mouseReleased FUNCTION4 mouseReleased +keys FUNCTION2 FloatDict_keys_ mouseWheel FUNCTION4 mouseWheel -mouseX KEYWORD4 mouseX -mouseY KEYWORD4 mouseY -nf FUNCTION1 nf_ -nfc FUNCTION1 nfc_ -nfp FUNCTION1 nfp_ -nfs FUNCTION1 nfs_ -noClip FUNCTION1 noClip_ -noCursor FUNCTION1 noCursor_ -noFill FUNCTION1 noFill_ -noise FUNCTION1 noise_ -noiseDetail FUNCTION1 noiseDetail_ -noiseSeed FUNCTION1 noiseSeed_ -noLights FUNCTION1 noLights_ -noLoop FUNCTION1 noLoop_ -norm FUNCTION1 norm_ -normal FUNCTION1 normal_ -noSmooth FUNCTION1 noSmooth_ -noStroke FUNCTION1 noStroke_ -noTint FUNCTION1 noTint_ -ortho FUNCTION1 ortho_ -parseJSONArray FUNCTION1 parseJSONArray_ -parseJSONObject FUNCTION1 parseJSONObject_ -parseXML FUNCTION1 parseXML_ -perspective FUNCTION1 perspective_ -PFont KEYWORD5 PFont -list FUNCTION1 PFont_list_ -PGraphics KEYWORD5 PGraphics -beginDraw FUNCTION2 PGraphics_beginDraw_ -endDraw FUNCTION2 PGraphics_endDraw_ -PI LITERAL2 PI +set FUNCTION1 set_ PImage KEYWORD5 PImage -blend FUNCTION2 PImage_blend_ -copy FUNCTION2 PImage_copy_ -filter FUNCTION2 PImage_filter_ +printProjection FUNCTION1 printProjection_ +popStyle FUNCTION1 popStyle_ +lerp FUNCTION1 lerp_ +clearRows FUNCTION2 Table_clearRows_ +perspective FUNCTION1 perspective_ +print FUNCTION1 print_ get FUNCTION2 PImage_get_ -loadPixels FUNCTION2 PImage_loadPixels_ -mask FUNCTION2 PImage_mask_ -pixels KEYWORD2 PImage_pixels -resize FUNCTION2 PImage_resize_ -save FUNCTION2 PImage_save_ -set FUNCTION2 PImage_set_ -updatePixels FUNCTION2 PImage_updatePixels_ -pixelDensity FUNCTION1 pixelDensity_ -pixelHeight FUNCTION1 pixelHeight_ -pixels KEYWORD4 pixels -pixelWidth KEYWORD4 pixelWidth -pmouseX KEYWORD4 pmouseX -pmouseY KEYWORD4 pmouseY -point FUNCTION1 point_ -pointLight FUNCTION1 pointLight_ -popMatrix FUNCTION1 popMatrix_ -popStyle FUNCTION1 popStyle_ -pow FUNCTION1 pow_ -print FUNCTION1 print_ -printArray FUNCTION1 printArray_ -printCamera FUNCTION1 printCamera_ -println FUNCTION1 println_ -printMatrix FUNCTION1 printMatrix_ -printProjection FUNCTION1 printProjection_ -PShader KEYWORD5 PShader -PShader FUNCTION2 PShader_set_ -PShape KEYWORD5 PShape +addColumn FUNCTION2 Table_addColumn_ +fill FUNCTION1 fill_ +loadJSONObject FUNCTION1 loadJSONObject_ +filter FUNCTION2 PImage_filter_ +getFloat FUNCTION2 Table_getFloat_ +redraw FUNCTION1 redraw_ +sortKeys FUNCTION2 StringDict_sortKeys_ +textAlign FUNCTION1 textAlign_ +append FUNCTION2 StringList_append_ +bezier FUNCTION1 bezier_ +size FUNCTION2 FloatDict_size_ addChild FUNCTION2 PShape_addChild_ -beginContour FUNCTION2 PShape_beginContour_ -beginShape FUNCTION2 PShape_beginShape_ -disableStyle FUNCTION2 PShape_disableStyle_ -enableStyle FUNCTION2 PShape_enableStyle_ -endContour FUNCTION2 PShape_endContour_ -endShape FUNCTION2 PShape_endShape_ -getChild FUNCTION2 PShape_getChild_ -getChildCount FUNCTION2 PShape_getChildCount_ -getVertex FUNCTION2 PShape_getVertex_ -getVertexCount FUNCTION2 PShape_getVertexCount_ -isVisible FUNCTION2 PShape_isVisible_ -resetMatrix FUNCTION2 PShape_resetMatrix_ -rotate FUNCTION2 PShape_rotate_ -rotateX FUNCTION2 PShape_rotateX_ -rotateY FUNCTION2 PShape_rotateY_ -rotateZ FUNCTION2 PShape_rotateZ_ -scale FUNCTION2 PShape_scale_ -setFill FUNCTION2 PShape_setFill_ -setStroke FUNCTION2 PShape_setStroke_ -setVertex FUNCTION2 PShape_setVertex_ -setVisible FUNCTION2 PShape_setVisible_ -translate FUNCTION2 PShape_translate_ -pushMatrix FUNCTION1 pushMatrix_ -pushStyle FUNCTION1 pushStyle_ -PVector KEYWORD5 PVector -add FUNCTION2 PVector_add_ +setFloat FUNCTION2 XML_setFloat_ +smooth FUNCTION1 smooth_ +blendColor FUNCTION1 blendColor_ +displayWidth KEYWORD4 displayWidth angleBetween FUNCTION2 PVector_angleBetween_ -array FUNCTION2 PVector_array_ -copy FUNCTION2 PVector_copy_ -cross FUNCTION2 PVector_cross_ -dist FUNCTION2 PVector_dist_ +removeRow FUNCTION2 Table_removeRow_ div FUNCTION2 PVector_div_ -dot FUNCTION2 PVector_dot_ -fromAngle FUNCTION2 PVector_fromAngle_ -get FUNCTION2 PVector_get_ -heading FUNCTION2 PVector_heading_ -lerp FUNCTION2 PVector_lerp_ -limit FUNCTION2 PVector_limit_ -mag FUNCTION2 PVector_mag_ -magSq FUNCTION2 PVector_magSq_ -mult FUNCTION2 PVector_mult_ -normalize FUNCTION2 PVector_normalize_ -random2D FUNCTION2 PVector_random2D_ -random3D FUNCTION2 PVector_random3D_ +println FUNCTION1 println_ +add FUNCTION2 FloatDict_add_ +brightness FUNCTION1 brightness_ +loadJSONArray FUNCTION1 loadJSONArray_ +tan FUNCTION1 tan_ +printMatrix FUNCTION1 printMatrix_ +lights FUNCTION1 lights_ +loadShape FUNCTION1 loadShape_ +random FUNCTION1 random_ +shuffle FUNCTION2 FloatList_shuffle_ rotate FUNCTION2 PVector_rotate_ -set FUNCTION2 PVector_set_ -setMag FUNCTION2 PVector_setMag_ -sub FUNCTION2 PVector_sub_ -quad FUNCTION1 quad_ +getJSONObject FUNCTION2 JSONObject_getJSONObject_ quadraticVertex FUNCTION1 quadraticVertex_ -QUARTER_PI LITERAL2 QUARTER_PI +sort FUNCTION2 StringList_sort_ +bezierVertex FUNCTION1 bezierVertex_ +exp FUNCTION1 exp_ +setJSONArray FUNCTION2 JSONArray_setJSONArray_ +setString FUNCTION2 JSONObject_setString_ +textureMode FUNCTION1 textureMode_ +specular FUNCTION1 specular_ +noSmooth FUNCTION1 noSmooth_ +pow FUNCTION1 pow_ +blend FUNCTION1 blend_ +listChildren FUNCTION2 XML_listChildren_ +keyArray FUNCTION2 IntDict_keyArray_ +green FUNCTION1 green_ +magSq FUNCTION2 PVector_magSq_ +listAttributes FUNCTION2 XML_listAttributes_ +createOutput FUNCTION1 createOutput_ +div FUNCTION2 IntDict_div_ +isNull FUNCTION2 JSONArray_isNull_ +getContent FUNCTION2 XML_getIntContent_ +setString FUNCTION2 XML_setString_ +get FUNCTION2 StringList_get_ +translate FUNCTION2 PShape_translate_ +concat FUNCTION1 concat_ +bezierTangent FUNCTION1 bezierTangent_ +mouseReleased FUNCTION4 mouseReleased +arrayCopy FUNCTION1 arrayCopy_ +beginCamera FUNCTION1 beginCamera_ +asin FUNCTION1 asin_ +remove FUNCTION2 IntDict_remove_ +lightFalloff FUNCTION1 lightFalloff_ +color FUNCTION1 color_ +shader FUNCTION1 shader_ +size FUNCTION2 IntDict_size_ +beginShape FUNCTION2 PShape_beginShape_ +getStringArray FUNCTION2 JSONArray_getStringArray_ +reverse FUNCTION2 FloatList_reverse_ +get FUNCTION2 FloatDict_get_ +rotateZ FUNCTION1 rotateZ_ +sortValues FUNCTION2 FloatDict_sortValues_ radians FUNCTION1 radians_ -random FUNCTION1 random_ -randomGaussian FUNCTION1 randomGaussian_ -randomSeed FUNCTION1 randomSeed_ -rect FUNCTION1 rect_ -rectMode FUNCTION1 rectMode_ -red FUNCTION1 red_ -redraw FUNCTION1 redraw_ -requestImage FUNCTION1 requestImage_ -resetMatrix FUNCTION1 resetMatrix_ -resetShader FUNCTION1 resetShader_ +keyArray FUNCTION2 StringDict_keyArray_ +curveTightness FUNCTION1 curveTightness_ +filter FUNCTION1 filter_ +getChildCount FUNCTION2 PShape_getChildCount_ +setJSONObject FUNCTION2 JSONArray_setJSONObject_ +heading FUNCTION2 PVector_heading_ +keys FUNCTION2 IntDict_keys_ +PFont KEYWORD5 PFont +noFill FUNCTION1 noFill_ +noise FUNCTION1 noise_ +acos FUNCTION1 acos_ +frameCount KEYWORD4 frameCount +curvePoint FUNCTION1 curvePoint_ +sort FUNCTION1 sort_ reverse FUNCTION1 reverse_ -rotate FUNCTION1 rotate_ -rotateX FUNCTION1 rotateX_ -rotateY FUNCTION1 rotateY_ -rotateZ FUNCTION1 rotateZ_ -round FUNCTION1 round_ -saturation FUNCTION1 saturation_ -save FUNCTION1 save_ -saveBytes FUNCTION1 saveBytes_ -saveFrame FUNCTION1 saveFrame_ -saveJSONArray FUNCTION1 saveJSONArray_ -saveJSONObject FUNCTION1 saveJSONObject_ -saveStream FUNCTION1 saveStream_ -saveStrings FUNCTION1 saveStrings_ -saveTable FUNCTION1 saveTable_ -saveXML FUNCTION1 saveXML_ -scale FUNCTION1 scale_ -screenX FUNCTION1 screenX_ -screenY FUNCTION1 screenY_ -screenZ FUNCTION1 screenZ_ +sphereDetail FUNCTION1 sphereDetail_ +sortReverse FUNCTION2 IntList_sortReverse_ +constrain FUNCTION1 constrain_ +frustum FUNCTION1 frustum_ +list FUNCTION1 PFont_list_ +max FUNCTION2 IntList_max_ +mag FUNCTION2 PVector_mag_ +sub FUNCTION2 FloatDict_sub_ second FUNCTION1 second_ -selectFolder FUNCTION1 selectFolder_ -selectInput FUNCTION1 selectInput_ -selectOutput FUNCTION1 selectOutput_ -set FUNCTION1 set_ -settings FUNCTION4 settings -setup FUNCTION4 setup -shader FUNCTION1 shader_ -shape FUNCTION1 shape_ -shapeMode FUNCTION1 shapeMode_ +set FUNCTION2 IntList_set_ +valueArray FUNCTION2 IntDict_valueArray_ +binary FUNCTION1 binary_ +StringList KEYWORD5 StringList +isVisible FUNCTION2 PShape_isVisible_ +push FUNCTION1 push_ +normal FUNCTION1 normal_ +PShader FUNCTION2 PShader_set_ +append FUNCTION2 JSONArray_append_ +pop FUNCTION1 pop_ shearX FUNCTION1 shearX_ +saveJSONObject FUNCTION1 saveJSONObject_ +enableStyle FUNCTION2 PShape_enableStyle_ +rotateY FUNCTION1 rotateY_ +rotateX FUNCTION1 rotateX_ +endShape FUNCTION1 endShape_ +sortKeys FUNCTION2 IntDict_sortKeys_ shearY FUNCTION1 shearY_ -shininess FUNCTION1 shininess_ -shorten FUNCTION1 shorten_ -sin FUNCTION1 sin_ -size FUNCTION1 size_ -smooth FUNCTION1 smooth_ -sort FUNCTION1 sort_ -specular FUNCTION1 specular_ -sphere FUNCTION1 sphere_ -sphereDetail FUNCTION1 sphereDetail_ -splice FUNCTION1 splice_ -split FUNCTION1 split_ -splitTokens FUNCTION1 splitTokens_ -spotLight FUNCTION1 spotLight_ -sq FUNCTION1 sq_ +shapeMode FUNCTION1 shapeMode_ +norm FUNCTION1 norm_ +saveJSONArray FUNCTION1 saveJSONArray_ +match FUNCTION1 match_ +values FUNCTION2 StringDict_values_ +sortValues FUNCTION2 StringDict_sortValues_ +floor FUNCTION1 floor_ +quad FUNCTION1 quad_ +pixelHeight FUNCTION1 pixelHeight_ +parseXML FUNCTION1 parseXML_ +exit FUNCTION1 exit_ +texture FUNCTION1 texture_ +clear FUNCTION2 IntDict_clear_ +size FUNCTION2 JSONArray_size_ +setup FUNCTION4 setup +getJSONObject FUNCTION2 JSONArray_getJSONObject_ +modelX FUNCTION1 modelX_ +dot FUNCTION2 PVector_dot_ +rotateX FUNCTION2 PShape_rotateX_ +valueArray FUNCTION2 FloatDict_valueArray_ +selectFolder FUNCTION1 selectFolder_ +random3D FUNCTION2 PVector_random3D_ sqrt FUNCTION1 sqrt_ -StringDict KEYWORD5 StringDict -clear FUNCTION2 StringDict_clear_ -get FUNCTION2 StringDict_get_ -hasKey FUNCTION2 StringDict_hasKey_ -keyArray FUNCTION2 StringDict_keyArray_ -keys FUNCTION2 StringDict_keys_ -remove FUNCTION2 StringDict_remove_ +sortReverse FUNCTION2 StringList_sortReverse_ +limit FUNCTION2 PVector_limit_ +log FUNCTION1 log_ +remove FUNCTION2 FloatDict_remove_ +shuffle FUNCTION2 StringList_shuffle_ +curveTangent FUNCTION1 curveTangent_ +unhex FUNCTION1 unhex_ +array FUNCTION2 IntList_array_ +size FUNCTION2 FloatList_size_ +remove FUNCTION2 StringList_remove_ +get FUNCTION2 PVector_get_ +createInput FUNCTION1 createInput_ set FUNCTION2 StringDict_set_ -size FUNCTION2 StringDict_size_ -sortKeys FUNCTION2 StringDict_sortKeys_ -sortKeysReverse FUNCTION2 StringDict_sortKeysReverse_ -sortValues FUNCTION2 StringDict_sortValues_ -sortValuesReverse FUNCTION2 StringDict_sortValuesReverse_ +thread FUNCTION1 thread_ +max FUNCTION2 FloatList_max_ +sub FUNCTION2 IntDict_sub_ +beginRaw FUNCTION1 beginRaw_ +set FUNCTION2 FloatList_set_ +getInt FUNCTION2 JSONObject_getInt_ +fromAngle FUNCTION2 PVector_fromAngle_ +rotateY FUNCTION2 PShape_rotateY_ +modelY FUNCTION1 modelY_ +ambientLight FUNCTION1 ambientLight_ +getJSONArray FUNCTION2 JSONObject_getJSONArray_ valueArray FUNCTION2 StringDict_valueArray_ -values FUNCTION2 StringDict_values_ -StringList KEYWORD5 StringList -append FUNCTION2 StringList_append_ -array FUNCTION2 StringList_array_ -clear FUNCTION2 StringList_clear_ -get FUNCTION2 StringList_get_ -hasValue FUNCTION2 StringList_hasValue_ -lower FUNCTION2 StringList_lower_ -remove FUNCTION2 StringList_remove_ -reverse FUNCTION2 StringList_reverse_ -set FUNCTION2 StringList_set_ -shuffle FUNCTION2 StringList_shuffle_ -size FUNCTION2 StringList_size_ -sort FUNCTION2 StringList_sort_ -sortReverse FUNCTION2 StringList_sortReverse_ -upper FUNCTION2 StringList_upper_ -stroke FUNCTION1 stroke_ -strokeCap FUNCTION1 strokeCap_ -strokeJoin FUNCTION1 strokeJoin_ -strokeWeight FUNCTION1 strokeWeight_ -subset FUNCTION1 subset_ -Table KEYWORD5 Table -addColumn FUNCTION2 Table_addColumn_ -addRow FUNCTION2 Table_addRow_ -clearRows FUNCTION2 Table_clearRows_ -findRow FUNCTION2 Table_findRow_ -findRows FUNCTION2 Table_findRows_ -getColumnCount FUNCTION2 Table_getColumnCount_ -getFloat FUNCTION2 Table_getFloat_ -getInt FUNCTION2 Table_getInt_ -getRow FUNCTION2 Table_getRow_ -getRowCount FUNCTION2 Table_getRowCount_ -getString FUNCTION2 Table_getString_ -getStringColumn FUNCTION2 Table_getStringColumn_ -matchRow FUNCTION2 Table_matchRow_ -matchRows FUNCTION2 Table_matchRows_ -removeColumn FUNCTION2 Table_removeColumn_ -removeRow FUNCTION2 Table_removeRow_ -removeTokens FUNCTION2 Table_removeTokens_ -rows FUNCTION2 Table_rows_ -setFloat FUNCTION2 Table_setFloat_ setInt FUNCTION2 Table_setInt_ -setString FUNCTION2 Table_setString_ -trim FUNCTION2 Table_trim_ -TableRow KEYWORD5 TableRow -getFloat FUNCTION2 TableRow_getFloat_ -getInt FUNCTION2 TableRow_getInt_ +rectMode FUNCTION1 rectMode_ +arc FUNCTION1 arc_ +setInt FUNCTION2 XML_setInt_ +getRow FUNCTION2 Table_getRow_ getString FUNCTION2 TableRow_getString_ -setFloat FUNCTION2 TableRow_setFloat_ -setInt FUNCTION2 TableRow_setInt_ -setString FUNCTION2 TableRow_setString_ -tan FUNCTION1 tan_ -TAU LITERAL2 TAU -text FUNCTION1 text_ -textAlign FUNCTION1 textAlign_ -textAscent FUNCTION1 textAscent_ -textDescent FUNCTION1 textDescent_ -textFont FUNCTION1 textFont_ -textLeading FUNCTION1 textLeading_ +noTint FUNCTION1 noTint_ +clear FUNCTION2 IntList_clear_ +beginContour FUNCTION2 PShape_beginContour_ +matchRows FUNCTION2 Table_matchRows_ +setFill FUNCTION2 PShape_setFill_ +shorten FUNCTION1 shorten_ +dist FUNCTION2 PVector_dist_ +unbinary FUNCTION1 unbinary_ +IntList KEYWORD5 IntList +toString FUNCTION2 XML_toString_ +get FUNCTION2 IntDict_get_ +getString FUNCTION2 JSONArray_getString_ +line FUNCTION1 line_ +sortValues FUNCTION2 IntDict_sortValues_ +mousePressed KEYWORD4 mousePressed +colorMode FUNCTION1 colorMode_ +loop FUNCTION1 loop_ +saturation FUNCTION1 saturation_ +sub FUNCTION2 PVector_sub_ +rotateZ FUNCTION2 PShape_rotateZ_ +beginDraw FUNCTION2 PGraphics_beginDraw_ +directionalLight FUNCTION1 directionalLight_ +hasValue FUNCTION2 FloatList_hasValue_ +modelZ FUNCTION1 modelZ_ +endContour FUNCTION2 PShape_endContour_ +setInt FUNCTION2 JSONObject_setInt_ +nf FUNCTION1 nf_ +size FUNCTION2 IntList_size_ +loadStrings FUNCTION1 loadStrings_ textMode FUNCTION1 textMode_ +camera FUNCTION1 camera_ +removeTokens FUNCTION2 Table_removeTokens_ +div FUNCTION2 FloatDict_div_ +screenY FUNCTION1 screenY_ +sortKeysReverse FUNCTION2 IntDict_sortKeysReverse_ textSize FUNCTION1 textSize_ -texture FUNCTION1 texture_ -textureMode FUNCTION1 textureMode_ -textureWrap FUNCTION1 textureWrap_ -textWidth FUNCTION1 textWidth_ -thread FUNCTION1 thread_ +rotate FUNCTION2 PShape_rotate_ +split FUNCTION1 split_ +Table KEYWORD5 Table +addRow FUNCTION2 Table_addRow_ +mouseClicked FUNCTION4 mouseClicked +ellipseMode FUNCTION1 ellipseMode_ +resetShader FUNCTION1 resetShader_ +hasChildren FUNCTION2 XML_hasChildren_ +append FUNCTION1 append_ +square FUNCTION1 square_ +getFloat FUNCTION2 XML_getFloat_ +textAscent FUNCTION1 textAscent_ +endShape FUNCTION2 PShape_endShape_ +box FUNCTION1 box_ +millis FUNCTION1 millis_ +curve FUNCTION1 curve_ +setFloat FUNCTION2 Table_setFloat_ +spotLight FUNCTION1 spotLight_ +resize FUNCTION2 PImage_resize_ +add FUNCTION2 IntDict_add_ +screenX FUNCTION1 screenX_ +curveVertex FUNCTION1 curveVertex_ +getChild FUNCTION2 PShape_getChild_ +getString FUNCTION2 Table_getString_ +printArray FUNCTION1 printArray_ +selectOutput FUNCTION1 selectOutput_ +endRecord FUNCTION1 endRecord_ +noiseSeed FUNCTION1 noiseSeed_ +hasKey FUNCTION2 StringDict_hasKey_ +endDraw FUNCTION2 PGraphics_endDraw_ +PGraphics KEYWORD5 PGraphics +pointLight FUNCTION1 pointLight_ +screenZ FUNCTION1 screenZ_ +array FUNCTION2 PVector_array_ +getVertex FUNCTION2 PShape_getVertex_ +save FUNCTION1 save_ +remove FUNCTION2 JSONArray_remove_ +loadShader FUNCTION1 loadShader_ +reverse FUNCTION2 StringList_reverse_ +keyCode KEYWORD4 keyCode +subset FUNCTION1 subset_ +image FUNCTION1 image_ tint FUNCTION1 tint_ -translate FUNCTION1 translate_ -triangle FUNCTION1 triangle_ -trim FUNCTION1 trim_ -TWO_PI LITERAL2 TWO_PI -unbinary FUNCTION1 unbinary_ -unhex FUNCTION1 unhex_ -updatePixels FUNCTION1 updatePixels_ -vertex FUNCTION1 vertex_ -XML KEYWORD5 XML -addChild FUNCTION2 XML_addChild_ -format FUNCTION2 XML_format_ getAttributeCount FUNCTION2 XML_getAttributeCount_ -getChild FUNCTION2 XML_getChild_ -getChildren FUNCTION2 XML_getChildren_ -getContent FUNCTION2 XML_getContent_ -getFloat FUNCTION2 XML_getFloat_ -getContent FUNCTION2 XML_getFloatContent_ +text FUNCTION1 text_ +mouseMoved FUNCTION4 mouseMoved +launch FUNCTION1 launch_ +PShader KEYWORD5 PShader +pushStyle FUNCTION1 pushStyle_ +textWidth FUNCTION1 textWidth_ +red FUNCTION1 red_ +lightSpecular FUNCTION1 lightSpecular_ +copy FUNCTION1 copy_ +atan2 FUNCTION1 atan2_ +add FUNCTION2 PVector_add_ +random2D FUNCTION2 PVector_random2D_ getInt FUNCTION2 XML_getInt_ -getContent FUNCTION2 XML_getIntContent_ -getName FUNCTION2 XML_getName_ -getParent FUNCTION2 XML_getParent_ -getString FUNCTION2 XML_getString_ -hasAttribute FUNCTION2 XML_hasAttribute_ -hasChildren FUNCTION2 XML_hasChildren_ -listAttributes FUNCTION2 XML_listAttributes_ -listChildren FUNCTION2 XML_listChildren_ -removeChild FUNCTION2 XML_removeChild_ -setContent FUNCTION2 XML_setContent_ -setFloat FUNCTION2 XML_setFloat_ -setInt FUNCTION2 XML_setInt_ -setName FUNCTION2 XML_setName_ -setString FUNCTION2 XML_setString_ -toString FUNCTION2 XML_toString_ -year FUNCTION1 year_ +createImage FUNCTION1 createImage_ +trim FUNCTION2 Table_trim_ +getColumnCount FUNCTION2 TableRow_getColumnCount_ +FloatList KEYWORD5 FloatList +attrib FUNCTION1 attrib_ +noLoop FUNCTION1 noLoop_ +setJSONObject FUNCTION2 JSONObject_setJSONObject_ +getInt FUNCTION2 Table_getInt_ diff --git a/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs b/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs index 2770cf1bf3..87b7a7a3a6 100644 --- a/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,13 @@ -#Sat Nov 12 10:56:00 CST 2011 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/ADS1X15.pde b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/ADS1X15.pde new file mode 100644 index 0000000000..91caaf94ab --- /dev/null +++ b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/ADS1X15.pde @@ -0,0 +1,107 @@ +import processing.io.I2C; + +// ADS1015 and ADS1115 are Analog-to-Digital converters using I2C +// they have four channels and 12 and 16 bits of resolution respectively +// datasheets: http://www.ti.com/lit/ds/symlink/ads1015.pdf +// http://www.ti.com/lit/ds/symlink/ads1115.pdf + +class ADS1015 extends ADS1X15 { + ADS1015(String dev, int address) { + super(dev, address); + bitShift = 4; + conversionDelay = 1; + } + + // returns a number between -1.0 and 1.0 + float analogRead(int channel) { + return readSingleEnded(channel) / 2047.0; + } +} + +class ADS1115 extends ADS1X15 { + ADS1115(String dev, int address) { + super(dev, address); + bitShift = 0; + conversionDelay = 8; + } + + // returns a number between -1.0 and 1.0 + float analogRead(int channel) { + return readSingleEnded(channel) / 32767.0; + } +} + + +class ADS1X15 extends I2C { + int address; + int bitShift; // bits to shift the result to the right + int conversionDelay; // in ms + int channel; // last channel used + int range; // see below + + // possible voltage ranges + static final int INTERNAL_6V144 = 0; // +/- 6.144V + static final int INTERNAL_4V096 = 1; // +/- 4.096V (library default) + static final int INTERNAL_2V048 = 2; // +/- 2.048V + static final int INTERNAL_1V024 = 3; // +/- 1.024V + static final int INTERNAL_0V512 = 4; // +/- 0.512V + static final int INTERNAL_0V256 = 5; // +/- 0.256V + + ADS1X15(String dev, int address) { + super(dev); + this.address = address; + this.channel = -1; + this.range = INTERNAL_4V096; + } + + // be careful not to make the input voltage exceed VCC + 0.3V + // this is regardless of the selected input range + void analogReference(int type) { + if (type < 0 || 7 < type) { + throw new RuntimeException("Invalid range setting"); + } + range = type; + } + + int readSingleEnded(int channel) { + if (channel < 0 || 3 < channel) { + System.err.println("The channel needs to be from 0 to 3"); + throw new IllegalArgumentException("Unexpected channel"); + } + + if (channel != this.channel) { + int config = 0x0183; // start with the default value from datasheet + config &= ~0x100; // enable continuous readings + config |= (range << 9); // set selected range (gain) + config |= (1 << 14) | (channel << 12); // set single-ended and channel + config |= (1 << 15); // start a single conversion + writeRegister(0x01, config); // write to the configuration register at 0x01 + + // when the channel switched we need to wait for the upcoming + // conversion to finish + delay(conversionDelay); + + // save the channel so that we don't need to do the same for + // subsequent reads from the same channel + this.channel = channel; + } + + return readS16(0x00) >> bitShift; // read from the conversion register at 0x00 + // the ADS1015 will have its 12-bit result in the upper bits, shift those right by four + } + + protected void writeRegister(int register, int value) { + beginTransmission(address); + write(register); + write(value >> 8); + write(value & 0xFF); + endTransmission(); + } + + protected int readS16(int register) { + beginTransmission(address); + write(register); + byte[] in = read(2); + return (in[0] << 8) | in[1]; + } +} diff --git a/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/AnalogDigital_I2C_ADS1X15.pde b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/AnalogDigital_I2C_ADS1X15.pde new file mode 100644 index 0000000000..31e5cec7bb --- /dev/null +++ b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/AnalogDigital_I2C_ADS1X15.pde @@ -0,0 +1,38 @@ +import processing.io.*; +ADS1015 adc; +// or, alternatively: +// ADS1115 adc; + +// see setup.png in the sketch folder for wiring details + +void setup() { + //printArray(I2C.list()); + + adc = new ADS1015("i2c-1", 0x48); + //adc = new ADS1115("i2c-1", 0x48); + + // this sets the measuring range to +/- 4.096 Volts + // other ranges supported by this chip: + // INTERNAL_6V144, INTERNAL_2V048, INTERNAL_1V024, + // INTERNAL_0V512, INTERNAL_0V256 + adc.analogReference(ADS1X15.INTERNAL_4V096); + + // Important: do not attempt to measure voltages higher than + // the supply voltage (VCC) + 0.3V, meaning that 3.6V is the + // absolut maximum voltage on the Raspberry Pi. This is + // irrespective of the analogReference() setting above. +} + +void draw() { + // this will return a number between 0 and 1 + // (as long as your voltage is positive) + float measured = adc.analogRead(0); + + // multiply with the selected range to get the absolut voltage + float volts = measured * 4.096; + println("Analog Input 0 is " + volts + "V"); + + background(255); + fill(measured * 255); + ellipse(width/2, height/2, width * 0.75, width * 0.75); +} diff --git a/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/setup.png b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/setup.png new file mode 100644 index 0000000000..f57950d7fa Binary files /dev/null and b/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/setup.png differ diff --git a/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/AnalogDigital_SPI_MCP3001.pde b/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/AnalogDigital_SPI_MCP3001.pde new file mode 100644 index 0000000000..fd7e49dff0 --- /dev/null +++ b/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/AnalogDigital_SPI_MCP3001.pde @@ -0,0 +1,20 @@ +import processing.io.*; +MCP3001 adc; + +// see setup.png in the sketch folder for wiring details + +void setup() { + //printArray(SPI.list()); + adc = new MCP3001(SPI.list()[0]); +} + +void draw() { + // this will return a number between 0 and 1 + float measured = adc.analogRead(); + + // multiply with the supply voltage to get an absolute value + float volts = 3.3 * measured; + println("Analog Input is " + volts + "V"); + + background(measured * 255); +} diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP/MCP3001.pde b/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/MCP3001.pde similarity index 77% rename from java/libraries/io/examples/SPIAnalogDigitalOOP/MCP3001.pde rename to java/libraries/io/examples/AnalogDigital_SPI_MCP3001/MCP3001.pde index e25869633e..2ffecaddb7 100644 --- a/java/libraries/io/examples/SPIAnalogDigitalOOP/MCP3001.pde +++ b/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/MCP3001.pde @@ -7,13 +7,14 @@ class MCP3001 extends SPI { MCP3001(String dev) { super(dev); - super.settings(500000, SPI.MSBFIRST, SPI.MODE0); + settings(500000, SPI.MSBFIRST, SPI.MODE0); } - float getAnalog() { + // returns a number between 0.0 and 1.0 + float analogRead() { // dummy write, actual values don't matter byte[] out = { 0, 0 }; - byte[] in = super.transfer(out); + byte[] in = transfer(out); // some input bit shifting according to the datasheet p. 16 int val = ((in[0] & 0x1f) << 5) | ((in[1] & 0xf8) >> 3); // val is between 0 and 1023 diff --git a/java/libraries/io/examples/SPIAnalogDigital/setup.png b/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/setup.png similarity index 100% rename from java/libraries/io/examples/SPIAnalogDigital/setup.png rename to java/libraries/io/examples/AnalogDigital_SPI_MCP3001/setup.png diff --git a/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/AnalogDigital_SPI_MCP3008.pde b/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/AnalogDigital_SPI_MCP3008.pde new file mode 100644 index 0000000000..2e3ea417d3 --- /dev/null +++ b/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/AnalogDigital_SPI_MCP3008.pde @@ -0,0 +1,22 @@ +import processing.io.*; +MCP3008 adc; + +// see setup.png in the sketch folder for wiring details + +void setup() { + //printArray(SPI.list()); + adc = new MCP3008(SPI.list()[0]); +} + +void draw() { + // this will return a number between 0 and 1 + float measured = adc.analogRead(0); + + // multiply with the supply voltage to get an absolute value + float volts = 3.3 * measured; + println("Analog Input 0 is " + volts + "V"); + + background(255); + fill(measured * 255); + ellipse(width/2, height/2, width * 0.75, width * 0.75); +} diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP8/MCP3008.pde b/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/MCP3008.pde similarity index 81% rename from java/libraries/io/examples/SPIAnalogDigitalOOP8/MCP3008.pde rename to java/libraries/io/examples/AnalogDigital_SPI_MCP3008/MCP3008.pde index 5ae8d9ef06..1c003d97e4 100644 --- a/java/libraries/io/examples/SPIAnalogDigitalOOP8/MCP3008.pde +++ b/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/MCP3008.pde @@ -8,10 +8,11 @@ class MCP3008 extends SPI { MCP3008(String dev) { super(dev); - super.settings(500000, SPI.MSBFIRST, SPI.MODE0); + settings(500000, SPI.MSBFIRST, SPI.MODE0); } - float getAnalog(int channel) { + // returns a number between 0.0 and 1.0 + float analogRead(int channel) { if (channel < 0 || 7 < channel) { System.err.println("The channel needs to be from 0 to 7"); throw new IllegalArgumentException("Unexpected channel"); @@ -19,7 +20,7 @@ class MCP3008 extends SPI { byte[] out = { 0, 0, 0 }; // encode the channel number in the first byte out[0] = (byte)(0x18 | channel); - byte[] in = super.transfer(out); + byte[] in = transfer(out); int val = ((in[1] & 0x03) << 8) | (in[2] & 0xff); // val is between 0 and 1023 return val/1023.0; diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP8/setup.png b/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/setup.png similarity index 100% rename from java/libraries/io/examples/SPIAnalogDigitalOOP8/setup.png rename to java/libraries/io/examples/AnalogDigital_SPI_MCP3008/setup.png diff --git a/java/libraries/io/examples/Compass_I2C_HMC6352/Compass_I2C_HMC6352.pde b/java/libraries/io/examples/Compass_I2C_HMC6352/Compass_I2C_HMC6352.pde new file mode 100644 index 0000000000..921fe47cb4 --- /dev/null +++ b/java/libraries/io/examples/Compass_I2C_HMC6352/Compass_I2C_HMC6352.pde @@ -0,0 +1,19 @@ +import processing.io.*; +HMC6352 compass; + +// see setup.png in the sketch folder for wiring details + +void setup() { + // the module's I2C address can be changed by modifying values in its EEPROM + // 0x21 is however the default address + + //printArray(I2C.list()); + compass = new HMC6352("i2c-1", 0x21); +} + +void draw() { + background(255); + float deg = compass.heading(); + println(deg + " degrees"); + line(width/2, height/2, width/2+sin(radians(deg))*width/2, height/2-cos(radians(deg))*height/2); +} diff --git a/java/libraries/io/examples/Compass_I2C_HMC6352/HMC6352.pde b/java/libraries/io/examples/Compass_I2C_HMC6352/HMC6352.pde new file mode 100644 index 0000000000..ff925ac3a5 --- /dev/null +++ b/java/libraries/io/examples/Compass_I2C_HMC6352/HMC6352.pde @@ -0,0 +1,38 @@ +import processing.io.I2C; + +// HMC6352 is a digital compass using I2C +// datasheet: https://www.sparkfun.com/datasheets/Components/HMC6352.pdf + +class HMC6352 extends I2C { + int address; + + HMC6352(String dev, int address) { + super(dev); + this.address = address; + setHeadingMode(); + } + + void setHeadingMode() { + beginTransmission(address); + // command byte for writing to EEPROM + write(0x77); + // address of the output data control byte + write(0x4e); + // give us the plain heading + write(0x00); + endTransmission(); + } + + float heading() { + beginTransmission(address); + // command byte for reading the data + write(0x41); + byte[] in = read(2); + endTransmission(); + // put bytes together to tenth of degrees + // & 0xff makes sure the byte is not interpreted as a negative value + int deg = (in[0] & 0xff) << 8 | (in[1] & 0xff); + // return degrees + return deg / 10.0; + } +} diff --git a/java/libraries/io/examples/I2CCompass/setup.png b/java/libraries/io/examples/Compass_I2C_HMC6352/setup.png similarity index 100% rename from java/libraries/io/examples/I2CCompass/setup.png rename to java/libraries/io/examples/Compass_I2C_HMC6352/setup.png diff --git a/java/libraries/io/examples/I2CDigitalAnalogOOP/I2CDigitalAnalogOOP.pde b/java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/DigitalAnalog_I2C_MCP4725.pde similarity index 100% rename from java/libraries/io/examples/I2CDigitalAnalogOOP/I2CDigitalAnalogOOP.pde rename to java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/DigitalAnalog_I2C_MCP4725.pde diff --git a/java/libraries/io/examples/I2CDigitalAnalogOOP/MCP4725.pde b/java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/MCP4725.pde similarity index 100% rename from java/libraries/io/examples/I2CDigitalAnalogOOP/MCP4725.pde rename to java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/MCP4725.pde diff --git a/java/libraries/io/examples/I2CScreen/I2CScreen.pde b/java/libraries/io/examples/Display_I2C_SSD1306/Display_I2C_SSD1306.pde similarity index 58% rename from java/libraries/io/examples/I2CScreen/I2CScreen.pde rename to java/libraries/io/examples/Display_I2C_SSD1306/Display_I2C_SSD1306.pde index 71a7615988..e16e6542a6 100644 --- a/java/libraries/io/examples/I2CScreen/I2CScreen.pde +++ b/java/libraries/io/examples/Display_I2C_SSD1306/Display_I2C_SSD1306.pde @@ -8,11 +8,15 @@ void setup() { // the display can be set to one of these two addresses: 0x3c (default) or 0x3d // (they might be listed as 0x7a and 0x7b on the circuit board) - oled = new SSD1306(I2C.list()[0], 0x3c); + + // you might need to use a different interface on other SBCs + oled = new SSD1306("i2c-1", 0x3c); } void draw() { - line(0, 0, 127, 63); - line(0, 63, 127, 0); - oled.sendImage(get()); + background(0); + stroke(255); + line(0, 0, 127, 63); + line(0, 63, 127, 0); + oled.sendImage(get()); } diff --git a/java/libraries/io/examples/I2CScreen/SSD1306.pde b/java/libraries/io/examples/Display_I2C_SSD1306/SSD1306.pde similarity index 98% rename from java/libraries/io/examples/I2CScreen/SSD1306.pde rename to java/libraries/io/examples/Display_I2C_SSD1306/SSD1306.pde index 6c9f343aa6..dee79a0276 100644 --- a/java/libraries/io/examples/I2CScreen/SSD1306.pde +++ b/java/libraries/io/examples/Display_I2C_SSD1306/SSD1306.pde @@ -61,7 +61,7 @@ class SSD1306 extends I2C { img.loadPixels(); for (int y=startY; y < height && y-startY < 64; y++) { for (int x=startX; x < width && x-startX < 128; x++) { - if (brightness(img.pixels[y*img.width+x]) < 128) { + if (128 <= brightness(img.pixels[y*img.width+x])) { // this isn't the normal (scanline) mapping, but 8 pixels below each other at a time // white pixels have their bit turned on frame[x + (y/8)*128] |= (1 << (y % 8)); diff --git a/java/libraries/io/examples/Environment_I2C_BME280/BME280.pde b/java/libraries/io/examples/Environment_I2C_BME280/BME280.pde new file mode 100644 index 0000000000..572e6d7013 --- /dev/null +++ b/java/libraries/io/examples/Environment_I2C_BME280/BME280.pde @@ -0,0 +1,407 @@ +import processing.io.I2C; + +// BME280 is an integrated environmental sensor +// It can measure temperature, pressure and humidity +// datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf +// code contributed by @OlivierLD + +public class BME280 extends I2C { + + public final static int BME280_I2CADDR = 0x77; // this is the default I2C address + public final static int DEFAULT_ADDR = BME280_I2CADDR; + + // Operating Modes + public final static int BME280_OSAMPLE_1 = 1; + public final static int BME280_OSAMPLE_2 = 2; + public final static int BME280_OSAMPLE_4 = 3; + public final static int BME280_OSAMPLE_8 = 4; + public final static int BME280_OSAMPLE_16 = 5; + + // BME280 Registers + public final static int BME280_REGISTER_DIG_T1 = 0x88; // Trimming parameter registers + public final static int BME280_REGISTER_DIG_T2 = 0x8A; + public final static int BME280_REGISTER_DIG_T3 = 0x8C; + + public final static int BME280_REGISTER_DIG_P1 = 0x8E; + public final static int BME280_REGISTER_DIG_P2 = 0x90; + public final static int BME280_REGISTER_DIG_P3 = 0x92; + public final static int BME280_REGISTER_DIG_P4 = 0x94; + public final static int BME280_REGISTER_DIG_P5 = 0x96; + public final static int BME280_REGISTER_DIG_P6 = 0x98; + public final static int BME280_REGISTER_DIG_P7 = 0x9A; + public final static int BME280_REGISTER_DIG_P8 = 0x9C; + public final static int BME280_REGISTER_DIG_P9 = 0x9E; + + public final static int BME280_REGISTER_DIG_H1 = 0xA1; + public final static int BME280_REGISTER_DIG_H2 = 0xE1; + public final static int BME280_REGISTER_DIG_H3 = 0xE3; + public final static int BME280_REGISTER_DIG_H4 = 0xE4; + public final static int BME280_REGISTER_DIG_H5 = 0xE5; + public final static int BME280_REGISTER_DIG_H6 = 0xE6; + public final static int BME280_REGISTER_DIG_H7 = 0xE7; + + public final static int BME280_REGISTER_CHIPID = 0xD0; + public final static int BME280_REGISTER_VERSION = 0xD1; + public final static int BME280_REGISTER_SOFTRESET = 0xE0; + + public final static int BME280_REGISTER_CONTROL_HUM = 0xF2; + public final static int BME280_REGISTER_CONTROL = 0xF4; + public final static int BME280_REGISTER_CONFIG = 0xF5; + public final static int BME280_REGISTER_PRESSURE_DATA = 0xF7; + public final static int BME280_REGISTER_TEMP_DATA = 0xFA; + public final static int BME280_REGISTER_HUMIDITY_DATA = 0xFD; + + private int dig_T1 = 0; + private int dig_T2 = 0; + private int dig_T3 = 0; + + private int dig_P1 = 0; + private int dig_P2 = 0; + private int dig_P3 = 0; + private int dig_P4 = 0; + private int dig_P5 = 0; + private int dig_P6 = 0; + private int dig_P7 = 0; + private int dig_P8 = 0; + private int dig_P9 = 0; + + private int dig_H1 = 0; + private int dig_H2 = 0; + private int dig_H3 = 0; + private int dig_H4 = 0; + private int dig_H5 = 0; + private int dig_H6 = 0; + + private float tFine = 0.0f; + + private int address; + private int mode = BME280_OSAMPLE_8; + private float standardSeaLevelPressure = 101325.0f; // in Pa (1013.25 hPa) + + protected float temp = 0.0f; // most recent sensor readings, set by update() + protected float press = 0.0f; + protected float hum = 0.0f; + + + public BME280(String dev) { + this(dev, DEFAULT_ADDR); + } + + public BME280(String dev, int address) { + super(dev); + this.address = address; + + // Soft reset + command(BME280_REGISTER_SOFTRESET, (byte)0xB6); + // Wait for the chip to wake up + delay(300); + + try { + readCalibrationData(); + // showCalibrationData(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + command(BME280_REGISTER_CONTROL, (byte)0x3F); + tFine = 0.0f; + } + + + /** + * Read and update all sensors values + */ + public void update() { + // The order used to read the data is important! + // 1.temperature, 2.pressure (analog to altitude), 3.humidity. + + try { + temp = readTemperature(); + } catch (Exception ex) { + System.err.println(ex.getMessage()); + ex.printStackTrace(); + } + + try { + press = readPressure(); + } catch (Exception ex) { + System.err.println(ex.getMessage()); + ex.printStackTrace(); + } + + try { + hum = readHumidity(); + } catch (Exception ex) { + System.err.println(ex.getMessage()); + ex.printStackTrace(); + } + } + + /** + * Returns the temperature in degrees celsius + */ + public float temperature() { + return temp; + } + + /** + * Returns the pressure in Pa + */ + public float pressure() { + return press; + } + + /** + * Returns the altitude in meters + * @param pressure as returned by pressure() + */ + public float altitude(float pressure) { + double altitude = 0.0; + if (standardSeaLevelPressure != 0) { + altitude = 44330.0 * (1.0 - Math.pow(pressure / standardSeaLevelPressure, 0.1903)); + } + return (float)altitude; + } + + /** + * Returns the altitude in meters + * @param pressure as returned by pressure() in Pa + * @param temperature as returned by temperature() in Celcius + */ + public float altitude(float pressure, float temperature) { + double altitude = 0.0; + if (standardSeaLevelPressure != 0) { + altitude = ((Math.pow(standardSeaLevelPressure / pressure, 1 / 5.257) - 1) * (temperature + 273.25)) / 0.0065; + } + return (float)altitude; + } + + /** + * Returns the humidity in percent + */ + public float humidity() { + return hum; + } + + /** + * Set the standard sea level pressure used for calculating altitude() + * Defaults to 101325 Pa (1013.25 hPa) + */ + public void setStandardSeaLevelPressure(float pressure) { + standardSeaLevelPressure = pressure; + } + + + protected float readTemperature() { + // Returns the compensated temperature in degrees celcius + float UT = readRawTemp(); + float var1 = 0.0f; + float var2 = 0.0f; + float temp = 0.0f; + + // Read raw temp before aligning it with the calibration values + var1 = (UT / 16384.0f - dig_T1 / 1024.0f) * (float) dig_T2; + var2 = ((UT / 131072.0f - dig_T1 / 8192.0f) * (UT / 131072.0f - dig_T1 / 8192.0f)) * (float) dig_T3; + tFine = (int) (var1 + var2); + temp = (var1 + var2) / 5120.0f; + // println("DBG: Calibrated temperature = " + temp + " C"); + return temp; + } + + protected float readPressure() { + // Returns the compensated pressure in Pascal + int adc = readRawPressure(); + // println("ADC:" + adc + ", tFine:" + tFine); + float var1 = (tFine / 2.0f) - 64000.0f; + float var2 = var1 * var1 * (dig_P6 / 32768.0f); + var2 = var2 + var1 * dig_P5 * 2.0f; + var2 = (var2 / 4.0f) + (dig_P4 * 65536.0f); + var1 = (dig_P3 * var1 * var1 / 524288.0f + dig_P2 * var1) / 524288.0f; + var1 = (1.0f + var1 / 32768.0f) * dig_P1; + if (var1 == 0f) { + return 0.0f; + } + float p = 1048576.0f - adc; + p = ((p - var2 / 4096.0f) * 6250.0f) / var1; + var1 = dig_P9 * p * p / 2147483648.0f; + var2 = p * dig_P8 / 32768.0f; + p = p + (var1 + var2 + dig_P7) / 16.0f; + // println("DBG: Pressure = " + p + " Pa"); + return p; + } + + protected float readHumidity() { + // Returns the compensated humidity in percent + int adc = readRawHumidity(); + float h = tFine - 76800.0f; + h = (adc - (dig_H4 * 64.0f + dig_H5 / 16384.8f * h)) * + (dig_H2 / 65536.0f * (1.0f + dig_H6 / 67108864.0f * h * (1.0f + dig_H3 / 67108864.0f * h))); + h = h * (1.0f - dig_H1 * h / 524288.0f); + if (h > 100) { + h = 100; + } else if (h < 0) { + h = 0; + } + // println("DBG: Humidity = " + h); + return h; + } + + + private void readCalibrationData() { + // Reads the calibration data from the IC + dig_T1 = readU16LE(BME280_REGISTER_DIG_T1); + dig_T2 = readS16LE(BME280_REGISTER_DIG_T2); + dig_T3 = readS16LE(BME280_REGISTER_DIG_T3); + + dig_P1 = readU16LE(BME280_REGISTER_DIG_P1); + dig_P2 = readS16LE(BME280_REGISTER_DIG_P2); + dig_P3 = readS16LE(BME280_REGISTER_DIG_P3); + dig_P4 = readS16LE(BME280_REGISTER_DIG_P4); + dig_P5 = readS16LE(BME280_REGISTER_DIG_P5); + dig_P6 = readS16LE(BME280_REGISTER_DIG_P6); + dig_P7 = readS16LE(BME280_REGISTER_DIG_P7); + dig_P8 = readS16LE(BME280_REGISTER_DIG_P8); + dig_P9 = readS16LE(BME280_REGISTER_DIG_P9); + + dig_H1 = readU8(BME280_REGISTER_DIG_H1); + dig_H2 = readS16LE(BME280_REGISTER_DIG_H2); + dig_H3 = readU8(BME280_REGISTER_DIG_H3); + dig_H6 = readS8(BME280_REGISTER_DIG_H7); + + int h4 = readS8(BME280_REGISTER_DIG_H4); + h4 = (h4 << 24) >> 20; + dig_H4 = h4 | (readU8(BME280_REGISTER_DIG_H5) & 0x0F); + + int h5 = readS8(BME280_REGISTER_DIG_H6); + h5 = (h5 << 24) >> 20; + dig_H5 = h5 | (readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F); + } + + private String displayRegister(int reg) { + return String.format("0x%s (%d)", lpad(Integer.toHexString(reg & 0xFFFF).toUpperCase(), 4, "0"), reg); + } + + private void showCalibrationData() { + // Displays the calibration values for debugging purposes + println("======================"); + println("DBG: T1 = " + displayRegister(dig_T1)); + println("DBG: T2 = " + displayRegister(dig_T2)); + println("DBG: T3 = " + displayRegister(dig_T3)); + println("----------------------"); + println("DBG: P1 = " + displayRegister(dig_P1)); + println("DBG: P2 = " + displayRegister(dig_P2)); + println("DBG: P3 = " + displayRegister(dig_P3)); + println("DBG: P4 = " + displayRegister(dig_P4)); + println("DBG: P5 = " + displayRegister(dig_P5)); + println("DBG: P6 = " + displayRegister(dig_P6)); + println("DBG: P7 = " + displayRegister(dig_P7)); + println("DBG: P8 = " + displayRegister(dig_P8)); + println("DBG: P9 = " + displayRegister(dig_P9)); + println("----------------------"); + println("DBG: H1 = " + displayRegister(dig_H1)); + println("DBG: H2 = " + displayRegister(dig_H2)); + println("DBG: H3 = " + displayRegister(dig_H3)); + println("DBG: H4 = " + displayRegister(dig_H4)); + println("DBG: H5 = " + displayRegister(dig_H5)); + println("DBG: H6 = " + displayRegister(dig_H6)); + println("======================"); + } + + private void command(int reg, byte val) { + super.beginTransmission(address); + super.write(reg); + super.write(val); + super.endTransmission(); + } + + private int readRawTemp() { + // Returns the raw (uncompensated) temperature + int meas = mode; + // println(String.format("readRawTemp: 1 - meas=%d", meas)); + command(BME280_REGISTER_CONTROL_HUM, (byte) meas); // HUM ? + meas = mode << 5 | mode << 2 | 1; + // println(String.format("readRawTemp: 2 - meas=%d", meas)); + command(BME280_REGISTER_CONTROL, (byte) meas); + + double sleepTime = 0.00125 + 0.0023 * (1 << mode); + sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575; + sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575; + delay((int)Math.round(sleepTime * 1000)); + int msb = readU8(BME280_REGISTER_TEMP_DATA); + int lsb = readU8(BME280_REGISTER_TEMP_DATA + 1); + int xlsb = readU8(BME280_REGISTER_TEMP_DATA + 2); + int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4; + // println("DBG: Raw Temp: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb)); + return raw; + } + + private int readRawPressure() { + // Returns the raw (uncompensated) pressure + int msb = readU8(BME280_REGISTER_PRESSURE_DATA); + int lsb = readU8(BME280_REGISTER_PRESSURE_DATA + 1); + int xlsb = readU8(BME280_REGISTER_PRESSURE_DATA + 2); + int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4; + // println("DBG: Raw Press: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb)); + return raw; + } + + private int readRawHumidity() { + // Returns the raw (uncompensated) humidity + int msb = readU8(BME280_REGISTER_HUMIDITY_DATA); + int lsb = readU8(BME280_REGISTER_HUMIDITY_DATA + 1); + int raw = (msb << 8) | lsb; + return raw; + } + + private int readU16LE(int register) { + super.beginTransmission(address); + super.write((byte)register); + byte[] ba = super.read(2); + super.endTransmission(); + return ((ba[1] & 0xFF) << 8) + (ba[0] & 0xFF); // Little Endian + } + + private int readS16LE(int register) { + super.beginTransmission(address); + super.write((byte)register); + byte[] ba = super.read(2); + super.endTransmission(); + + int lo = ba[0] & 0xFF; + int hi = ba[1] & 0xFF; + if (hi > 127) + hi -= 256; + return (hi << 8) + lo; // Little Endian + } + + private int readU8(int register) { + super.beginTransmission(address); + super.write(register); + byte[] ba = super.read(1); + super.endTransmission(); + return (int)(ba[0] & 0xFF); + } + + private int readS8(int register) { + int val = readU8(register); + if (val > 127) + val -= 256; + return val; + } + + private String rpad(String s, int len, String pad) { + String str = s; + while (str.length() < len) { + str += pad; + } + return str; + } + + private String lpad(String s, int len, String pad) { + String str = s; + while (str.length() < len) { + str = pad + str; + } + return str; + } +} diff --git a/java/libraries/io/examples/Environment_I2C_BME280/Environment_I2C_BME280.pde b/java/libraries/io/examples/Environment_I2C_BME280/Environment_I2C_BME280.pde new file mode 100644 index 0000000000..a5ec80602c --- /dev/null +++ b/java/libraries/io/examples/Environment_I2C_BME280/Environment_I2C_BME280.pde @@ -0,0 +1,29 @@ +import processing.io.*; +BME280 bme280; + +// see setup.png in the sketch folder for wiring details + +void setup() { + size(720, 320); + textSize(72); + + //printArray(I2C.list()); + bme280 = new BME280("i2c-1", 0x77); +} + +void draw() { + background(0); + stroke(255); + + bme280.update(); + float temp = bme280.temperature(); + float hum = bme280.humidity(); + float press = bme280.pressure(); + text(String.format("Temp: %.02f\272C", temp), 10, 75); + text(String.format("Hum: %.02f %%", hum), 10, 150); + text(String.format("Press: %.02f hPa", press / 100f), 10, 225); + + // pressure can be used to calculate the altitude like so + float alt = bme280.altitude(press, temp); + text(String.format("Alt: %.02f m", alt), 10, 300); +} diff --git a/java/libraries/io/examples/Environment_I2C_BME280/setup.png b/java/libraries/io/examples/Environment_I2C_BME280/setup.png new file mode 100644 index 0000000000..cb37a3a60e Binary files /dev/null and b/java/libraries/io/examples/Environment_I2C_BME280/setup.png differ diff --git a/java/libraries/io/examples/I2CCompass/I2CCompass.pde b/java/libraries/io/examples/I2CCompass/I2CCompass.pde deleted file mode 100644 index 079a7bcc61..0000000000 --- a/java/libraries/io/examples/I2CCompass/I2CCompass.pde +++ /dev/null @@ -1,43 +0,0 @@ -import processing.io.*; -I2C i2c; - -// HMC6352 is a digital compass module using I2C -// datasheet: https://www.sparkfun.com/datasheets/Components/HMC6352.pdf -// see setup.png in the sketch folder for wiring details - -void setup() { - //printArray(I2C.list()); - i2c = new I2C(I2C.list()[0]); - setHeadingMode(); -} - -void draw() { - background(255); - float deg = getHeading(); - println(deg + " degrees"); - line(width/2, height/2, width/2+sin(radians(deg))*width/2, height/2-cos(radians(deg))*height/2); -} - -void setHeadingMode() { - i2c.beginTransmission(0x21); - // command byte for writing to EEPROM - i2c.write(0x77); - // address of the output data control byte - i2c.write(0x4e); - // give us the plain heading - i2c.write(0x00); - i2c.endTransmission(); -} - -float getHeading() { - i2c.beginTransmission(0x21); - // command byte for reading the data - i2c.write(0x41); - byte[] in = i2c.read(2); - i2c.endTransmission(); - // put bytes together to tenth of degrees - // & 0xff makes sure the byte is not interpreted as a negative value - int deg = (in[0] & 0xff) << 8 | (in[1] & 0xff); - // return degrees - return deg / 10.0; -} diff --git a/java/libraries/io/examples/Light_I2C_TSL2561/Light_I2C_TSL2561.pde b/java/libraries/io/examples/Light_I2C_TSL2561/Light_I2C_TSL2561.pde new file mode 100644 index 0000000000..c6c9a28ec7 --- /dev/null +++ b/java/libraries/io/examples/Light_I2C_TSL2561/Light_I2C_TSL2561.pde @@ -0,0 +1,27 @@ +import processing.io.*; +TSL2561 sensor; + +// see setup.png in the sketch folder for wiring details + +// this variable will contain the measured brightness +// Lux (lx) is the unit of illuminance +float lux; + +void setup() { + size(700, 100); + textSize(72); + //printArray(I2C.list()); + sensor = new TSL2561("i2c-1", 0x39); +} + +void draw() { + background(0); + stroke(255); + lux = sensor.lux(); + text(String.format("Light: %.02f Lux", lux), 10, 75); +} + +void dispose() { + // turn the sensor off + sensor.stop(); +} diff --git a/java/libraries/io/examples/Light_I2C_TSL2561/TSL2561.pde b/java/libraries/io/examples/Light_I2C_TSL2561/TSL2561.pde new file mode 100644 index 0000000000..775b9d02ca --- /dev/null +++ b/java/libraries/io/examples/Light_I2C_TSL2561/TSL2561.pde @@ -0,0 +1,187 @@ +import processing.io.I2C; + +// TSL2561 is light sensor using I2C +// datasheet: https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf +// code contributed by @OlivierLD + +public class TSL2561 extends I2C { + + public final static int TSL2561_ADDRESS = 0x39; + + public final static int TSL2561_ADDRESS_LOW = 0x29; + public final static int TSL2561_ADDRESS_FLOAT = 0x39; + public final static int TSL2561_ADDRESS_HIGH = 0x49; + + public final static int TSL2561_COMMAND_BIT = 0x80; + public final static int TSL2561_WORD_BIT = 0x20; + public final static int TSL2561_CONTROL_POWERON = 0x03; + public final static int TSL2561_CONTROL_POWEROFF = 0x00; + + public final static int TSL2561_REGISTER_CONTROL = 0x00; + public final static int TSL2561_REGISTER_TIMING = 0x01; + public final static int TSL2561_REGISTER_CHAN0_LOW = 0x0C; + public final static int TSL2561_REGISTER_CHAN0_HIGH = 0x0D; + public final static int TSL2561_REGISTER_CHAN1_LOW = 0x0E; + public final static int TSL2561_REGISTER_CHAN1_HIGH = 0x0F; + public final static int TSL2561_REGISTER_ID = 0x0A; + + public final static int TSL2561_GAIN_1X = 0x00; + public final static int TSL2561_GAIN_16X = 0x10; + + public final static int TSL2561_INTEGRATIONTIME_13MS = 0x00; // rather 13.7ms + public final static int TSL2561_INTEGRATIONTIME_101MS = 0x01; + public final static int TSL2561_INTEGRATIONTIME_402MS = 0x02; + + public final static double TSL2561_LUX_K1C = 0.130; // (0x0043) // 0.130 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B1C = 0.0315; // (0x0204) // 0.0315 * 2^LUX_SCALE + public final static double TSL2561_LUX_M1C = 0.0262; // (0x01ad) // 0.0262 * 2^LUX_SCALE + public final static double TSL2561_LUX_K2C = 0.260; // (0x0085) // 0.260 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B2C = 0.0337; // (0x0228) // 0.0337 * 2^LUX_SCALE + public final static double TSL2561_LUX_M2C = 0.0430; // (0x02c1) // 0.0430 * 2^LUX_SCALE + public final static double TSL2561_LUX_K3C = 0.390; // (0x00c8) // 0.390 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B3C = 0.0363; // (0x0253) // 0.0363 * 2^LUX_SCALE + public final static double TSL2561_LUX_M3C = 0.0529; // (0x0363) // 0.0529 * 2^LUX_SCALE + public final static double TSL2561_LUX_K4C = 0.520; // (0x010a) // 0.520 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B4C = 0.0392; // (0x0282) // 0.0392 * 2^LUX_SCALE + public final static double TSL2561_LUX_M4C = 0.0605; // (0x03df) // 0.0605 * 2^LUX_SCALE + public final static double TSL2561_LUX_K5C = 0.65; // (0x014d) // 0.65 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B5C = 0.0229; // (0x0177) // 0.0229 * 2^LUX_SCALE + public final static double TSL2561_LUX_M5C = 0.0291; // (0x01dd) // 0.0291 * 2^LUX_SCALE + public final static double TSL2561_LUX_K6C = 0.80; // (0x019a) // 0.80 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B6C = 0.0157; // (0x0101) // 0.0157 * 2^LUX_SCALE + public final static double TSL2561_LUX_M6C = 0.0180; // (0x0127) // 0.0180 * 2^LUX_SCALE + public final static double TSL2561_LUX_K7C = 1.3; // (0x029a) // 1.3 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B7C = 0.00338; // (0x0037) // 0.00338 * 2^LUX_SCALE + public final static double TSL2561_LUX_M7C = 0.00260; // (0x002b) // 0.00260 * 2^LUX_SCALE + public final static double TSL2561_LUX_K8C = 1.3; // (0x029a) // 1.3 * 2^RATIO_SCALE + public final static double TSL2561_LUX_B8C = 0.000; // (0x0000) // 0.000 * 2^LUX_SCALE + public final static double TSL2561_LUX_M8C = 0.000; // (0x0000) // 0.000 * 2^LUX_SCALE + + private int gain = TSL2561_GAIN_1X; + private int integration = TSL2561_INTEGRATIONTIME_402MS; + private int pause = 800; + + private int address; + + + public TSL2561(String dev) { + this(dev, TSL2561_ADDRESS); + } + + public TSL2561(String dev, int address) { + super(dev); + this.address = address; + start(); + } + + public void start() { + command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWERON); + } + + public void stop() { + command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWEROFF); + } + + public void setGain() { + setGain(TSL2561_GAIN_1X); + } + + public void setGain(int gain) { + setGain(gain, TSL2561_INTEGRATIONTIME_402MS); + } + + public void setGain(int gain, int integration) { + if (gain != TSL2561_GAIN_1X && gain != TSL2561_GAIN_16X) { + throw new IllegalArgumentException("Invalid gain value"); + } + if (gain != this.gain || integration != this.integration) { + command(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, (byte) (gain | integration)); + //println("Setting low gain"); + this.gain = gain; + this.integration = integration; + delay(pause); // pause for integration (pause must be bigger than integration time) + } + } + + /** + * Read visible+IR diode from the I2C device + */ + public int readFull() { + int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN0_LOW; + return readU16(reg); + } + + /** + * Read IR only diode from the I2C device + */ + public int readIR() { + int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN1_LOW; + return readU16(reg); + } + + /** + * Device lux range 0.1 - 40,000+ + * see https://learn.adafruit.com/tsl2561/overview + */ + public float lux() { + int ambient = this.readFull(); + int ir = this.readIR(); + + //println("IR Result: " + ir); + //println("Ambient Result: " + ambient); + + if (ambient >= 0xffff || ir >= 0xffff) { + throw new RuntimeException("Gain too high, values exceed range"); + } + double ratio = (ir / (float) ambient); + + /* + * For the values below, see https://github.com/adafruit/_TSL2561/blob/master/_TSL2561_U.h + */ + float lux = 0.0f; + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K4C)) { + lux = (float)((TSL2561_LUX_B1C * ambient) - (0.0593 * ambient * (Math.pow(ratio, 1.4)))); + } else if (ratio <= TSL2561_LUX_K5C) { + lux = (float)((TSL2561_LUX_B5C * ambient) - (TSL2561_LUX_M5C * ir)); + } else if (ratio <= TSL2561_LUX_K6C) { + lux = (float)((TSL2561_LUX_B6C * ambient) - (TSL2561_LUX_M6C * ir)); + } else if (ratio <= TSL2561_LUX_K7C) { + lux = (float)((TSL2561_LUX_B7C * ambient) - (TSL2561_LUX_M7C * ir)); + } else if (ratio > TSL2561_LUX_K8C) { + lux = 0.0f; + } + return lux; + } + + + private void command(int register, byte value) { + beginTransmission(address); + write(register); + write(value); + endTransmission(); + } + + private int readU8(int register) { + beginTransmission(this.address); + write(register); + byte[] ba = read(1); + endTransmission(); + return (int)(ba[0] & 0xFF); + } + + private int readU16(int register) { + int lo = readU8(register); + int hi = readU8(register + 1); + int result = (hi << 8) + lo; // Big Endian + //println("(U16) I2C: Device " + toHex(TSL2561_ADDRESS) + " returned " + toHex(result) + " from reg " + toHex(register)); + return result; + } + + private String toHex(int i) { + String s = Integer.toString(i, 16).toUpperCase(); + while (s.length() % 2 != 0) { + s = "0" + s; + } + return "0x" + s; + } +} diff --git a/java/libraries/io/examples/Light_I2C_TSL2561/setup.png b/java/libraries/io/examples/Light_I2C_TSL2561/setup.png new file mode 100644 index 0000000000..a0b33fefbe Binary files /dev/null and b/java/libraries/io/examples/Light_I2C_TSL2561/setup.png differ diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP/SPIAnalogDigitalOOP.pde b/java/libraries/io/examples/SPIAnalogDigitalOOP/SPIAnalogDigitalOOP.pde deleted file mode 100644 index f45f0fa5ce..0000000000 --- a/java/libraries/io/examples/SPIAnalogDigitalOOP/SPIAnalogDigitalOOP.pde +++ /dev/null @@ -1,13 +0,0 @@ -import processing.io.*; -MCP3001 adc; - -// see setup.png in the sketch folder for wiring details - -void setup() { - //printArray(SPI.list()); - adc = new MCP3001(SPI.list()[0]); -} - -void draw() { - background(adc.getAnalog() * 255); -} diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP8/SPIAnalogDigitalOOP8.pde b/java/libraries/io/examples/SPIAnalogDigitalOOP8/SPIAnalogDigitalOOP8.pde deleted file mode 100644 index 58c4969779..0000000000 --- a/java/libraries/io/examples/SPIAnalogDigitalOOP8/SPIAnalogDigitalOOP8.pde +++ /dev/null @@ -1,15 +0,0 @@ -import processing.io.*; -MCP3008 adc; - -// see setup.png in the sketch folder for wiring details - -void setup() { - //printArray(SPI.list()); - adc = new MCP3008(SPI.list()[0]); -} - -void draw() { - background(adc.getAnalog(0) * 255); - fill(adc.getAnalog(1) * 255); - ellipse(width/2, height/2, width * 0.75, width * 0.75); -} diff --git a/java/libraries/io/examples/Servo_I2C_PCA9685/PCA9685.pde b/java/libraries/io/examples/Servo_I2C_PCA9685/PCA9685.pde new file mode 100644 index 0000000000..67ea815a4f --- /dev/null +++ b/java/libraries/io/examples/Servo_I2C_PCA9685/PCA9685.pde @@ -0,0 +1,148 @@ +import processing.io.I2C; + +// PCA9685 is a 16-channel servo/PWM driver +// datasheet: https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf +// code contributed by @OlivierLD + +public class PCA9685 extends I2C { + public final static int PCA9685_ADDRESS = 0x40; + + // registers used + public final static int MODE1 = 0x00; + public final static int PRESCALE = 0xFE; + public final static int LED0_ON_L = 0x06; + public final static int LED0_ON_H = 0x07; + public final static int LED0_OFF_L = 0x08; + public final static int LED0_OFF_H = 0x09; + + private int address; + private int freq = 200; // 200 Hz default frequency (after power-up) + private boolean hasFreqSet = false; // whether a different frequency has been set + private int minPulses[] = new int[16]; + private int maxPulses[] = new int[16]; + + + public PCA9685(String dev) { + this(dev, PCA9685_ADDRESS); + } + public PCA9685(String dev, int address) { + super(dev); + this.address = address; + // reset device + command(MODE1, (byte) 0x00); + } + + + public void attach(int channel) { + // same as on Arduino + attach(channel, 544, 2400); + } + + public void attach(int channel, int minPulse, int maxPulse) { + if (channel < 0 || 15 < channel) { + throw new IllegalArgumentException("Channel must be between 0 and 15"); + } + minPulses[channel] = minPulse; + maxPulses[channel] = maxPulse; + + // set the PWM frequency to be the same as on Arduino + if (!hasFreqSet) { + frequency(50); + } + } + + public void write(int channel, float angle) { + if (channel < 0 || 15 < channel) { + throw new IllegalArgumentException("Channel must be between 0 and 15"); + } + if (angle < 0 || 180 < angle) { + throw new IllegalArgumentException("Angle must be between 0 and 180"); + } + int us = (int)(minPulses[channel] + (angle/180.0) * (maxPulses[channel]-minPulses[channel])); + + double pulseLength = 1000000; // 1s = 1,000,000 us per pulse + pulseLength /= freq; // 40..1000 Hz + pulseLength /= 4096; // 12 bits of resolution + int pulse = us; + pulse /= pulseLength; + // println(pulseLength + " us per bit, pulse:" + pulse); + pwm(channel, 0, pulse); + } + + public boolean attached(int channel) { + if (channel < 0 || 15 < channel) { + return false; + } + return (maxPulses[channel] != 0) ? true : false; + } + + public void detach(int channel) { + pwm(channel, 0, 0); + minPulses[channel] = 0; + maxPulses[channel] = 0; + } + + + /** + * @param freq 40..1000 Hz + */ + public void frequency(int freq) { + this.freq = freq; + float preScaleVal = 25000000.0f; // 25MHz + preScaleVal /= 4096.0; // 4096: 12-bit + preScaleVal /= freq; + preScaleVal -= 1.0; + // println("Setting PWM frequency to " + freq + " Hz"); + // println("Estimated pre-scale: " + preScaleVal); + double preScale = Math.floor(preScaleVal + 0.5); + // println("Final pre-scale: " + preScale); + byte oldmode = (byte) readU8(MODE1); + byte newmode = (byte) ((oldmode & 0x7F) | 0x10); // sleep + command(MODE1, newmode); // go to sleep + command(PRESCALE, (byte) (Math.floor(preScale))); + command(MODE1, oldmode); + delay(5); + command(MODE1, (byte) (oldmode | 0x80)); + hasFreqSet = true; + } + + /** + * @param channel 0..15 + * @param on cycle offset to turn output on (0..4095) + * @param off cycle offset to turn output off again (0..4095) + */ + public void pwm(int channel, int on, int off) { + if (channel < 0 || 15 < channel) { + throw new IllegalArgumentException("Channel must be between 0 and 15"); + } + if (on < 0 || 4095 < on) { + throw new IllegalArgumentException("On must be between 0 and 4095"); + } + if (off < 0 || 4095 < off) { + throw new IllegalArgumentException("Off must be between 0 and 4095"); + } + if (off < on) { + throw new IllegalArgumentException("Off must be greater than On"); + } + command(LED0_ON_L + 4 * channel, (byte) (on & 0xFF)); + command(LED0_ON_H + 4 * channel, (byte) (on >> 8)); + command(LED0_OFF_L + 4 * channel, (byte) (off & 0xFF)); + command(LED0_OFF_H + 4 * channel, (byte) (off >> 8)); + } + + + private void command(int register, byte value) { + beginTransmission(address); + write(register); + write(value); + endTransmission(); + } + + private byte readU8(int register) { + beginTransmission(address); + write(register); + byte[] ba = read(1); + endTransmission(); + return (byte)(ba[0] & 0xFF); + } +} diff --git a/java/libraries/io/examples/Servo_I2C_PCA9685/Servo_I2C_PCA9685.pde b/java/libraries/io/examples/Servo_I2C_PCA9685/Servo_I2C_PCA9685.pde new file mode 100644 index 0000000000..ede995bc5e --- /dev/null +++ b/java/libraries/io/examples/Servo_I2C_PCA9685/Servo_I2C_PCA9685.pde @@ -0,0 +1,41 @@ +import processing.io.*; +PCA9685 servos; + +// see setup.png in the sketch folder for wiring details + +void setup() { + size(400, 300); + //printArray(I2C.list()); + servos = new PCA9685("i2c-1", 0x40); + + // different servo motors will vary in the pulse width they expect + // the lines below set the pulse width for 0 degrees to 544 microseconds (μs) + // and the pulse width for 180 degrees to 2400 microseconds + // these values match the defaults of the Servo library on Arduino + // but you might need to modify this for your particular servo still + servos.attach(0, 544, 2400); + servos.attach(1, 544, 2400); +} + +void draw() { + background(0); + stroke(255); + strokeWeight(3); + + // we don't go right to the edge to prevent + // making the servo unhappy + float angle = 90 + sin(frameCount / 100.0)*85; + servos.write(0, angle); + float y = map(angle, 0, 180, 0, height); + line(0, y, width/2, y); + + angle = 90 + cos(frameCount / 100.0)*85; + servos.write(1, 90 + cos(frameCount / 100.0)*85); + y = map(angle, 0, 180, 0, height); + line(width/2, y, width, y); +} + +void dispose() { + servos.detach(0); + servos.detach(1); +} diff --git a/java/libraries/io/examples/Servo_I2C_PCA9685/setup.png b/java/libraries/io/examples/Servo_I2C_PCA9685/setup.png new file mode 100644 index 0000000000..77b0b74bf0 Binary files /dev/null and b/java/libraries/io/examples/Servo_I2C_PCA9685/setup.png differ diff --git a/java/libraries/io/examples/I2CDigitalAnalog/I2CDigitalAnalog.pde b/java/libraries/io/examples/SimpleI2C/SimpleI2C.pde similarity index 86% rename from java/libraries/io/examples/I2CDigitalAnalog/I2CDigitalAnalog.pde rename to java/libraries/io/examples/SimpleI2C/SimpleI2C.pde index 66f034f61e..75a5bacccf 100644 --- a/java/libraries/io/examples/I2CDigitalAnalog/I2CDigitalAnalog.pde +++ b/java/libraries/io/examples/SimpleI2C/SimpleI2C.pde @@ -4,6 +4,9 @@ I2C i2c; // MCP4725 is a Digital-to-Analog converter using I2C // datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf +// also see DigitalAnalog_I2C_MCP4725 for how to write the +// same sketch in an object-oriented way + void setup() { //printArray(I2C.list()); i2c = new I2C(I2C.list()[0]); diff --git a/java/libraries/io/examples/SimpleInput/SimpleInput.pde b/java/libraries/io/examples/SimpleInput/SimpleInput.pde index d7a420ce12..5b6f5687a6 100644 --- a/java/libraries/io/examples/SimpleInput/SimpleInput.pde +++ b/java/libraries/io/examples/SimpleInput/SimpleInput.pde @@ -5,14 +5,18 @@ import processing.io.*; // see setup.png in the sketch folder for wiring details void setup() { - GPIO.pinMode(4, GPIO.INPUT); + // INPUT_PULLUP enables the built-in pull-up resistor for this pin + // left alone, the pin will read as HIGH + // connected to ground (via e.g. a button or switch) it will read LOW + GPIO.pinMode(4, GPIO.INPUT_PULLUP); } void draw() { - // sense the input pin - if (GPIO.digitalRead(4) == GPIO.HIGH) { + if (GPIO.digitalRead(4) == GPIO.LOW) { + // button is pressed fill(255); } else { + // button is not pressed fill(204); } stroke(255); diff --git a/java/libraries/io/examples/SPIAnalogDigital/SPIAnalogDigital.pde b/java/libraries/io/examples/SimpleSPI/SimpleSPI.pde similarity index 86% rename from java/libraries/io/examples/SPIAnalogDigital/SPIAnalogDigital.pde rename to java/libraries/io/examples/SimpleSPI/SimpleSPI.pde index bb1311adaf..a1b4e2b08d 100644 --- a/java/libraries/io/examples/SPIAnalogDigital/SPIAnalogDigital.pde +++ b/java/libraries/io/examples/SimpleSPI/SimpleSPI.pde @@ -5,6 +5,9 @@ SPI spi; // datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf // see setup.png in the sketch folder for wiring details +// also see AnalogDigital_SPI_MCP3001 for how to write the +// same sketch in an object-oriented way + void setup() { //printArray(SPI.list()); spi = new SPI(SPI.list()[0]); diff --git a/java/libraries/io/examples/SPIAnalogDigitalOOP/setup.png b/java/libraries/io/examples/SimpleSPI/setup.png similarity index 100% rename from java/libraries/io/examples/SPIAnalogDigitalOOP/setup.png rename to java/libraries/io/examples/SimpleSPI/setup.png diff --git a/java/libraries/io/examples/ServoSweep/ServoSweep.pde b/java/libraries/io/examples/SoftwareServoSweep/SoftwareServoSweep.pde similarity index 100% rename from java/libraries/io/examples/ServoSweep/ServoSweep.pde rename to java/libraries/io/examples/SoftwareServoSweep/SoftwareServoSweep.pde diff --git a/java/libraries/io/examples/ServoSweep/setup.png b/java/libraries/io/examples/SoftwareServoSweep/setup.png similarity index 100% rename from java/libraries/io/examples/ServoSweep/setup.png rename to java/libraries/io/examples/SoftwareServoSweep/setup.png diff --git a/java/libraries/io/examples/ServoSweep/setup_better.png b/java/libraries/io/examples/SoftwareServoSweep/setup_better.png similarity index 100% rename from java/libraries/io/examples/ServoSweep/setup_better.png rename to java/libraries/io/examples/SoftwareServoSweep/setup_better.png diff --git a/java/libraries/io/examples/Touch_I2C_MPR121/MPR121.pde b/java/libraries/io/examples/Touch_I2C_MPR121/MPR121.pde new file mode 100644 index 0000000000..0ef023820b --- /dev/null +++ b/java/libraries/io/examples/Touch_I2C_MPR121/MPR121.pde @@ -0,0 +1,112 @@ +import processing.io.I2C; + +// MPR121 is a capacitive-touch sensor controller with 12 channels +// datasheet: https://www.nxp.com/docs/en/data-sheet/MPR121.pdf + +class MPR121 extends I2C { + int address; + int touched; + + // registers used (there are more) + static final int EFD0LB = 0x04; // ELE0 Electrode Filtered Data LSB + static final int E0TTH = 0x41; // ELE0 Touch Threshold + static final int E0RTH = 0x42; // ELE0 Release Threshold + static final int E0BV = 0x1e; // ELE0 Baseline Value + static final int MHDR = 0x2b; // MHD Rising + static final int NHDR = 0x2c; // NHD Amount Rising + static final int NCLR = 0x2d; // NCL Rising + static final int MHDF = 0x2f; // MHD Falling + static final int NHDF = 0x30; // NHD Amount Falling + static final int NCLF = 0x31; // NCL Falling + static final int CDT = 0x5d; // Filter/Global CDT Configuration + static final int ECR = 0x5e; // Electrode Configuration + static final int SRST = 0x80; // Soft Reset + + // there can be more than one device connected to the bus + // as long as they have different addresses + // possible addresses: 0x5a (default) - 0x5d + MPR121(String dev, int address) { + super(dev); + this.address = address; + reset(); + } + + void update() { + beginTransmission(address); + write(0x00); + byte[] in = read(2); + // & 0xff makes sure the byte is not interpreted as a negative value + touched = (in[1] & 0xff) << 8 | (in[0] & 0xff); + } + + boolean touched(int channel) { + if (channel < 0 || 11 < channel) { + return false; + } + if ((touched & (1 << channel)) != 0) { + return true; + } else { + return false; + } + } + + void threshold(int touch, int release) { + for (int i=0; i < 12; i++) { + threshold(touch, release, i); + } + } + + void threshold(int touch, int release, int channel) { + if (channel < 0 || 11 < channel) { + return; + } + touch = constrain(touch, 0, 255); + release = constrain(release, 0, 255); + writeRegister(E0TTH + 2*channel, touch); + writeRegister(E0RTH + 2*channel, release); + } + + int analogRead(int channel) { + if (channel < 0 || 11 < channel) { + return 0; + } + beginTransmission(address); + write(EFD0LB + 2*channel); + byte[] in = read(2); + return (in[1] & 0xff) << 8 | (in[0] & 0xff); + } + + int analogReadBaseline(int channel) { + if (channel < 0 || 11 < channel) { + return 0; + } + beginTransmission(address); + write(E0BV + channel); + byte[] in = read(1); + return (in[0] & 0xff) << 2; + } + + void reset() { + writeRegister(SRST, 0x63); + delay(1); + threshold(12, 6); + // set baseline filtering control registers (see p. 12) + writeRegister(MHDR, 0x01); + writeRegister(NHDR, 0x01); + writeRegister(NCLR, 0x0e); + writeRegister(MHDF, 0x01); + writeRegister(NHDF, 0x05); + writeRegister(NCLF, 0x01); + // change sample interval to 1ms period from default 16ms + writeRegister(CDT, 0x20); + // start sampling + writeRegister(ECR, 0x8f); + } + + void writeRegister(int register, int value) { + beginTransmission(address); + write(register); + write(value); + endTransmission(); + } +} diff --git a/java/libraries/io/examples/Touch_I2C_MPR121/Touch_I2C_MPR121.pde b/java/libraries/io/examples/Touch_I2C_MPR121/Touch_I2C_MPR121.pde new file mode 100644 index 0000000000..58f69ad1c1 --- /dev/null +++ b/java/libraries/io/examples/Touch_I2C_MPR121/Touch_I2C_MPR121.pde @@ -0,0 +1,26 @@ +import processing.io.*; +MPR121 touch; + +// see setup.png in the sketch folder for wiring details + +void setup() { + size(600, 200); + //printArray(I2C.list()); + touch = new MPR121("i2c-1", 0x5a); +} + +void draw() { + background(204); + noStroke(); + + touch.update(); + + for (int i=0; i < 12; i++) { + if (touch.touched(i)) { + fill(255, 0, 0); + } else { + fill(255, 255, 255); + } + ellipse((width/12) * (i+0.5), height/2, 20, 20); + } +} diff --git a/java/libraries/io/examples/Touch_I2C_MPR121/setup.png b/java/libraries/io/examples/Touch_I2C_MPR121/setup.png new file mode 100644 index 0000000000..65bb7a04b2 Binary files /dev/null and b/java/libraries/io/examples/Touch_I2C_MPR121/setup.png differ diff --git a/java/libraries/io/library/linux-arm64/libprocessing-io.so b/java/libraries/io/library/linux-arm64/libprocessing-io.so new file mode 100755 index 0000000000..9659c68af3 Binary files /dev/null and b/java/libraries/io/library/linux-arm64/libprocessing-io.so differ diff --git a/java/libraries/io/library/linux-armv6hf/libprocessing-io.so b/java/libraries/io/library/linux-armv6hf/libprocessing-io.so index 94ed162d63..9d272c4d86 100755 Binary files a/java/libraries/io/library/linux-armv6hf/libprocessing-io.so and b/java/libraries/io/library/linux-armv6hf/libprocessing-io.so differ diff --git a/java/libraries/io/library/linux32/libprocessing-io.so b/java/libraries/io/library/linux32/libprocessing-io.so index 32a231170c..acc2bd6032 100755 Binary files a/java/libraries/io/library/linux32/libprocessing-io.so and b/java/libraries/io/library/linux32/libprocessing-io.so differ diff --git a/java/libraries/io/library/linux64/libprocessing-io.so b/java/libraries/io/library/linux64/libprocessing-io.so index 2979766a83..4c2d715886 100755 Binary files a/java/libraries/io/library/linux64/libprocessing-io.so and b/java/libraries/io/library/linux64/libprocessing-io.so differ diff --git a/java/libraries/io/src/native/Makefile b/java/libraries/io/src/native/Makefile index f33218a6c4..6a2c003738 100644 --- a/java/libraries/io/src/native/Makefile +++ b/java/libraries/io/src/native/Makefile @@ -3,7 +3,7 @@ OBJS := impl.o CC := gcc # prefix with -m32 to compile for linux32 -CFLAGS := -std=gnu99 -fPIC -g +CFLAGS := -std=gnu99 -fPIC -g -ffast-math CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include/linux LDFLAGS := -shared @@ -16,3 +16,5 @@ iface.h: clean: rm -f $(TARGET) $(OBJS) + +.PHONY: iface.h clean diff --git a/java/libraries/io/src/native/iface.h b/java/libraries/io/src/native/iface.h index 32e235e1e1..74decc1852 100644 --- a/java/libraries/io/src/native/iface.h +++ b/java/libraries/io/src/native/iface.h @@ -47,6 +47,30 @@ JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_readFile JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_writeFile (JNIEnv *, jclass, jstring, jbyteArray); +/* + * Class: processing_io_NativeInterface + * Method: raspbianGpioMemRead + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemRead + (JNIEnv *, jclass, jint); + +/* + * Class: processing_io_NativeInterface + * Method: raspbianGpioMemWrite + * Signature: (III)I + */ +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemWrite + (JNIEnv *, jclass, jint, jint, jint); + +/* + * Class: processing_io_NativeInterface + * Method: raspbianGpioMemWrite + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemSetPinBias + (JNIEnv *, jclass, jint, jint); + /* * Class: processing_io_NativeInterface * Method: pollDevice diff --git a/java/libraries/io/src/native/impl.c b/java/libraries/io/src/native/impl.c index 0f9402ab92..522aa310fa 100644 --- a/java/libraries/io/src/native/impl.c +++ b/java/libraries/io/src/native/impl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,143 @@ JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_writeFile } +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemRead + (JNIEnv *env, jclass cls, jint offset) +{ + // validate offset + if (4096 <= offset) { + return -EINVAL; + } + + int file = open("/dev/gpiomem", O_RDWR|O_SYNC); + if (file < 0) { + return -errno; + } + + uint32_t *mem = mmap(NULL, 4096, PROT_READ, MAP_SHARED, file, 0); + if (mem == MAP_FAILED) { + close(file); + return -errno; + } + + uint32_t value = mem[offset]; + + munmap(mem, 4096); + close(file); + return value; +} + + +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemWrite + (JNIEnv *env, jclass cls, jint offset, jint mask, jint value) +{ + // validate offset + if (4096 <= offset) { + return -EINVAL; + } + + int file = open("/dev/gpiomem", O_RDWR|O_SYNC); + if (file < 0) { + return -errno; + } + + uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0); + if (mem == MAP_FAILED) { + close(file); + return -errno; + } + + mem[offset] = (mem[offset] & ~mask) | (value & mask); + + munmap(mem, 4096); + close(file); + return 1; // number of bytes written +} + + +#define BCM2835_GPPUD_OFFSET (0x94 >> 2) +#define BCM2835_GPPUDCLK0_OFFSET (0x98 >> 2) +#define BCM2835_GPPUDCLK1_OFFSET (0x9c >> 2) + +JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemSetPinBias + (JNIEnv *env, jclass cls, jint gpio, jint mode) +{ + int ret = 0; // success + + int file = open("/dev/gpiomem", O_RDWR|O_SYNC); + if (file < 0) { + return -errno; + } + + uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0); + if (mem == MAP_FAILED) { + close(file); + return -errno; + } + + // validate arguments + if (gpio < 0 || 53 < gpio) { + ret = -EINVAL; + goto out; + } + + // see BCM2835 datasheet, p. 101 + uint32_t pud; + if (mode == 0) { + pud = 0; // floating + } else if (mode == 2) { + pud = 2; // pull-up + } else if (mode == 3) { + pud = 1; // pull-down + } else { + ret = -EINVAL; + goto out; + } + + /* + * From the BCM2835 datasheet, p. 101: + * + * The following sequence of events is required: + * 1. Write to GPPUD to set the required control signal (i.e. Pull-up or + * Pull-Down or neither to remove the current Pull-up/down) + * 2. Wait 150 cycles – this provides the required set-up time for the + * control signal + * 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads + * you wish to modify – NOTE only the pads which receive a clock will + * be modified, all others will retain their previous state. + * 4. Wait 150 cycles – this provides the required hold time for the + * control signal + * 5. Write to GPPUD to remove the control signal + * 6. Write to GPPUDCLK0/1 to remove the clock + */ + + // python-gpiozero uses a delay of 214 ns, so we do the same + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 214; + + mem[BCM2835_GPPUD_OFFSET] = pud; + nanosleep(&wait, NULL); + if (gpio < 32) { + mem[BCM2835_GPPUDCLK0_OFFSET] = 1 << gpio; + } else { + mem[BCM2835_GPPUDCLK1_OFFSET] = 1 << (gpio-32); + } + nanosleep(&wait, NULL); + mem[BCM2835_GPPUD_OFFSET] = 0; + if (gpio < 32) { + mem[BCM2835_GPPUDCLK0_OFFSET] = 0; + } else { + mem[BCM2835_GPPUDCLK1_OFFSET] = 0; + } + +out: + munmap(mem, 4096); + close(file); + return ret; +} + + JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_pollDevice (JNIEnv *env, jclass cls, jstring _fn, jint timeout) { @@ -166,29 +304,36 @@ JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferI2c jbyte *out, *in; packets.msgs = msgs; - - msgs[0].addr = slave; - msgs[0].flags = 0; - msgs[0].len = (*env)->GetArrayLength(env, _out); - out = (*env)->GetByteArrayElements(env, _out, NULL); - msgs[0].buf = out; + packets.nmsgs = 0; + + if (_out != NULL) { + msgs[packets.nmsgs].addr = slave; + msgs[packets.nmsgs].flags = 0; + msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _out); + out = (*env)->GetByteArrayElements(env, _out, NULL); + msgs[packets.nmsgs].buf = out; + packets.nmsgs++; + } if (_in != NULL) { + msgs[packets.nmsgs].addr = slave; + msgs[packets.nmsgs].flags = I2C_M_RD; // I2C_M_RECV_LEN is not supported + msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _in); in = (*env)->GetByteArrayElements(env, _in, NULL); - msgs[1].addr = slave; - msgs[1].flags = I2C_M_RD; // I2C_M_RECV_LEN is not supported - msgs[1].len = (*env)->GetArrayLength(env, _in); - msgs[1].buf = in; - packets.nmsgs = 2; - } else { - packets.nmsgs = 1; + msgs[packets.nmsgs].buf = in; + packets.nmsgs++; } + // set the timeout to 100ms - this helps slow devices such as the + // Arduino Uno to keep up + ioctl(handle, I2C_TIMEOUT, 10); int ret = ioctl(handle, I2C_RDWR, &packets); if (ret < 0) { ret = -errno; } - (*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT); + if (_out != NULL) { + (*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT); + } if (_in != NULL) { (*env)->ReleaseByteArrayElements(env, _in, in, 0); } diff --git a/java/libraries/io/src/processing/io/GPIO.java b/java/libraries/io/src/processing/io/GPIO.java index a0b9709553..711aafd808 100644 --- a/java/libraries/io/src/processing/io/GPIO.java +++ b/java/libraries/io/src/processing/io/GPIO.java @@ -328,7 +328,7 @@ public static void noInterrupts() { /** * Configures a pin to act either as input or output * @param pin GPIO pin - * @param mode GPIO.INPUT or GPIO.OUTPUT + * @param mode GPIO.INPUT, GPIO.INPUT_PULLUP, GPIO.INPUT_PULLDOWN, or GPIO.OUTPUT * @see digitalRead * @see digitalWrite * @see releasePin @@ -356,19 +356,15 @@ public static void pinMode(int pin, int mode) { } } - // delay to give udev a chance to change the file permissions behind our back - // there should really be a cleaner way for this - try { - Thread.sleep(500); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - // set direction and default level for outputs fn = String.format("/sys/class/gpio/gpio%d/direction", pin); String out; if (mode == INPUT) { out = "in"; + + // attempt to disable any pre-set pullups on the Raspberry Pi + NativeInterface.raspbianGpioMemSetPinBias(pin, mode); + } else if (mode == OUTPUT) { if (values.get(pin)) { out = "high"; @@ -376,13 +372,32 @@ public static void pinMode(int pin, int mode) { out = "low"; } } else if (mode == INPUT_PULLUP || mode == INPUT_PULLDOWN) { + out = "in"; + + // attempt to set pullups on the Raspberry Pi + ret = NativeInterface.raspbianGpioMemSetPinBias(pin, mode); + if (ret == -2) { // NOENT + System.err.println("Setting pullup or pulldown resistors is currently only supported on the Raspberry Pi running Raspbian. Continuing without."); + } else if (ret < 0) { + System.err.println("Error setting pullup or pulldown resistors: " + NativeInterface.getError(ret) + ". Continuing without."); + } // currently this can't be done in a non-platform-specific way, see // http://lists.infradead.org/pipermail/linux-rpi-kernel/2015-August/002146.html - throw new RuntimeException("Not yet implemented"); + } else { throw new IllegalArgumentException("Unknown mode"); } - ret = NativeInterface.writeFile(fn, out); + + // we need to give udev some time to change the file permissions behind our back + // retry for 500ms when writing to the file fails with -EACCES + long start = System.currentTimeMillis(); + do { + ret = NativeInterface.writeFile(fn, out); + if (ret == -13) { + Thread.yield(); + } + } while (ret == -13 && System.currentTimeMillis()-start < 500); + if (ret < 0) { throw new RuntimeException(fn + ": " + NativeInterface.getError(ret)); } @@ -447,13 +462,30 @@ public static void releasePin(int pin) { * Waits for the value of an input pin to change * @param pin GPIO pin * @param mode what to wait for: GPIO.CHANGE, GPIO.FALLING or GPIO.RISING - * @param timeout don't wait more than timeout milliseconds (-1 waits indefinitely) - * @return true if the interrupt occured, false if the timeout occured * @webref */ - public static boolean waitForInterrupt(int pin, int mode, int timeout) { + public static void waitFor(int pin, int mode) { + waitFor(pin, mode, -1); + } + + + /** + * Waits for the value of an input pin to change + * + * This function will throw a RuntimeException in case of a timeout. + * @param timeout don't wait more than timeout milliseconds + * @webref + */ + public static void waitFor(int pin, int mode, int timeout) { enableInterrupt(pin, mode); - return waitForInterrupt(pin, timeout); + if (waitForInterrupt(pin, timeout) == false) { + throw new RuntimeException("Timeout occurred"); + } + } + + + public static boolean waitForInterrupt(int pin, int mode, int timeout) { + throw new RuntimeException("The waitForInterrupt function has been renamed to waitFor. Please update your sketch accordingly."); } @@ -494,19 +526,4 @@ protected static boolean waitForInterrupt(int pin, int timeout) { return true; } } - - - /** - * Waits for the value of an input pin to change - * - * Make sure to setup the interrupt with enableInterrupt() before calling - * this function. This function will wait indefinitely for an interrupt - * to occur. - * @parm pin GPIO pin - * @see enableInterrupt - * @see disableInterrupt - */ - protected static void waitForInterrupt(int pin) { - waitForInterrupt(pin, -1); - } } diff --git a/java/libraries/io/src/processing/io/I2C.java b/java/libraries/io/src/processing/io/I2C.java index 1d0bfac31b..2e5dedb4e5 100644 --- a/java/libraries/io/src/processing/io/I2C.java +++ b/java/libraries/io/src/processing/io/I2C.java @@ -125,7 +125,7 @@ public void endTransmission() { transmitting = false; out = null; if (ret < 0) { - if (ret == -5) { // EIO + if (ret == -5 | ret == -121) { // EIO | EREMOTEIO System.err.println("The device did not respond. Check the cabling and whether you are using the correct address."); } throw new RuntimeException(NativeInterface.getError(ret)); @@ -185,7 +185,7 @@ public byte[] read(int len) { transmitting = false; out = null; if (ret < 0) { - if (ret == -5) { // EIO + if (ret == -5 | ret == -121) { // EIO | EREMOTEIO System.err.println("The device did not respond. Check the cabling and whether you are using the correct address."); } throw new RuntimeException(NativeInterface.getError(ret)); diff --git a/java/libraries/io/src/processing/io/LED.java b/java/libraries/io/src/processing/io/LED.java index 61635f4d0b..32925e6ea8 100644 --- a/java/libraries/io/src/processing/io/LED.java +++ b/java/libraries/io/src/processing/io/LED.java @@ -161,7 +161,7 @@ public static String[] list() { return new String[]{ "led0", "led1" }; } - ArrayList devs = new ArrayList(); + ArrayList devs = new ArrayList<>(); File dir = new File("/sys/class/leds"); File[] files = dir.listFiles(); if (files != null) { diff --git a/java/libraries/io/src/processing/io/NativeInterface.java b/java/libraries/io/src/processing/io/NativeInterface.java index 3b1b3e0c32..a05a71ecd5 100644 --- a/java/libraries/io/src/processing/io/NativeInterface.java +++ b/java/libraries/io/src/processing/io/NativeInterface.java @@ -62,6 +62,9 @@ public static int writeFile(String fn, String out) { } /* GPIO */ + public static native int raspbianGpioMemRead(int offset); + public static native int raspbianGpioMemWrite(int offset, int mask, int value); + public static native int raspbianGpioMemSetPinBias(int gpio, int mode); public static native int pollDevice(String fn, int timeout); /* I2C */ public static native int transferI2c(int handle, int slave, byte[] out, byte[] in); diff --git a/java/libraries/io/src/processing/io/PWM.java b/java/libraries/io/src/processing/io/PWM.java index 455a659e41..c33c9107cb 100644 --- a/java/libraries/io/src/processing/io/PWM.java +++ b/java/libraries/io/src/processing/io/PWM.java @@ -117,7 +117,7 @@ public void close() { // XXX: implicit clear()? // XXX: also check GPIO - String fn = "/sys/class/pwm/" + chip + "/export"; + String fn = "/sys/class/pwm/" + chip + "/unexport"; int ret = NativeInterface.writeFile(fn, Integer.toString(channel)); if (ret < 0) { if (ret == -2) { // ENOENT @@ -206,7 +206,6 @@ public void set(int period, float duty) { /** * Enables the PWM output with a preset period of 1 kHz - * @param duty duty cycle, 0.0 (always off) to 1.0 (always on) * @webref */ public void set(float duty) { diff --git a/java/libraries/io/src/processing/io/RPI.java b/java/libraries/io/src/processing/io/RPI.java deleted file mode 100644 index 523ffeb123..0000000000 --- a/java/libraries/io/src/processing/io/RPI.java +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Copyright (c) The Processing Foundation 2015 - Hardware I/O library developed by Gottfried Haider as part of GSoC 2015 - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.io; - - -/** - * @webref - */ -public class RPI { - - /* - * The Raspberry Pi has a 2x20 pin header for connecting various peripherals. - * The following constants describe how the pins of this header correspond - * to the pin numbering used by the CPU and by software ("GPIO pin number"). - * - * You can use this class to refer to a pin by its location on the header: - * e.g. GPIO.digitalWrite(RPI.PIN7, GPIO.HIGH) - * - * Alternatively, if you know a pins "true" pin number (GPIO number), you - * can use it directly. The following is equivalent to the example above: - * GPIO.digitalWrite(4, GPIO.HIGH) - * - * PIN1 is located on the "top left" of the column of pins, close to the two - * LEDs. PIN2 is next to it. PIN3 is below PIN1, and it goes on like this. - * See also: http://pi.gadgetoid.com/pinout - */ - - public static final int PIN1 = -1; /* 3v3 Power, can source up to 50 mA */ - public static final int PIN2 = -1; /* 5v Power, connected to input power */ - public static final int PIN3 = 2; /* GPIO 2, also: I2C data */ - public static final int PIN4 = -1; /* 5v Power, connected to input power */ - public static final int PIN5 = 3; /* GPIO 3, also: I2C clock */ - public static final int PIN6 = -1; /* Ground */ - public static final int PIN7 = 4; /* GPIO 4 */ - public static final int PIN8 = 14; /* GPIO 14, also: Serial TX */ - public static final int PIN9 = -1; /* Ground */ - public static final int PIN10 = 15; /* GPIO 15, also: Serial RX */ - public static final int PIN11 = 17; /* GPIO 17 */ - public static final int PIN12 = 18; /* GPIO 18 */ - public static final int PIN13 = 27; /* GPIO 27 */ - public static final int PIN14 = -1; /* Ground */ - public static final int PIN15 = 22; /* GPIO 22 */ - public static final int PIN16 = 23; /* GPIO 23 */ - public static final int PIN17 = -1; /* 3v3 Power, can source up to 50 mA */ - public static final int PIN18 = 24; /* GPIO 24 */ - public static final int PIN19 = 10; /* GPIO 10, also: SPI MOSI */ - public static final int PIN20 = -1; /* Ground */ - public static final int PIN21 = 9; /* GPIO 9, also: SPI MISO */ - public static final int PIN22 = 25; /* GPIO 25 */ - public static final int PIN23 = 11; /* GPIO 11, also: SPI SCLK */ - public static final int PIN24 = 8; /* GPIO 8, also: SPI Chip Select 0 */ - public static final int PIN25 = -1; /* Ground */ - public static final int PIN26 = 7; /* GPIO 7, also: SPI Chip Select 1 */ - public static final int PIN27 = 0; /* GPIO 0, also: HAT I2C data, reserved [currenly not accessible] */ - public static final int PIN28 = 1; /* GPIO 1, also HAT I2C data, reserved [currenly not accessible] */ - public static final int PIN29 = 5; /* GPIO 5 */ - public static final int PIN30 = -1; /* Ground */ - public static final int PIN31 = 6; /* GPIO 6 */ - public static final int PIN32 = 12; /* GPIO 12 */ - public static final int PIN33 = 13; /* GPIO 13 */ - public static final int PIN34 = -1; /* Ground */ - public static final int PIN35 = 19; /* GPIO 19, also: SPI MISO [currenly not accessible] */ - public static final int PIN36 = 16; /* GPIO 16 */ - public static final int PIN37 = 26; /* GPIO 26 */ - public static final int PIN38 = 20; /* GPIO 20, also: SPI MISO [currenly not accessible] */ - public static final int PIN39 = -1; /* Ground */ - public static final int PIN40 = 21; /* GPIO 21, also: SPI CLK [currenly not accessible] */ -} diff --git a/java/libraries/io/src/processing/io/SoftwareServo.java b/java/libraries/io/src/processing/io/SoftwareServo.java index feece76e2a..db5cbdcbef 100644 --- a/java/libraries/io/src/processing/io/SoftwareServo.java +++ b/java/libraries/io/src/processing/io/SoftwareServo.java @@ -83,8 +83,7 @@ public void attach(int pin) { /** - * Attaches a servo motor to a GPIO pin - * @param pin GPIO pin + * Attaches a servo motor to a GPIO pin using custom pulse widths * @param minPulse minimum pulse width in microseconds (default: 544, same as on Arduino) * @param maxPulse maximum pulse width in microseconds (default: 2400, same as on Arduino) * @webref @@ -98,7 +97,7 @@ public void attach(int pin, int minPulse, int maxPulse) { /** - * Move a servo motor to a given orientation + * Moves a servo motor to a given orientation * @param angle angle in degrees (controls speed and direction on continuous-rotation servos) * @webref */ diff --git a/java/libraries/net/.settings/org.eclipse.jdt.core.prefs b/java/libraries/net/.settings/org.eclipse.jdt.core.prefs index a11eccb8d4..ac3ca93e5c 100644 --- a/java/libraries/net/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/net/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,22 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 @@ -18,24 +25,39 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 @@ -44,6 +66,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line @@ -53,34 +76,40 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false org.eclipse.jdt.core.formatter.comment.format_block_comments=true org.eclipse.jdt.core.formatter.comment.format_comments=true org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=1 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true @@ -93,6 +122,7 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=2 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert @@ -102,6 +132,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -115,11 +146,15 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -146,9 +181,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declar org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -173,13 +213,20 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -223,9 +270,13 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_decla org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -262,9 +313,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -276,20 +330,59 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_decla org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never org.eclipse.jdt.core.formatter.lineSplit=80 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.text_block_indentation=0 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/java/libraries/net/.settings/org.eclipse.jdt.ui.prefs b/java/libraries/net/.settings/org.eclipse.jdt.ui.prefs index 7f5ba1ed84..66aaa0890e 100644 --- a/java/libraries/net/.settings/org.eclipse.jdt.ui.prefs +++ b/java/libraries/net/.settings/org.eclipse.jdt.ui.prefs @@ -1,3 +1,3 @@ eclipse.preferences.version=1 formatter_profile=_processing -formatter_settings_version=12 +formatter_settings_version=18 diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 11287c59ef..6e343f2c7a 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -45,11 +45,14 @@ * @see_external LIB_net/clientEvent */ public class Client implements Runnable { + + protected static final int MAX_BUFFER_SIZE = 1 << 27; // 128 MB + PApplet parent; Method clientEventMethod; Method disconnectEventMethod; - Thread thread; + volatile Thread thread; Socket socket; int port; String host; @@ -57,6 +60,8 @@ public class Client implements Runnable { public InputStream input; public OutputStream output; + final Object bufferLock = new Object[0]; + byte buffer[] = new byte[32768]; int bufferIndex; int bufferLast; @@ -90,24 +95,18 @@ public Client(PApplet parent, String host, int port) { // which would be called each time an event comes in try { clientEventMethod = - parent.getClass().getMethod("clientEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("clientEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } // do the same for disconnectEvent(Client c); try { disconnectEventMethod = - parent.getClass().getMethod("disconnectEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("disconnectEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } - } catch (ConnectException ce) { - ce.printStackTrace(); - dispose(); - } catch (IOException e) { e.printStackTrace(); dispose(); @@ -130,11 +129,18 @@ public Client(PApplet parent, Socket socket) throws IOException { thread.start(); // reflection to check whether host sketch has a call for - // public void disconnectEvent(processing.net.Client) + // public void clientEvent(processing.net.Client) + // which would be called each time an event comes in + try { + clientEventMethod = + parent.getClass().getMethod("clientEvent", Client.class); + } catch (Exception e) { + // no such method, or an error.. which is fine, just ignore + } + // do the same for disconnectEvent(Client c); try { disconnectEventMethod = - parent.getClass().getMethod("disconnectEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("disconnectEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -155,9 +161,14 @@ public Client(PApplet parent, Socket socket) throws IOException { public void stop() { if (disconnectEventMethod != null && thread != null){ try { - disconnectEventMethod.invoke(parent, new Object[] { this }); + disconnectEventMethod.invoke(parent, this); } catch (Exception e) { - e.printStackTrace(); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); disconnectEventMethod = null; } } @@ -206,16 +217,26 @@ public void dispose() { } + @Override public void run() { + byte[] readBuffer; + { // make the read buffer same size as socket receive buffer so that + // we don't waste cycles calling listeners when there is more data waiting + int readBufferSize = 1 << 16; // 64 KB (default socket receive buffer size) + try { + readBufferSize = socket.getReceiveBufferSize(); + } catch (SocketException ignore) { } + readBuffer = new byte[readBufferSize]; + } while (Thread.currentThread() == thread) { try { while (input != null) { - int value; + int readCount; // try to read a byte using a blocking read. // An exception will occur when the sketch is exits. try { - value = input.read(); + readCount = input.read(readBuffer, 0, readBuffer.length); } catch (SocketException e) { System.err.println("Client SocketException: " + e.getMessage()); // the socket had a problem reading so don't try to read from it again. @@ -224,31 +245,55 @@ public void run() { } // read returns -1 if end-of-stream occurs (for example if the host disappears) - if (value == -1) { + if (readCount == -1) { System.err.println("Client got end-of-stream."); stop(); return; } - synchronized (buffer) { - // todo: at some point buffer should stop increasing in size, - // otherwise it could use up all the memory. - if (bufferLast == buffer.length) { - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); - buffer = temp; + synchronized (bufferLock) { + int freeBack = buffer.length - bufferLast; + if (readCount > freeBack) { + // not enough space at the back + int bufferLength = bufferLast - bufferIndex; + byte[] targetBuffer = buffer; + if (bufferLength + readCount > buffer.length) { + // can't fit even after compacting, resize the buffer + // find the next power of two which can fit everything in + int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1; + if (newSize > MAX_BUFFER_SIZE) { + // buffer is full because client is not reading (fast enough) + System.err.println("Client: can't receive more data, buffer is full. " + + "Make sure you read the data from the client."); + stop(); + return; + } + targetBuffer = new byte[newSize]; + } + // compact the buffer (either in-place or into the new bigger buffer) + System.arraycopy(buffer, bufferIndex, targetBuffer, 0, bufferLength); + bufferLast -= bufferIndex; + bufferIndex = 0; + buffer = targetBuffer; } - buffer[bufferLast++] = (byte)value; + // copy all newly read bytes into the buffer + System.arraycopy(readBuffer, 0, buffer, bufferLast, readCount); + bufferLast += readCount; } // now post an event if (clientEventMethod != null) { try { - clientEventMethod.invoke(parent, new Object[] { this }); - } catch (Exception e) { - System.err.println("error, disabling clientEvent() for " + host); - e.printStackTrace(); - clientEventMethod = null; + clientEventMethod.invoke(parent, this); + } catch (Exception e) { + System.err.println("error, disabling clientEvent() for " + host); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); + clientEventMethod = null; } } } @@ -306,7 +351,9 @@ public String ip() { * @brief Returns the number of bytes in the buffer waiting to be read */ public int available() { - return (bufferLast - bufferIndex); + synchronized (bufferLock) { + return (bufferLast - bufferIndex); + } } @@ -321,8 +368,10 @@ public int available() { * @brief Clears the buffer */ public void clear() { - bufferLast = 0; - bufferIndex = 0; + synchronized (bufferLock) { + bufferLast = 0; + bufferIndex = 0; + } } @@ -339,9 +388,9 @@ public void clear() { * @brief Returns a value from the buffer */ public int read() { - if (bufferIndex == bufferLast) return -1; + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return -1; - synchronized (buffer) { int outgoing = buffer[bufferIndex++] & 0xff; if (bufferIndex == bufferLast) { // rewind bufferIndex = 0; @@ -364,8 +413,10 @@ public int read() { * @brief Returns the next byte in the buffer as a char */ public char readChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) read(); + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return (char) (-1); + return (char) read(); + } } @@ -392,9 +443,9 @@ public char readChar() { * @brief Reads everything in the buffer */ public byte[] readBytes() { - if (bufferIndex == bufferLast) return null; + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; - synchronized (buffer) { int length = bufferLast - bufferIndex; byte outgoing[] = new byte[length]; System.arraycopy(buffer, bufferIndex, outgoing, 0, length); @@ -417,9 +468,9 @@ public byte[] readBytes() { * @param max the maximum number of bytes to read */ public byte[] readBytes(int max) { - if (bufferIndex == bufferLast) return null; + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; - synchronized (buffer) { int length = bufferLast - bufferIndex; if (length > max) length = max; byte outgoing[] = new byte[length]; @@ -449,9 +500,9 @@ public byte[] readBytes(int max) { * @param bytebuffer passed in byte array to be altered */ public int readBytes(byte bytebuffer[]) { - if (bufferIndex == bufferLast) return 0; + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return 0; - synchronized (buffer) { int length = bufferLast - bufferIndex; if (length > bytebuffer.length) length = bytebuffer.length; System.arraycopy(buffer, bufferIndex, bytebuffer, 0, length); @@ -487,10 +538,11 @@ public int readBytes(byte bytebuffer[]) { * @param interesting character designated to mark the end of the data */ public byte[] readBytesUntil(int interesting) { - if (bufferIndex == bufferLast) return null; byte what = (byte)interesting; - synchronized (buffer) { + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; + int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { @@ -528,10 +580,11 @@ public byte[] readBytesUntil(int interesting) { * @param byteBuffer passed in byte array to be altered */ public int readBytesUntil(int interesting, byte byteBuffer[]) { - if (bufferIndex == bufferLast) return 0; byte what = (byte)interesting; - synchronized (buffer) { + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return 0; + int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { @@ -576,8 +629,9 @@ public int readBytesUntil(int interesting, byte byteBuffer[]) { * @brief Returns the buffer as a String */ public String readString() { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); + byte b[] = readBytes(); + if (b == null) return null; + return new String(b); } diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index bf4abced2d..61a877202a 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -52,10 +52,11 @@ public class Server implements Runnable { PApplet parent; Method serverEventMethod; - Thread thread; + volatile Thread thread; ServerSocket server; int port; - + + protected final Object clientsLock = new Object[0]; /** Number of clients currently connected. */ public int clientCount; /** Array of client objects, useful length is determined by clientCount. */ @@ -72,8 +73,6 @@ public Server(PApplet parent, int port) { /** - * @param parent typically use "this" - * @param port port used to transfer data * @param host when multiple NICs are in use, the ip (or name) to bind from */ public Server(PApplet parent, int port, String host) { @@ -99,9 +98,7 @@ public Server(PApplet parent, int port, String host) { // which is called when a new guy connects try { serverEventMethod = - parent.getClass().getMethod("serverEvent", - new Class[] { Server.class, - Client.class }); + parent.getClass().getMethod("serverEvent", Server.class, Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -127,26 +124,30 @@ public Server(PApplet parent, int port, String host) { */ public void disconnect(Client client) { client.stop(); - int index = clientIndex(client); - if (index != -1) { - removeIndex(index); + synchronized (clientsLock) { + int index = clientIndex(client); + if (index != -1) { + removeIndex(index); + } } } protected void removeIndex(int index) { - clientCount--; - // shift down the remaining clients - for (int i = index; i < clientCount; i++) { - clients[i] = clients[i+1]; + synchronized (clientsLock) { + clientCount--; + // shift down the remaining clients + for (int i = index; i < clientCount; i++) { + clients[i] = clients[i + 1]; + } + // mark last empty var for garbage collection + clients[clientCount] = null; } - // mark last empty var for garbage collection - clients[clientCount] = null; } protected void disconnectAll() { - synchronized (clients) { + synchronized (clientsLock) { for (int i = 0; i < clientCount; i++) { try { clients[i].stop(); @@ -161,20 +162,24 @@ protected void disconnectAll() { protected void addClient(Client client) { - if (clientCount == clients.length) { - clients = (Client[]) PApplet.expand(clients); + synchronized (clientsLock) { + if (clientCount == clients.length) { + clients = (Client[]) PApplet.expand(clients); + } + clients[clientCount++] = client; } - clients[clientCount++] = client; } protected int clientIndex(Client client) { - for (int i = 0; i < clientCount; i++) { - if (clients[i] == client) { - return i; + synchronized (clientsLock) { + for (int i = 0; i < clientCount; i++) { + if (clients[i] == client) { + return i; + } } + return -1; } - return -1; } @@ -219,7 +224,7 @@ static public String ip() { * @usage application */ public Client available() { - synchronized (clients) { + synchronized (clientsLock) { int index = lastAvailable + 1; if (index >= clientCount) index = 0; @@ -288,19 +293,25 @@ public void dispose() { } + @Override public void run() { while (Thread.currentThread() == thread) { try { Socket socket = server.accept(); Client client = new Client(parent, socket); - synchronized (clients) { + synchronized (clientsLock) { addClient(client); if (serverEventMethod != null) { try { - serverEventMethod.invoke(parent, new Object[] { this, client }); + serverEventMethod.invoke(parent, this, client); } catch (Exception e) { System.err.println("Disabling serverEvent() for port " + port); - e.printStackTrace(); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); serverEventMethod = null; } } @@ -314,9 +325,6 @@ public void run() { e.printStackTrace(); thread = null; } - try { - Thread.sleep(8); - } catch (InterruptedException ex) { } } } @@ -333,39 +341,45 @@ public void run() { * @param data data to write */ public void write(int data) { // will also cover char - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } public void write(byte data[]) { - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } public void write(String data) { - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } diff --git a/java/libraries/pdf/.settings/org.eclipse.jdt.core.prefs b/java/libraries/pdf/.settings/org.eclipse.jdt.core.prefs index f3b4e11d65..02a284792f 100644 --- a/java/libraries/pdf/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/pdf/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,22 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 @@ -18,24 +25,39 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 @@ -44,6 +66,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line @@ -53,32 +76,38 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false org.eclipse.jdt.core.formatter.comment.format_block_comments=true org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=1 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true @@ -90,6 +119,7 @@ org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=2 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert @@ -99,6 +129,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -112,11 +143,15 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert @@ -143,9 +178,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declar org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert @@ -170,13 +210,20 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert @@ -220,9 +267,13 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_decla org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert @@ -259,9 +310,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -273,20 +327,59 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_decla org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never org.eclipse.jdt.core.formatter.lineSplit=80 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.text_block_indentation=0 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/java/libraries/pdf/.settings/org.eclipse.jdt.ui.prefs b/java/libraries/pdf/.settings/org.eclipse.jdt.ui.prefs index 0d6ea5b9dd..24dec57837 100644 --- a/java/libraries/pdf/.settings/org.eclipse.jdt.ui.prefs +++ b/java/libraries/pdf/.settings/org.eclipse.jdt.ui.prefs @@ -1,4 +1,4 @@ eclipse.preferences.version=1 formatter_profile=_processing -formatter_settings_version=12 +formatter_settings_version=18 org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java index a84c6108f7..5987508c6a 100644 --- a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java +++ b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java @@ -1,7 +1,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2005-11 Ben Fry and Casey Reas + Copyright (c) 2005-12 Ben Fry and Casey Reas + Copyright (c) 2012-18 The Processing Foundation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -550,6 +551,14 @@ public void filter(int kind, float param) { // + protected void blendModeImpl() { + if (blendMode != REPLACE && blendMode != BLEND) { + showMissingWarning("blendMode"); + } + } + + // + public void copy(int sx1, int sy1, int sx2, int sy2, int dx1, int dy1, int dx2, int dy2) { nope("copy"); diff --git a/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs b/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs index f709eac1ee..87b7a7a3a6 100644 --- a/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,13 @@ -#Sat Nov 12 10:56:44 CST 2011 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java/libraries/serial/library/jssc.jar b/java/libraries/serial/library/jssc.jar index 93269cfabe..bf5640670c 100644 Binary files a/java/libraries/serial/library/jssc.jar and b/java/libraries/serial/library/jssc.jar differ diff --git a/java/libraries/serial/library/linux-arm64/libjSSC-2.8.so b/java/libraries/serial/library/linux-arm64/libjSSC-2.8.so new file mode 100755 index 0000000000..38813ae5fa Binary files /dev/null and b/java/libraries/serial/library/linux-arm64/libjSSC-2.8.so differ diff --git a/java/src/processing/mode/java/AutoFormat.java b/java/src/processing/mode/java/AutoFormat.java index ec61540dc0..8aa3cbeaa8 100644 --- a/java/src/processing/mode/java/AutoFormat.java +++ b/java/src/processing/mode/java/AutoFormat.java @@ -436,8 +436,10 @@ static private void trimRight(final StringBuilder sb) { /** Entry point */ public String format(final String source) { final String normalizedText = source.replaceAll("\r", ""); - final String cleanText = - normalizedText + (normalizedText.endsWith("\n") ? "" : "\n"); + String cleanText = normalizedText; + if (!normalizedText.endsWith("\n")) { + cleanText += "\n"; + } // Globals' description at top of file. result.setLength(0); @@ -459,8 +461,8 @@ public String format(final String source) { ind = new boolean[10]; p_flg = new int[10]; s_tabs = new int[20][10]; - doWhileFlags = new Stack(); - ifWhileForFlags = new Stack(); + doWhileFlags = new Stack<>(); + ifWhileForFlags = new Stack<>(); chars = cleanText.toCharArray(); @@ -639,25 +641,48 @@ public String format(final String source) { break; case '"': + case '“': + case '”': case '\'': + case '‘': + case '’': inStatementFlag = true; - buf.append(c); + char realQuote = c; + if (c == '“' || c == '”') realQuote = '"'; + if (c == '‘' || c == '’') realQuote = '\''; + buf.append(realQuote); + + char otherQuote = c; + if (c == '“') otherQuote = '”'; + if (c == '”') otherQuote = '“'; + if (c == '‘') otherQuote = '’'; + if (c == '’') otherQuote = '‘'; + char cc = nextChar(); - while (!EOF && cc != c) { + // In a proper string, all the quotes tested are c. In a curly-quoted + // string, there are three possible end quotes: c, its reverse, and + // the correct straight quote. + while (!EOF && cc != otherQuote && cc != realQuote && cc != c) { buf.append(cc); if (cc == '\\') { buf.append(cc = nextChar()); } - if (cc == '\n') { - writeIndentedLine(); - startFlag = true; - } + + // Syntax error: unterminated string. Leave \n in nextChar, so it + // feeds back into the loop. + if (peek() == '\n') break; cc = nextChar(); } - buf.append(cc); - if (readForNewLine()) { - // push a newline into the stream - chars[pos--] = '\n'; + if (cc == otherQuote || cc == realQuote || cc == c) { + buf.append(realQuote); + if (readForNewLine()) { + // push a newline into the stream + chars[pos--] = '\n'; + } + } else { + // We've had a syntax error if the string wasn't terminated by EOL/ + // EOF, just abandon this statement. + inStatementFlag = false; } break; diff --git a/java/src/processing/mode/java/Compiler.java b/java/src/processing/mode/java/Compiler.java index c62b4c000a..cfe9eb97d9 100644 --- a/java/src/processing/mode/java/Compiler.java +++ b/java/src/processing/mode/java/Compiler.java @@ -39,7 +39,7 @@ public class Compiler { static HashMap importSuggestions; static { - importSuggestions = new HashMap(); + importSuggestions = new HashMap<>(); importSuggestions.put("Arrays", "java.util.Arrays"); importSuggestions.put("Collections", "java.util.Collections"); importSuggestions.put("Date", "java.util.Date"); @@ -54,7 +54,7 @@ public class Compiler { * @param sketch Sketch object to be compiled, used for placing exceptions * @param buildPath Where the temporary files live and will be built from. * @return true if successful. - * @throws RunnerException Only if there's a problem. Only then. + * @throws SketchException Only if there's a problem. Only then. */ static public boolean compile(JavaBuild build) throws SketchException { @@ -68,6 +68,7 @@ static public boolean compile(JavaBuild build) throws SketchException { //"-noExit", // not necessary for ecj "-source", "1.7", "-target", "1.7", + "-encoding", "utf8", "-classpath", build.getClassPath(), "-nowarn", // we're not currently interested in warnings (works in ecj) "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath @@ -166,6 +167,8 @@ public void close() { } exception = new SketchException(errorMessage); } + String[] parts = null; + if (errorMessage.startsWith("The import ") && errorMessage.endsWith("cannot be resolved")) { // The import poo cannot be resolved @@ -188,7 +191,8 @@ public void close() { } "You might be missing a library."); System.err.println("Libraries must be " + "installed in a folder named 'libraries' " + - "inside the 'sketchbook' folder."); + "inside the sketchbook folder " + + "(see the Preferences window)."); } } @@ -211,8 +215,8 @@ public void close() { } String suggestion = importSuggestions.get(what); if (suggestion != null) { System.err.println("You may need to add \"import " + suggestion + ";\" to the top of your sketch."); - System.err.println("To make sketches more portable, imports that are not part of the Processing API have been removed from Processing 2.0."); - System.err.println("See the changes page for more information: http://wiki.processing.org/w/Changes"); + System.err.println("To make sketches more portable, imports that are not part of the Processing API were removed in Processing 2."); + System.err.println("See the changes page for more information: https://github.com/processing/processing/wiki/Changes"); } } @@ -252,9 +256,18 @@ public void close() { } // "Duplicate nested type xxx" // "Duplicate local variable xxx" + } else if (null != (parts = PApplet.match(errorMessage, + "literal (\\S*) of type (\\S*) is out of range"))) { + if ("int".equals(parts[2])) { + exception.setMessage("The type int can't handle numbers that big. Try " + + parts[1] + "L to upgrade to long."); + } else { + // I'd like to give an essay on BigInteger and BigDecimal, but + // this margin is too narrow to contain it. + exception.setMessage("Even the type " + parts[2] + " can't handle " + + parts[1] + ". Research big numbers in Java."); + } } else { - String[] parts = null; - // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX //xxx("blah"); // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX diff --git a/java/src/processing/mode/java/Debugger.java b/java/src/processing/mode/java/Debugger.java index 496cbb96ca..7b37a96f96 100644 --- a/java/src/processing/mode/java/Debugger.java +++ b/java/src/processing/mode/java/Debugger.java @@ -2,7 +2,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation + + Copyright (c) 2012-19 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -29,16 +30,17 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.JTree; // needed for javadocs import javax.swing.tree.DefaultMutableTreeNode; +import processing.app.Messages; +import processing.app.RunnerListenerEdtAdapter; import processing.app.Sketch; import processing.app.SketchCode; import processing.mode.java.debug.*; @@ -69,7 +71,7 @@ public class Debugger { protected ReferenceType mainClass; /// holds all loaded classes in the debuggee VM - protected Set classes = new HashSet<>(); + protected Set classes = new LinkedHashSet<>(); /// listeners for class load events protected List classLoadListeners = new ArrayList<>(); @@ -125,24 +127,12 @@ public ReferenceType getMainClass() { /** - * Get the {@link ReferenceType} for a class name. - * @param name the class name - * @return the {@link ReferenceType} or null if not found - * (e.g. not yet loaded) + * Get the main and nested {@link ReferenceType}s for the sketch. + * @return a list of main and nested {@link ReferenceType}s, + * empty list if nothing found (e.g. not yet loaded) */ - public ReferenceType getClass(String name) { - if (name == null) { - return null; - } - if (name.equals(mainClassName)) { - return mainClass; - } - for (ReferenceType rt : classes) { - if (rt.name().equals(name)) { - return rt; - } - } - return null; + public Set getClasses() { + return classes; } @@ -195,28 +185,28 @@ public synchronized void startDebug() { Sketch sketch = editor.getSketch(); JavaBuild build = new JavaBuild(sketch); - log(Level.INFO, "building sketch: {0}", sketch.getName()); + log("building sketch: " + sketch.getName()); //LineMapping.addLineNumbers(sketch); // annotate // mainClassName = build.build(false); mainClassName = build.build(true); //LineMapping.removeLineNumbers(sketch); // annotate - log(Level.INFO, "class: {0}", mainClassName); + log("class: " + mainClassName); // folder with assembled/preprocessed src srcPath = build.getSrcFolder().getPath(); - log(Level.INFO, "build src: {0}", srcPath); + log("build src: " + srcPath); // folder with compiled code (.class files) - log(Level.INFO, "build bin: {0}", build.getBinFolder().getPath()); + log("build bin: " + build.getBinFolder().getPath()); if (mainClassName != null) { // generate the source line mapping //lineMap = LineMapping.generateMapping(srcPath + File.separator + mainClassName + ".java"); - log(Level.INFO, "launching debuggee runtime"); - runtime = new Runner(build, editor); + log("launching debuggee runtime"); + runtime = new Runner(build, new RunnerListenerEdtAdapter(editor)); VirtualMachine vm = runtime.debug(null); // non-blocking if (vm == null) { - log(Level.SEVERE, "error 37: launch failed"); + loge("error 37: launch failed", null); } // start receiving vm events @@ -239,7 +229,12 @@ public synchronized void startDebug() { public synchronized void stopDebug() { editor.variableInspector().lock(); if (runtime != null) { - log(Level.INFO, "closing runtime"); + Messages.log("closing runtime"); + + for (LineBreakpoint bp : breakpoints) { + bp.detach(); + } + runtime.close(); runtime = null; //build = null; @@ -383,7 +378,7 @@ synchronized void setBreakpoint(LineID line) { return; } breakpoints.add(new LineBreakpoint(line, this)); - log(Level.INFO, "set breakpoint on line {0}", line); + log("set breakpoint on line " + line); } @@ -411,16 +406,16 @@ void removeBreakpoint(int lineIdx) { if (bp != null) { bp.remove(); breakpoints.remove(bp); - log(Level.INFO, "removed breakpoint {0}", bp); + log("removed breakpoint " + bp); } } /** Remove all breakpoints. */ synchronized void clearBreakpoints() { - //TODO: handle busy-ness correctly + // TODO: handle busy-ness correctly if (isBusy()) { - log(Level.WARNING, "busy"); + log("busy"); return; } @@ -436,9 +431,9 @@ synchronized void clearBreakpoints() { * @param tabFilename the tab's file name */ synchronized void clearBreakpoints(String tabFilename) { - //TODO: handle busy-ness correctly + // TODO: handle busy-ness correctly if (isBusy()) { - log(Level.WARNING, "busy"); + log("busy"); return; } @@ -534,8 +529,14 @@ synchronized List getBreakpoints(String tabFilename) { * @param es Incoming set of events from VM */ public synchronized void vmEvent(EventSet es) { + VirtualMachine vm = vm(); + if (vm != null && vm != es.virtualMachine()) { + // This is no longer VM we are interested in, + // we already cleaned up and run different VM now. + return; + } for (Event e : es) { - log(Level.INFO, "*** VM Event: {0}", e.toString()); + log("*** VM Event: " + e); if (e instanceof VMStartEvent) { vmStartEvent(); @@ -558,21 +559,25 @@ public synchronized void vmEvent(EventSet es) { } } + private void createClassPrepareRequest(String name) { + ClassPrepareRequest classPrepareRequest = runtime.vm().eventRequestManager().createClassPrepareRequest(); + classPrepareRequest.addClassFilter(name); + classPrepareRequest.enable(); + } + private void vmStartEvent() { // break on main class load - log(Level.INFO, "requesting event on main class load: {0}", mainClassName); - ClassPrepareRequest mainClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); - mainClassPrepare.addClassFilter(mainClassName); - mainClassPrepare.enable(); - + log("requesting event on main class load: " + mainClassName); + createClassPrepareRequest(mainClassName); + createClassPrepareRequest(mainClassName + "$*"); // break on loading custom classes for (SketchCode tab : editor.getSketch().getCode()) { if (tab.isExtension("java")) { - log(Level.INFO, "requesting event on class load: {0}", tab.getPrettyName()); - ClassPrepareRequest customClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); - customClassPrepare.addClassFilter(tab.getPrettyName()); - customClassPrepare.enable(); + log("requesting event on class load: " + tab.getPrettyName()); + String name = tab.getPrettyName(); + createClassPrepareRequest(name); + createClassPrepareRequest(name + "$*"); } } runtime.vm().resume(); @@ -587,11 +592,12 @@ private void vmClassPrepareEvent(ClassPrepareEvent ce) { if (rt.name().equals(mainClassName)) { //printType(rt); mainClass = rt; - log(Level.INFO, "main class load: {0}", rt.name()); + classes.add(rt); + log("main class load: " + rt.name()); started = true; // now that main class is loaded, we're started } else { classes.add(rt); // save loaded classes - log(Level.INFO, "class load: {0}", rt.name()); + log("class load: {0}" + rt.name()); } // notify listeners @@ -694,7 +700,7 @@ protected void stepOutIntoViewOrContinue() { continueDebug(); } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } } @@ -748,7 +754,7 @@ protected void printStackTrace(ThreadReference t) { System.out.println(i++ + ": " + f.toString()); } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } } @@ -857,9 +863,9 @@ protected void printLocalVariables(ThreadReference t) { } } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } catch (AbsentInformationException ex) { - System.out.println("local variable information not available"); + log("local variable information not available"); } } @@ -876,7 +882,7 @@ protected void updateVariableInspector(ThreadReference t) { try { if (t.frameCount() == 0) { // TODO: needs to be handled in a better way: - log(Level.WARNING, "call stack empty"); + log("call stack empty"); } else { final VariableInspector vi = editor.variableInspector(); // first get data @@ -901,7 +907,7 @@ public void run() { }); } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } } @@ -920,7 +926,7 @@ protected String thisName(ThreadReference t) { return ref == null ? "" : ref.referenceType().name(); } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); return ""; } } @@ -940,7 +946,7 @@ protected String currentLocation(ThreadReference t) { return locationToString(t.frame(0).location()); } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); return ""; } } @@ -984,9 +990,9 @@ protected List getLocals(ThreadReference t, int depth) { } } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } catch (AbsentInformationException ex) { - log(Level.WARNING, "local variable information not available", ex); + loge("local variable information not available", ex); } return vars; } @@ -1009,7 +1015,7 @@ protected List getThisFields(ThreadReference t, int depth, return getFields(thisObj, depth, includeInherited); } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } return new ArrayList<>(); } @@ -1098,7 +1104,7 @@ protected List getStackTrace(ThreadReference t) { stack.add(new DefaultMutableTreeNode(locationToString(f.location()))); } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } return stack; } @@ -1131,7 +1137,7 @@ protected void printThis(ThreadReference t) { } } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } } @@ -1150,7 +1156,7 @@ protected void printSourceLocation(ThreadReference t) { printSourceLocation(l); } } catch (IncompatibleThreadStateException ex) { - log(Level.SEVERE, null, ex); + logitse(ex); } } @@ -1166,7 +1172,7 @@ protected void printSourceLocation(Location l) { System.out.println(getSourceLine(l.sourcePath(), l.lineNumber(), 2)); } catch (AbsentInformationException ex) { - log(Level.SEVERE, null, ex); + log("absent information", ex); } } @@ -1180,7 +1186,7 @@ protected void printSourceLocation(Location l) { */ protected String getSourceLine(String filePath, int lineNo, int radius) { if (lineNo == -1) { - log(Level.SEVERE, "invalid line number: {0}", lineNo); + loge("invalid line number: " + lineNo, null); return ""; } //System.out.println("getting line: " + lineNo); @@ -1211,7 +1217,7 @@ protected String getSourceLine(String filePath, int lineNo, int radius) { return f.getName() + ":" + lineNo; } catch (IOException ex) { - log(Level.SEVERE, null, ex); + loge("other io exception", ex); return ""; } } @@ -1248,7 +1254,7 @@ protected LineID locationToLineID(Location l) { return javaToSketchLine(new LineID(l.sourceName(), l.lineNumber() - 1)); } catch (AbsentInformationException ex) { - log(Level.SEVERE, null, ex); + loge("absent information", ex); return null; } } @@ -1384,30 +1390,39 @@ protected void stopTrackingLineChanges() { } - static private void log(Level level, String msg) { - Logger.getLogger(Debugger.class.getName()).log(level, msg); + private void log(String msg, Object... args) { + if (args != null && args.length != 0) { + Messages.logf(getClass().getName() + " " + msg, args); + } else { + Messages.log(getClass().getName() + " " + msg); + } + } + + + private void loge(String msg, Throwable t) { + if (t != null) { + Messages.loge(getClass().getName() + " " + msg, t); + } else { + Messages.loge(getClass().getName() + " " + msg); + } } - static private void log(Level level, String msg, Object obj) { - Logger.getLogger(Debugger.class.getName()).log(level, msg, obj); + static private void logitse(Throwable t) { + Messages.loge("incompatible thread state?", t); } /** * Interface for VM callbacks. - * - * @author Martin Leopold */ protected interface VMEventListener { - - /** - * Receive an event from the VM. Events are sent in batches. See - * documentation of EventSet for more information. - * - * @param es Set of events - */ - void vmEvent(EventSet es); + /** + * Receive an event from the VM. Events are sent in batches. See + * documentation of EventSet for more information. + * @param es Set of events + */ + void vmEvent(EventSet es); } @@ -1418,40 +1433,36 @@ protected interface VMEventListener { * @author Martin Leopold */ protected static class VMEventReader extends Thread { - - EventQueue eventQueue; - VMEventListener listener; - - /** - * Construct a VMEventReader. Needs to be kicked off with start() once - * constructed. - * - * @param eventQueue The queue to read events from. Can be obtained from a - * VirtualMachine via eventQueue(). - * @param listener the listener to forward events to. - */ - public VMEventReader(EventQueue eventQueue, VMEventListener listener) { - super("VM Event Thread"); - this.eventQueue = eventQueue; - this.listener = listener; - } - - @Override - public void run() { - try { - while (true) { - EventSet eventSet = eventQueue.remove(); - listener.vmEvent(eventSet); - /* - * for (Event e : eventSet) { System.out.println("VM Event: " + - * e.toString()); } - */ - } - } catch (VMDisconnectedException e) { - Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect"); - } catch (Exception e) { - Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e); - } + EventQueue eventQueue; + VMEventListener listener; + + /** + * Construct a VMEventReader. Needs to be kicked off with start() once + * constructed. + * + * @param eventQueue The queue to read events from. Can be obtained from a + * VirtualMachine via eventQueue(). + * @param listener the listener to forward events to. + */ + public VMEventReader(EventQueue eventQueue, VMEventListener listener) { + super("VM Event Thread"); + this.eventQueue = eventQueue; + this.listener = listener; + } + + @Override + public void run() { + try { + while (true) { + EventSet eventSet = eventQueue.remove(); + listener.vmEvent(eventSet); + // for (Event e : eventSet) { System.out.println("VM Event: " + e.toString()); } + } + } catch (VMDisconnectedException e) { + Messages.log("VMEventReader quit on VM disconnect"); + } catch (Exception e) { + Messages.loge("VMEventReader quit", e); } + } } } diff --git a/java/src/processing/mode/java/JavaBuild.java b/java/src/processing/mode/java/JavaBuild.java old mode 100755 new mode 100644 index 5c9c2a9d65..85413a4eae --- a/java/src/processing/mode/java/JavaBuild.java +++ b/java/src/processing/mode/java/JavaBuild.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org -Copyright (c) 2012-16 The Processing Foundation +Copyright (c) 2012-19 The Processing Foundation Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology @@ -38,6 +38,7 @@ import org.apache.tools.ant.ProjectHelper; import processing.app.Base; +import processing.app.Language; import processing.app.Library; import processing.app.Messages; import processing.app.Mode; @@ -52,12 +53,11 @@ import processing.core.PConstants; import processing.data.StringList; import processing.data.XML; +import processing.mode.java.pdex.SourceUtils; import processing.mode.java.preproc.PdePreprocessor; import processing.mode.java.preproc.PreprocessorResult; import processing.mode.java.preproc.SurfaceInfo; -// Would you believe there's a java.lang.Compiler class? I wouldn't. - public class JavaBuild { public static final String PACKAGE_REGEX = @@ -222,10 +222,11 @@ public String preprocess(File srcFolder, // Remove the entries being moved to settings(). They will be re-inserted // by writeFooter() when it emits the settings() method. - if (sizeInfo != null && sizeInfo.hasSettings()) { -// String sizeStatement = sizeInfo.getStatement(); + // If the user already has a settings() method, don't mess with anything. + // https://github.com/processing/processing/issues/4703 + if (!PdePreprocessor.hasSettingsMethod(bigCode.toString()) && + sizeInfo != null && sizeInfo.hasSettings()) { for (String stmt : sizeInfo.getStatements()) { - //System.out.format("size stmt is '%s'%n", sizeStatement); // Don't remove newlines (and while you're at it, just keep spaces) // https://github.com/processing/processing/issues/3654 stmt = stmt.trim(); @@ -245,19 +246,18 @@ public String preprocess(File srcFolder, File outputFolder = (packageName == null) ? srcFolder : new File(srcFolder, packageName.replace('.', '/')); outputFolder.mkdirs(); -// Base.openFolder(outputFolder); final File java = new File(outputFolder, sketch.getName() + ".java"); - final PrintWriter stream = new PrintWriter(new FileWriter(java)); try { - result = preprocessor.write(stream, bigCode.toString(), codeFolderPackages); - } finally { - stream.close(); + final PrintWriter writer = PApplet.createWriter(java); + try { + result = preprocessor.write(writer, bigCode.toString(), codeFolderPackages); + } finally { + writer.close(); + } + } catch (RuntimeException re) { + re.printStackTrace(); + throw new SketchException("Could not write " + java.getAbsolutePath()); } - } catch (FileNotFoundException fnfe) { - fnfe.printStackTrace(); - String msg = "Build folder disappeared or could not be written"; - throw new SketchException(msg); - } catch (antlr.RecognitionException re) { // re also returns a column that we're not bothering with for now // first assume that it's the main file @@ -267,40 +267,34 @@ public String preprocess(File srcFolder, // then search through for anyone else whose preprocName is null, // since they've also been combined into the main pde. int errorFile = findErrorFile(errorLine); -// System.out.println("error line is " + errorLine + ", file is " + errorFile); errorLine -= sketch.getCode(errorFile).getPreprocOffset(); -// System.out.println(" preproc offset for that file: " + sketch.getCode(errorFile).getPreprocOffset()); - -// System.out.println("i found this guy snooping around.."); -// System.out.println("whatcha want me to do with 'im boss?"); -// System.out.println(errorLine + " " + errorFile + " " + code[errorFile].getPreprocOffset()); String msg = re.getMessage(); - //System.out.println(java.getAbsolutePath()); -// System.out.println(bigCode); - - if (msg.contains("expecting RCURLY")) { - //if (msg.equals("expecting RCURLY, found 'null'")) { - // This can be a problem since the error is sometimes listed as a line - // that's actually past the number of lines. For instance, it might - // report "line 15" of a 14 line program. Added code to highlightLine() - // inside Editor to deal with this situation (since that code is also - // useful for other similar situations). - throw new SketchException("Found one too many { characters " + - "without a } to match it.", - errorFile, errorLine, re.getColumn(), false); - } - - if (msg.contains("expecting LCURLY")) { - System.err.println(msg); - String suffix = "."; - String[] m = PApplet.match(msg, "found ('.*')"); - if (m != null) { - suffix = ", not " + m[1] + "."; + if (msg.contains("expecting RCURLY") || msg.contains("expecting LCURLY")) { + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode sc = sketch.getCode(i); + if (sc.isExtension("pde")) { + String s = sc.getProgram(); + int[] braceTest = SourceUtils.checkForMissingBraces( + SourceUtils.scrubCommentsAndStrings(s) + "\n", 0, s.length()+1); + if (braceTest[0] == 0) continue; + + // Completely ignoring the errorFile/errorLine given since it's + // likely to be the wrong tab. For the same reason, I'm not showing + // the result of PApplet.match(msg, "found ('.*')") on missing + // LCURLY. + throw new SketchException(braceTest[0] > 0 + ? "Found an extra { character without a } to match it." + : "Found an extra } character without a { to match it.", + i, braceTest[1], braceTest[2], false); + } } - throw new SketchException("Was expecting a { character" + suffix, - errorFile, errorLine, re.getColumn(), false); + // If we're still here, there's the right brackets, just not in the + // right place. Passing on the original error. + throw new SketchException( + msg.replace("LCURLY", "{").replace("RCURLY", "}"), + errorFile, errorLine, re.getColumn(), false); } if (msg.indexOf("expecting RBRACK") != -1) { @@ -341,9 +335,30 @@ public String preprocess(File srcFolder, // System.err.println("and then she tells me " + tsre.toString()); // TODO not tested since removing ORO matcher.. ^ could be a problem - String mess = "^line (\\d+):(\\d+):\\s"; + String locationRegex = "^line (\\d+):(\\d+):\\s"; + String message = tsre.getMessage(); + String[] m; + + if (null != (m = PApplet.match(tsre.toString(), + "unexpected char: (.*)"))) { + char c = 0; + if (m[1].startsWith("0x")) { // Hex + c = (char) PApplet.unhex(m[1].substring(2)); + } else if (m[1].length() == 3) { // Quoted + c = m[1].charAt(1); + } else if (m[1].length() == 1) { // Alone + c = m[1].charAt(0); + } + if (c == '\u201C' || c == '\u201D' || // “” + c == '\u2018' || c == '\u2019') { // ‘’ + message = Language.interpolate("editor.status.bad_curly_quote", c); + } else if (c != 0) { + message = "Not expecting symbol " + m[1] + + ", which is " + Character.getName(c) + "."; + } + } - String[] matches = PApplet.match(tsre.toString(), mess); + String[] matches = PApplet.match(tsre.toString(), locationRegex); if (matches != null) { int errorLine = Integer.parseInt(matches[1]) - 1; int errorColumn = Integer.parseInt(matches[2]); @@ -358,7 +373,7 @@ public String preprocess(File srcFolder, } errorLine -= sketch.getCode(errorFile).getPreprocOffset(); - throw new SketchException(tsre.getMessage(), + throw new SketchException(message, errorFile, errorLine, errorColumn); } else { @@ -381,7 +396,7 @@ public String preprocess(File srcFolder, // grab the imports from the code just preprocessed - importedLibraries = new ArrayList(); + importedLibraries = new ArrayList<>(); Library core = mode.getCoreLibrary(); if (core != null) { importedLibraries.add(core); @@ -389,26 +404,19 @@ public String preprocess(File srcFolder, javaLibraryPath += File.pathSeparator + core.getNativePath(); } -// System.out.println("extra imports: " + result.extraImports); for (String item : result.extraImports) { -// System.out.println("item = '" + item + "'"); // remove things up to the last dot int dot = item.lastIndexOf('.'); // http://dev.processing.org/bugs/show_bug.cgi?id=1145 String entry = (dot == -1) ? item : item.substring(0, dot); -// System.out.print(entry + " => "); if (item.startsWith("static ")) { // import static - https://github.com/processing/processing/issues/8 - // Remove more stuff. int dot2 = item.lastIndexOf('.'); entry = entry.substring(7, (dot2 == -1) ? entry.length() : dot2); -// System.out.println(entry); } -// System.out.println("library searching for " + entry); Library library = mode.getLibrary(entry); -// System.out.println(" found " + library); if (library != null) { if (!importedLibraries.contains(library)) { @@ -437,7 +445,6 @@ public String preprocess(File srcFolder, } } } -// PApplet.println(PApplet.split(libraryPath, File.pathSeparatorChar)); // Finally, add the regular Java CLASSPATH. This contains everything // imported by the PDE itself (core.jar, pde.jar, quaqua.jar) which may @@ -509,6 +516,7 @@ public String preprocess(File srcFolder, return result.className; } + /** * Returns true if this package isn't part of a library (it's a system import * or something like that). Don't bother complaining about java.* or javax.* @@ -520,6 +528,7 @@ public String preprocess(File srcFolder, protected boolean ignorableImport(String pkg) { if (pkg.startsWith("java.")) return true; if (pkg.startsWith("javax.")) return true; + if (pkg.startsWith("javafx.")) return true; if (pkg.startsWith("processing.core.")) return true; if (pkg.startsWith("processing.data.")) return true; @@ -697,11 +706,13 @@ protected boolean exportApplication() throws IOException, SketchException { final String arch = Platform.getNativeArch(); if (Library.hasMultipleArch(platform, importedLibraries)) { - // export the 32-bit version - folder = new File(sketch.getFolder(), "application." + platformName + "32"); - - if (!exportApplication(folder, platform, "32", embedJava && (bits == 32) && ("x86".equals(arch) || "i386".equals(arch)))) { - return false; + // Don't try to export 32-bit on macOS, because it doesn't exist. + if (platform != PConstants.MACOSX) { + // export the 32-bit version + folder = new File(sketch.getFolder(), "application." + platformName + "32"); + if (!exportApplication(folder, platform, "32", embedJava && (bits == 32) && ("x86".equals(arch) || "i386".equals(arch)))) { + return false; + } } // export the 64-bit version folder = new File(sketch.getFolder(), "application." + platformName + "64"); @@ -709,11 +720,15 @@ protected boolean exportApplication() throws IOException, SketchException { return false; } if (platform == PConstants.LINUX) { - // export the armv6hf version as well + // export the arm versions as well folder = new File(sketch.getFolder(), "application.linux-armv6hf"); if (!exportApplication(folder, platform, "armv6hf", embedJava && (bits == 32) && "arm".equals(arch))) { return false; } + folder = new File(sketch.getFolder(), "application.linux-arm64"); + if (!exportApplication(folder, platform, "arm64", embedJava && (bits == 64) && "aarch64".equals(arch))) { + return false; + } } } else { // just make a single one for this platform folder = new File(sketch.getFolder(), "application." + platformName); @@ -790,7 +805,8 @@ protected boolean exportApplication(File destFolder, File macosFolder = new File(contentsFolder, "MacOS"); macosFolder.mkdirs(); - Util.copyFile(new File(contentsOrig, "MacOS/Processing"), + // This is an unsigned copy of the app binary (see build/build.xml) + Util.copyFile(mode.getContentFile("application/mac-app-stub"), new File(contentsFolder, "MacOS/" + sketch.getName())); File pkgInfo = new File(contentsFolder, "PkgInfo"); diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index c45a29263b..6b87398c15 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -9,8 +9,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.*; @@ -23,6 +21,7 @@ import processing.app.*; import processing.app.contrib.*; import processing.app.syntax.JEditTextArea; +import processing.app.syntax.PdeTextArea; import processing.app.syntax.PdeTextAreaDefaults; import processing.app.ui.*; import processing.app.ui.Toolkit; @@ -49,6 +48,9 @@ public class JavaEditor extends Editor { // Runner associated with this editor window private Runner runtime; + private boolean runtimeLaunchRequested; + private final Object runtimeLock = new Object[0]; + // Need to sort through the rest of these additions [fry] protected final List breakpointedLines = new ArrayList<>(); @@ -220,7 +222,7 @@ public void actionPerformed(ActionEvent e) { stopItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (isDebuggerEnabled()) { - Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); + Messages.log("Invoked 'Stop' menu item"); debugger.stopDebug(); } else { handleStop(); @@ -310,17 +312,17 @@ public void actionPerformed(ActionEvent e) { @Override public void menuSelected(MenuEvent e) { - boolean isCoreLibMenuItemAdded = false; - boolean isContribLibMenuItemAdded = false; - // Adding this in case references are included in a core library, - // or other core libraries are incuded in future - isCoreLibMenuItemAdded = addLibReferencesToSubMenu(mode.coreLibraries, libRefSubmenu); + // or other core libraries are included in the future + boolean isCoreLibMenuItemAdded = + addLibReferencesToSubMenu(mode.coreLibraries, libRefSubmenu); - if (isCoreLibMenuItemAdded && !mode.contribLibraries.isEmpty()) + if (isCoreLibMenuItemAdded && !mode.contribLibraries.isEmpty()) { libRefSubmenu.addSeparator(); + } - isContribLibMenuItemAdded = addLibReferencesToSubMenu(mode.contribLibraries, libRefSubmenu); + boolean isContribLibMenuItemAdded = + addLibReferencesToSubMenu(mode.contribLibraries, libRefSubmenu); if (!isContribLibMenuItemAdded && !isCoreLibMenuItemAdded) { JMenuItem emptyMenuItem = new JMenuItem(Language.text("menu.help.empty")); @@ -328,8 +330,8 @@ public void menuSelected(MenuEvent e) { emptyMenuItem.setFocusable(false); emptyMenuItem.setFocusPainted(false); libRefSubmenu.add(emptyMenuItem); - } - else if (!isContribLibMenuItemAdded && !mode.coreLibraries.isEmpty()) { + + } else if (!isContribLibMenuItemAdded && !mode.coreLibraries.isEmpty()) { //re-populate the menu to get rid of terminal separator libRefSubmenu.removeAll(); addLibReferencesToSubMenu(mode.coreLibraries, libRefSubmenu); @@ -1059,49 +1061,49 @@ public void handleRun() { debugger.continueDebug(); } else { - new Thread(new Runnable() { - public void run() { - prepareRun(); - try { - toolbar.activateRun(); - //runtime = jmode.handleRun(sketch, JavaEditor.this); - runtime = jmode.handleLaunch(sketch, JavaEditor.this, false); - } catch (Exception e) { - statusError(e); - } - } - }).start(); + handleLaunch(false, false); } } public void handlePresent() { - new Thread(new Runnable() { - public void run() { - prepareRun(); - try { - toolbar.activateRun(); - //runtime = jmode.handlePresent(sketch, JavaEditor.this); - runtime = jmode.handleLaunch(sketch, JavaEditor.this, true); - } catch (Exception e) { - statusError(e); - } - } - }).start(); + handleLaunch(true, false); } public void handleTweak() { - new Thread(new Runnable() { - public void run() { - prepareRun(); - try { -// toolbar.activate(JavaToolbar.RUN); - toolbar.activateRun(); - runtime = jmode.handleTweak(sketch, JavaEditor.this); - } catch (Exception e) { - statusError(e); + autoSave(); + + if (sketch.isModified()) { + Messages.showMessage(Language.text("menu.file.save"), + Language.text("tweak_mode.save_before_tweak")); + return; + } + + handleLaunch(false, true); + } + + protected void handleLaunch(boolean present, boolean tweak) { + prepareRun(); + toolbar.activateRun(); + synchronized (runtimeLock) { + runtimeLaunchRequested = true; + } + new Thread(() -> { + try { + synchronized (runtimeLock) { + if (runtimeLaunchRequested) { + runtimeLaunchRequested = false; + RunnerListener listener = new RunnerListenerEdtAdapter(JavaEditor.this); + if (!tweak) { + runtime = jmode.handleLaunch(sketch, listener, present); + } else { + runtime = jmode.handleTweak(sketch, listener, JavaEditor.this); + } + } } + } catch (Exception e) { + EventQueue.invokeLater(() -> statusError(e)); } }).start(); } @@ -1116,23 +1118,24 @@ public void handleStop() { debugger.stopDebug(); } else { -// toolbar.activate(JavaToolbar.STOP); toolbar.activateStop(); try { - //jmode.handleStop(); - if (runtime != null) { - runtime.close(); // kills the window - runtime = null; - // } else { - // System.out.println("runtime is null"); + synchronized (runtimeLock) { + if (runtimeLaunchRequested) { + // Cancel the launch before the runtime was created + runtimeLaunchRequested = false; + } + if (runtime != null) { + // Cancel the launch after the runtime was created + runtime.close(); // kills the window + runtime = null; + } } } catch (Exception e) { statusError(e); } -// toolbar.deactivate(JavaToolbar.RUN); -// toolbar.deactivate(JavaToolbar.STOP); toolbar.deactivateStop(); toolbar.deactivateRun(); @@ -1144,26 +1147,35 @@ public void handleStop() { public void handleStep(int modifiers) { if (modifiers == 0) { - Logger.getLogger(getClass().getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); + Messages.log("Invoked 'Step Over' menu item"); debugger.stepOver(); } else if ((modifiers & ActionEvent.SHIFT_MASK) != 0) { - Logger.getLogger(getClass().getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); + Messages.log("Invoked 'Step Into' menu item"); debugger.stepInto(); } else if ((modifiers & ActionEvent.ALT_MASK) != 0) { - Logger.getLogger(getClass().getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); + Messages.log("Invoked 'Step Out' menu item"); debugger.stepOut(); } } public void handleContinue() { - Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); + Messages.log("Invoked 'Continue' menu item"); debugger.continueDebug(); } + public void onRunnerExiting(Runner runner) { + synchronized (runtimeLock) { + if (this.runtime == runner) { + deactivateRun(); + } + } + } + + // /** Toggle a breakpoint on the current line. */ // public void toggleBreakpoint() { // toggleBreakpoint(getCurrentLineID().lineIdx()); @@ -1264,6 +1276,12 @@ public void codeFolderChanged() { } + @Override + public void sketchChanged() { + preprocessingService.notifySketchChanged(); + } + + public void statusError(String what) { super.statusError(what); // new Exception("deactivating RUN").printStackTrace(); @@ -1366,7 +1384,7 @@ public void actionPerformed(ActionEvent e) { // }); // debugMenu.add(item); - item = Toolkit.newJMenuItem(Language.text("menu.debug.step"), KeyEvent.VK_J); + item = Toolkit.newJMenuItemExt("menu.debug.step"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleStep(0); @@ -1375,7 +1393,7 @@ public void actionPerformed(ActionEvent e) { debugMenu.add(item); item.setEnabled(false); - item = Toolkit.newJMenuItemShift(Language.text("menu.debug.step_into"), KeyEvent.VK_J); + item = Toolkit.newJMenuItemExt("menu.debug.step_into"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleStep(ActionEvent.SHIFT_MASK); @@ -1384,7 +1402,7 @@ public void actionPerformed(ActionEvent e) { debugMenu.add(item); item.setEnabled(false); - item = Toolkit.newJMenuItemAlt(Language.text("menu.debug.step_out"), KeyEvent.VK_J); + item = Toolkit.newJMenuItemExt("menu.debug.step_out"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleStep(ActionEvent.ALT_MASK); @@ -1399,7 +1417,7 @@ public void actionPerformed(ActionEvent e) { Toolkit.newJMenuItem(Language.text("menu.debug.toggle_breakpoint"), 'B'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); + Messages.log("Invoked 'Toggle Breakpoint' menu item"); // TODO wouldn't getCaretLine() do the same thing with less effort? toggleBreakpoint(getCurrentLineID().lineIdx()); } @@ -1603,7 +1621,7 @@ protected void addBreakpointComments(String tabFilename) { tab.setProgram(code); tab.save(); } catch (IOException ex) { - Logger.getLogger(JavaEditor.class.getName()).log(Level.SEVERE, null, ex); + Messages.loge(null, ex); } } @@ -2062,7 +2080,7 @@ public void setCurrentLine(LineID line) { cursorToLineStart(line.lineIdx()); // highlight line currentLine = new LineHighlight(line.lineIdx(), this); - currentLine.setMarker(JavaTextArea.STEP_MARKER); + currentLine.setMarker(PdeTextArea.STEP_MARKER); currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down } @@ -2091,7 +2109,7 @@ public void clearCurrentLine() { */ public void addBreakpointedLine(LineID lineID) { LineHighlight hl = new LineHighlight(lineID, this); - hl.setMarker(JavaTextArea.BREAK_MARKER); + hl.setMarker(PdeTextArea.BREAK_MARKER); breakpointedLines.add(hl); // repaint current line if it's on this line if (currentLine != null && currentLine.getLineID().equals(lineID)) { @@ -2334,7 +2352,7 @@ private void showImportSuggestion(String[] list, int x, int y) { frmImportSuggest = new JFrame(); frmImportSuggest.setUndecorated(true); - frmImportSuggest.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmImportSuggest.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.setBackground(Color.WHITE); @@ -2764,11 +2782,9 @@ static private String replaceString(String str, int start, int end, String put) //private int howManyInts(ArrayList handles[]) static private int howManyInts(List> handles) { int count = 0; - //for (int i=0; i list : handles) { - //for (Handle n : handles[i]) { for (Handle n : list) { - if (n.type == "int" || n.type == "hex" || n.type == "webcolor") { + if ("int".equals(n.type) || "hex".equals(n.type) || "webcolor".equals(n.type)) { count++; } } @@ -2780,11 +2796,9 @@ static private int howManyInts(List> handles) { //private int howManyFloats(ArrayList handles[]) static private int howManyFloats(List> handles) { int count = 0; - //for (int i=0; i list : handles) { - //for (Handle n : handles[i]) { for (Handle n : list) { - if (n.type == "float") { + if ("float".equals(n.type)) { count++; } } diff --git a/java/src/processing/mode/java/JavaInputHandler.java b/java/src/processing/mode/java/JavaInputHandler.java index 9e3ae59121..0c02a4418c 100644 --- a/java/src/processing/mode/java/JavaInputHandler.java +++ b/java/src/processing/mode/java/JavaInputHandler.java @@ -164,7 +164,7 @@ public boolean handlePressed(KeyEvent event) { event.consume(); } - } else if (c == 10 || c == 13) { // auto-indent + } else if (code == 10 || code == 13) { // auto-indent if (Preferences.getBoolean("editor.indent")) { char contents[] = textarea.getText().toCharArray(); int tabSize = Preferences.getInteger("editor.tabs.size"); diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index 365fa3e6de..54a70462bb 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -30,10 +30,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.logging.FileHandler; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.SwingUtilities; @@ -56,7 +52,7 @@ public Editor createEditor(Base base, String path, public JavaMode(Base base, File folder) { super(base, folder); - initLogger(); +// initLogger(); loadPreferences(); } @@ -144,16 +140,7 @@ public void run() { /** Start a sketch in tweak mode */ public Runner handleTweak(Sketch sketch, - RunnerListener listener) throws SketchException { -// final boolean present) throws SketchException { - final JavaEditor editor = (JavaEditor) listener; - - if (isSketchModified(sketch)) { - editor.deactivateRun(); - Messages.showMessage(Language.text("menu.file.save"), - Language.text("tweak_mode.save_before_tweak")); - return null; - } + RunnerListener listener, JavaEditor editor) throws SketchException { // first try to build the unmodified code JavaBuild build = new JavaBuild(sketch); @@ -218,6 +205,7 @@ public void run() { } + /* // TODO Why is this necessary? Why isn't Sketch.isModified() used? static private boolean isSketchModified(Sketch sketch) { for (SketchCode sc : sketch.getCode()) { @@ -227,6 +215,7 @@ static private boolean isSketchModified(Sketch sketch) { } return false; } + */ // public void handleStop() { @@ -263,7 +252,7 @@ public String getSearchPath() { // Merged from ExperimentalMode - + /* void initLogger() { final boolean VERBOSE_LOGGING = true; final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) @@ -293,6 +282,7 @@ void initLogger() { Logger.getLogger(JavaMode.class.getName()).log(Level.SEVERE, null, ex); } } + */ //ImageIcon classIcon, fieldIcon, methodIcon, localVarIcon; diff --git a/java/src/processing/mode/java/VariableInspector.java b/java/src/processing/mode/java/VariableInspector.java index e9e30a4e73..66eeba869a 100644 --- a/java/src/processing/mode/java/VariableInspector.java +++ b/java/src/processing/mode/java/VariableInspector.java @@ -26,8 +26,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.*; import javax.swing.event.TreeExpansionEvent; @@ -40,17 +38,12 @@ import com.sun.jdi.Value; import processing.app.Language; +import processing.app.Messages; import processing.app.Mode; import processing.mode.java.debug.VariableNode; public class VariableInspector extends JDialog { -// static public final int GAP = 13; - -// EditorButton continueButton; -// EditorButton stepButton; -// EditorButton breakpointButton; - // The tray will be placed at this amount from the top of the editor window, // and extend to this amount from the bottom of the editor window. static final int VERTICAL_OFFSET = 64; @@ -88,7 +81,7 @@ public class VariableInspector extends JDialog { // protected Debugger dbg; /// list of expanded tree paths. (using list to maintain the order of expansion) - protected List expandedNodes = new ArrayList(); + protected List expandedNodes = new ArrayList<>(); public VariableInspector(final JavaEditor editor) { @@ -251,10 +244,10 @@ Container createScrollPane() { //System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass()); //System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass()); - callStack = new ArrayList(); - locals = new ArrayList(); - thisFields = new ArrayList(); - declaredThisFields = new ArrayList(); + callStack = new ArrayList<>(); + locals = new ArrayList<>(); + thisFields = new ArrayList<>(); + declaredThisFields = new ArrayList<>(); // Remove ugly (and unused) focus border on OS X scrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); @@ -441,11 +434,12 @@ public void setValueFor(Object o, int i, Object o1) { break; } } catch (NumberFormatException ex) { - Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "invalid value entered for {0}: {1}", new Object[]{var.getName(), stringValue}); + Messages.log(getClass().getName() + " invalid value entered for " + + var.getName() + " -> " + stringValue); } if (value != null) { var.setValue(value); - Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "new value set: {0}", var.getStringValue()); + Messages.log(getClass().getName() + " new value set: " + var.getStringValue()); } } @@ -483,7 +477,7 @@ private ImageIcon[][] loadIcons(String fileName) { Mode mode = editor.getMode(); File file = mode.getContentFile(fileName); if (!file.exists()) { - Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath()); + Messages.log(getClass().getName(), "icon file not found: " + file.getAbsolutePath()); return null; } Image allIcons = mode.loadImage(fileName); @@ -702,7 +696,7 @@ public void treeCollapsed(TreeExpansionEvent tee) { // first remove all children of collapsed path // this makes sure children do not appear before parents in the list. // (children can't be expanded before their parents) - List removalList = new ArrayList(); + List removalList = new ArrayList<>(); for (TreePath path : expandedNodes) { if (path.getParentPath().equals(tee.getPath())) { removalList.add(path); @@ -917,7 +911,7 @@ protected TreePath synthesizePath(TreePath path) { * @return the filtered list. */ protected List filterNodes(List nodes, VariableNodeFilter filter) { - List filtered = new ArrayList(); + List filtered = new ArrayList<>(); for (VariableNode node : nodes) { if (filter.accept(node)) { filtered.add(node); diff --git a/java/src/processing/mode/java/debug/ArrayFieldNode.java b/java/src/processing/mode/java/debug/ArrayFieldNode.java index ec5423729a..8d527573e1 100644 --- a/java/src/processing/mode/java/debug/ArrayFieldNode.java +++ b/java/src/processing/mode/java/debug/ArrayFieldNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; @@ -24,45 +25,36 @@ import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; + +import processing.app.Messages; /** * Specialized {@link VariableNode} for representing single fields in an array. * Overrides {@link #setValue} to properly change the value of the encapsulated * array field. - * - * @author Martin Leopold */ public class ArrayFieldNode extends VariableNode { - - protected ArrayReference array; - protected int index; - - /** - * Construct an {@link ArrayFieldNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param array a reference to the array - * @param index the index inside the array - */ - public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) { - super(name, type, value); - this.array = array; - this.index = index; - } - - @Override - public void setValue(Value value) { - try { - array.setValue(index, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; + protected ArrayReference array; + protected int index; + + + /** + * Construct an {@link ArrayFieldNode}. + */ + public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) { + super(name, type, value); + this.array = array; + this.index = index; + } + + + @Override + public void setValue(Value value) { + try { + array.setValue(index, value); + } catch (InvalidTypeException | ClassNotLoadedException ex) { + Messages.loge(null, ex); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/ClassLoadListener.java b/java/src/processing/mode/java/debug/ClassLoadListener.java index bee6ffa471..1dd4a288d5 100644 --- a/java/src/processing/mode/java/debug/ClassLoadListener.java +++ b/java/src/processing/mode/java/debug/ClassLoadListener.java @@ -1,40 +1,38 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; import com.sun.jdi.ReferenceType; + /** * Listener to be notified when a class is loaded in the debugger. Used by * {@link LineBreakpoint}s to activate themselves as soon as the respective * class is loaded. - * - * @author Martin Leopold */ public interface ClassLoadListener { - /** - * Event handler called when a class is loaded. - * - * @param theClass the class - */ - public void classLoaded(ReferenceType theClass); + /** + * Event handler called when a class is loaded. + */ + public void classLoaded(ReferenceType theClass); } diff --git a/java/src/processing/mode/java/debug/FieldNode.java b/java/src/processing/mode/java/debug/FieldNode.java index 76b4bc2ad1..cae4d7178b 100644 --- a/java/src/processing/mode/java/debug/FieldNode.java +++ b/java/src/processing/mode/java/debug/FieldNode.java @@ -2,11 +2,12 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 The Processing Foundation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,8 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; @@ -25,46 +26,40 @@ import com.sun.jdi.InvalidTypeException; import com.sun.jdi.ObjectReference; import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; + +import processing.app.Messages; /** * Specialized {@link VariableNode} for representing fields. Overrides * {@link #setValue} to properly change the value of the encapsulated field. - * - * @author Martin Leopold */ public class FieldNode extends VariableNode { - protected Field field; - protected ObjectReference obj; + protected Field field; + protected ObjectReference obj; + + + /** + * Construct a {@link FieldNode}. + * @param obj a reference to the object containing the field + */ + public FieldNode(String name, String type, Value value, Field field, + ObjectReference obj) { + super(name, type, value); + this.field = field; + this.obj = obj; + } - - /** - * Construct a {@link FieldNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param field the field - * @param obj a reference to the object containing the field - */ - public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) { - super(name, type, value); - this.field = field; - this.obj = obj; - } - - @Override - public void setValue(Value value) { - try { - obj.setValue(field, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; + @Override + public void setValue(Value value) { + try { + obj.setValue(field, value); + } catch (InvalidTypeException ite) { + Messages.loge(null, ite); + } catch (ClassNotLoadedException cnle) { + Messages.loge(null, cnle); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/LineBreakpoint.java b/java/src/processing/mode/java/debug/LineBreakpoint.java index 5272270e5e..a5372553da 100644 --- a/java/src/processing/mode/java/debug/LineBreakpoint.java +++ b/java/src/processing/mode/java/debug/LineBreakpoint.java @@ -1,28 +1,27 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import processing.app.Messages; import processing.mode.java.Debugger; @@ -30,203 +29,227 @@ import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; +import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.request.BreakpointRequest; + /** * Model/Controller of a line breakpoint. Can be set before or while debugging. * Adds a highlight using the debuggers view ({@link DebugEditor}). - * - * @author Martin Leopold */ public class LineBreakpoint implements ClassLoadListener { - - protected Debugger dbg; // the debugger - protected LineID line; // the line this breakpoint is set on - protected BreakpointRequest bpr; // the request on the VM's event request manager - protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded - - /** - * Create a {@link LineBreakpoint}. If in a debug session, will try to - * immediately set the breakpoint. If not in a debug session or the - * corresponding class is not yet loaded the breakpoint will activate on - * class load. - * - * @param line the line id to create the breakpoint on - * @param dbg the {@link Debugger} - */ - public LineBreakpoint(LineID line, Debugger dbg) { - this.line = line; - line.startTracking(dbg.getEditor().getTab(line.fileName()).getDocument()); - this.dbg = dbg; - theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded - set(); // activate the breakpoint (show highlight, attach if debugger is running) - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + className(), new Object[]{}); + protected Debugger dbg; // the debugger + protected LineID line; // the line this breakpoint is set on + protected BreakpointRequest bpr; // the request on the VM's event request manager + protected String className; + + + /** + * Create a {@link LineBreakpoint}. If in a debug session, will try to + * immediately set the breakpoint. If not in a debug session or the + * corresponding class is not yet loaded the breakpoint will activate on + * class load. + * + * @param line the line id to create the breakpoint on + * @param dbg the {@link Debugger} + */ + public LineBreakpoint(LineID line, Debugger dbg) { + this.line = line; + line.startTracking(dbg.getEditor().getTab(line.fileName()).getDocument()); + this.dbg = dbg; + this.className = className(); + set(); // activate the breakpoint (show highlight, attach if debugger is running) + Messages.log("LBP Created " + toString() + " class: " + this.className); + } + + + /** + * Create a {@link LineBreakpoint} on a line in the current tab. + * @param lineIdx the line index of the current tab to create the breakpoint + */ + // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} + public LineBreakpoint(int lineIdx, Debugger dbg) { + this(dbg.getEditor().getLineIDInCurrentTab(lineIdx), dbg); + } + + + /** + * Get the line id this breakpoint is on. + */ + public LineID lineID() { + return line; + } + + + /** + * Test if this breakpoint is on a certain line. + * + * @param testLine the line id to test + * @return true if this breakpoint is on the given line + */ + public boolean isOnLine(LineID testLine) { + return line.equals(testLine); + } + + + /** + * Attach this breakpoint to the VM. Creates and enables a + * {@link BreakpointRequest}. VM needs to be paused. + * + * @param theClass class to attach to + * @return true on success + */ + protected boolean attach(ReferenceType theClass) { + + if (theClass == null || className == null || + !className.equals(parseTopLevelClassName(theClass.name()))) { + return false; } - /** - * Create a {@link LineBreakpoint} on a line in the current tab. - * - * @param lineIdx the line index of the current tab to create the breakpoint - * on - * @param dbg the {@link Debugger} - */ - // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} - public LineBreakpoint(int lineIdx, Debugger dbg) { - this(dbg.getEditor().getLineIDInCurrentTab(lineIdx), dbg); - } + log("trying to attach: " + line.fileName + ":" + line.lineIdx + " to " + theClass.name()); - /** - * Get the line id this breakpoint is on. - * - * @return the line id - */ - public LineID lineID() { - return line; + if (!dbg.isPaused()) { + log("can't attach breakpoint, debugger not paused"); + return false; } - /** - * Test if this breakpoint is on a certain line. - * - * @param testLine the line id to test - * @return true if this breakpoint is on the given line - */ - public boolean isOnLine(LineID testLine) { - return line.equals(testLine); + // find line in java space + LineID javaLine = dbg.sketchToJavaLine(line); + if (javaLine == null) { + log("couldn't find line " + line + " in the java code"); + return false; } - - /** - * Attach this breakpoint to the VM. Creates and enables a - * {@link BreakpointRequest}. VM needs to be paused. - */ - protected void attach() { - if (!dbg.isPaused()) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused"); - return; - } - - if (theClass == null) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className()); - return; - } - - // find line in java space - LineID javaLine = dbg.sketchToJavaLine(line); - if (javaLine == null) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line); - return; - } - try { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0} , line " + (javaLine.lineIdx() + 1), new Object[]{theClass}); - List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); - if (locations.isEmpty()) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); - return; - } - // use first found location - bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); - bpr.enable(); - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine}); - } catch (AbsentInformationException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } + try { + log("BPs of class: " + theClass + ", line " + (javaLine.lineIdx() + 1)); + List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); + if (locations.isEmpty()) { + log("no location found for line " + line + " -> " + javaLine); + return false; + } + // use first found location + bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); + bpr.enable(); + log("attached breakpoint to " + line + " -> " + javaLine); + return true; + } catch (AbsentInformationException ex) { + Messages.loge(null, ex); } + return false; + } - /** - * Detach this breakpoint from the VM. Deletes the - * {@link BreakpointRequest}. - */ - protected void detach() { - if (bpr != null) { - dbg.vm().eventRequestManager().deleteEventRequest(bpr); - bpr = null; - } - } - /** - * Set this breakpoint. Adds the line highlight. If Debugger is paused also - * attaches the breakpoint by calling {@link #attach()}. - */ - protected void set() { - dbg.addClassLoadListener(this); // class may not yet be loaded - dbg.getEditor().addBreakpointedLine(line); - if (theClass != null && dbg.isPaused()) { // class is loaded - // immediately activate the breakpoint - attach(); - } - if (dbg.getEditor().isInCurrentTab(line)) { - dbg.getEditor().getSketch().setModified(true); - } - } + protected boolean isAttached() { + return bpr != null; + } + - /** - * Remove this breakpoint. Clears the highlight and detaches the breakpoint - * if the debugger is paused. - */ - public void remove() { - dbg.removeClassLoadListener(this); - //System.out.println("removing " + line.lineIdx()); - dbg.getEditor().removeBreakpointedLine(line.lineIdx()); - if (dbg.isPaused()) { - // immediately remove the breakpoint - detach(); - } - line.stopTracking(); - if (dbg.getEditor().isInCurrentTab(line)) { - dbg.getEditor().getSketch().setModified(true); - } + /** + * Detach this breakpoint from the VM. Deletes the + * {@link BreakpointRequest}. + */ + public void detach() { + if (bpr != null) { + try { + dbg.vm().eventRequestManager().deleteEventRequest(bpr); + } catch (VMDisconnectedException ignore) { } + bpr = null; + } + } + + + /** + * Set this breakpoint. Adds the line highlight. If Debugger is paused + * also attaches the breakpoint by calling {@link #attach()}. + */ + protected void set() { + dbg.addClassLoadListener(this); // class may not yet be loaded + dbg.getEditor().addBreakpointedLine(line); + if (className != null && dbg.isPaused()) { // debugging right now, try to attach + for (ReferenceType rt : dbg.getClasses()) { + // try to attach to all top level or nested classes + if (attach(rt)) break; + } + } + if (dbg.getEditor().isInCurrentTab(line)) { + dbg.getEditor().getSketch().setModified(true); + } + } + + + /** + * Remove this breakpoint. Clears the highlight and detaches + * the breakpoint if the debugger is paused. + */ + public void remove() { + dbg.removeClassLoadListener(this); + //System.out.println("removing " + line.lineIdx()); + dbg.getEditor().removeBreakpointedLine(line.lineIdx()); + if (dbg.isPaused()) { + // immediately remove the breakpoint + detach(); } + line.stopTracking(); + if (dbg.getEditor().isInCurrentTab(line)) { + dbg.getEditor().getSketch().setModified(true); + } + } + + + @Override + public String toString() { + return line.toString(); + } -// public void enable() { -// } -// -// public void disable() { -// } - @Override - public String toString() { - return line.toString(); + + /** + * Get the name of the class this breakpoint belongs to. Needed for + * fetching the right location to create a breakpoint request. + * @return the class name + */ + protected String className() { + if (line.fileName().endsWith(".pde")) { + // standard tab + return dbg.getEditor().getSketch().getName(); } - /** - * Get the name of the class this breakpoint belongs to. Needed for fetching - * the right location to create a breakpoint request. - * - * @return the class name - */ - protected String className() { - if (line.fileName().endsWith(".pde")) { - // standard tab - ReferenceType mainClass = dbg.getMainClass(); - //System.out.println(dbg.getMainClass().name()); - if (mainClass == null) { - return null; - } - return dbg.getMainClass().name(); - } - - if (line.fileName().endsWith(".java")) { - // pure java tab - return line.fileName().substring(0, line.fileName().lastIndexOf(".java")); - } - - return null; + if (line.fileName().endsWith(".java")) { + // pure java tab + return line.fileName().substring(0, line.fileName().lastIndexOf(".java")); + } + return null; + } + + + /** + * Event handler called when a class is loaded in the debugger. Causes the + * breakpoint to be attached, if its class was loaded. + * + * @param theClass the class that was just loaded. + */ + @Override + public void classLoaded(ReferenceType theClass) { + if (!isAttached()) { + // try to attach + attach(theClass); } + } + + + static public String parseTopLevelClassName(String name) { + // Get rid of nested class name + int dollar = name.indexOf('$'); + return (dollar == -1) ? name : name.substring(0, dollar); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + - /** - * Event handler called when a class is loaded in the debugger. Causes the - * breakpoint to be attached, if its class was loaded. - * - * @param theClass the class that was just loaded. - */ - @Override - public void classLoaded(ReferenceType theClass) { - // check if our class is being loaded - Messages.log("Class Loaded: " + theClass.name()); - if (theClass.name().equals(className())) { - this.theClass = theClass; - attach(); - } - for (ReferenceType ct : theClass.nestedTypes()) { - Messages.log("Nested " + ct.name()); - } + private void log(String msg, Object... args) { + if (args != null && args.length != 0) { + Messages.logf(getClass().getName() + " " + msg, args); + } else { + Messages.log(getClass().getName() + " " + msg); } + } } diff --git a/java/src/processing/mode/java/debug/LineHighlight.java b/java/src/processing/mode/java/debug/LineHighlight.java index 789d4ba966..66856f8292 100644 --- a/java/src/processing/mode/java/debug/LineHighlight.java +++ b/java/src/processing/mode/java/debug/LineHighlight.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; @@ -29,23 +30,17 @@ /** * Model/Controller for a highlighted source code line. Implements a custom * background color and a text based marker placed in the left-hand gutter area. - * - * @author Martin Leopold */ public class LineHighlight { - protected final JavaEditor editor; // the view, used for highlighting lines by setting a background color protected final LineID lineID; // the id of the line protected String marker; // protected int priority = 0; protected static final Set allHighlights = new HashSet<>(); - + /** * Create a {@link LineHighlight}. - * - * @param lineID the line id to highlight - * @param editor the {@link JavaEditor} */ public LineHighlight(LineID lineID, JavaEditor editor) { this.lineID = lineID; @@ -56,10 +51,10 @@ public LineHighlight(LineID lineID, JavaEditor editor) { allHighlights.add(this); } - + protected static boolean isHighestPriority(LineHighlight hl) { for (LineHighlight check : allHighlights) { - if (check.getLineID().equals(hl.getLineID()) && + if (check.getLineID().equals(hl.getLineID()) && check.priority() > hl.priority()) { return false; } @@ -67,107 +62,114 @@ protected static boolean isHighestPriority(LineHighlight hl) { return true; } - + public void setPriority(int p) { this.priority = p; } - + public int priority() { return priority; } - - /** - * Create a {@link LineHighlight} on the current tab. - * - * @param lineIdx the line index on the current tab to highlight - * @param editor the {@link JavaEditor} - */ - // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, JavaEditor editor)} - public LineHighlight(int lineIdx, JavaEditor editor) { - this(editor.getLineIDInCurrentTab(lineIdx), editor); - } - /** - * Set a text based marker displayed in the left hand gutter area of this - * highlighted line. - * - * @param marker the marker text - */ - public void setMarker(String marker) { - this.marker = marker; - paint(); - } + /** + * Create a {@link LineHighlight} on the current tab. + * + * @param lineIdx the line index on the current tab to highlight + * @param editor the {@link JavaEditor} + */ + // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, JavaEditor editor)} + public LineHighlight(int lineIdx, JavaEditor editor) { + this(editor.getLineIDInCurrentTab(lineIdx), editor); + } - /** - * Retrieve the line id of this {@link LineHighlight}. - * - * @return the line id - */ - public LineID getLineID() { - return lineID; - } - /** - * Test if this highlight is on a certain line. - * - * @param testLine the line to test - * @return true if this highlight is on the given line - */ - public boolean isOnLine(LineID testLine) { - return lineID.equals(testLine); - } + /** + * Set a text based marker displayed in the left hand gutter area of this + * highlighted line. + * + * @param marker the marker text + */ + public void setMarker(String marker) { + this.marker = marker; + paint(); + } + + + /** + * Retrieve the line id of this {@link LineHighlight}. + * + * @return the line id + */ + public LineID getLineID() { + return lineID; + } + + + /** + * Test if this highlight is on a certain line. + * + * @param testLine the line to test + * @return true if this highlight is on the given line + */ + public boolean isOnLine(LineID testLine) { + return lineID.equals(testLine); + } - /** - * Event handler for line number changes (due to editing). Will remove the - * highlight from the old line number and repaint it at the new location. - * - * @param line the line that has changed - * @param oldLineIdx the old line index (0-based) - * @param newLineIdx the new line index (0-based) - */ - public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { - // clear old line - if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { - editor.getJavaTextArea().clearGutterText(oldLineIdx); - } - - // paint new line - // but only if it's on top -> fixes current line being hidden by breakpoint moving it down. - // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...) - if (LineHighlight.isHighestPriority(this)) { - paint(); - } + + /** + * Event handler for line number changes (due to editing). Will remove the + * highlight from the old line number and repaint it at the new location. + * + * @param line the line that has changed + * @param oldLineIdx the old line index (0-based) + * @param newLineIdx the new line index (0-based) + */ + public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { + // clear old line + if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { + editor.getJavaTextArea().clearGutterText(oldLineIdx); } - /** - * Notify this line highlight that it is no longer used. Call this for - * cleanup before the {@link LineHighlight} is discarded. - */ - public void dispose() { - lineID.removeListener(this); - lineID.stopTracking(); - allHighlights.remove(this); + // paint new line + // but only if it's on top -> fixes current line being hidden by breakpoint moving it down. + // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...) + if (LineHighlight.isHighestPriority(this)) { + paint(); } + } + - /** - * (Re-)paint this line highlight. - */ - public void paint() { - if (editor.isInCurrentTab(lineID)) { - if (marker != null) { - editor.getJavaTextArea().setGutterText(lineID.lineIdx(), marker); - } - } + /** + * Notify this line highlight that it is no longer used. Call this for + * cleanup before the {@link LineHighlight} is discarded. + */ + public void dispose() { + lineID.removeListener(this); + lineID.stopTracking(); + allHighlights.remove(this); + } + + + /** + * (Re-)paint this line highlight. + */ + public void paint() { + if (editor.isInCurrentTab(lineID)) { + if (marker != null) { + editor.getJavaTextArea().setGutterText(lineID.lineIdx(), marker); + } } + } + - /** - * Clear this line highlight. - */ - public void clear() { - if (editor.isInCurrentTab(lineID)) { - editor.getJavaTextArea().clearGutterText(lineID.lineIdx()); - } + /** + * Clear this line highlight. + */ + public void clear() { + if (editor.isInCurrentTab(lineID)) { + editor.getJavaTextArea().clearGutterText(lineID.lineIdx()); } + } } diff --git a/java/src/processing/mode/java/debug/LineID.java b/java/src/processing/mode/java/debug/LineID.java index e7c066110c..251a29ceee 100644 --- a/java/src/processing/mode/java/debug/LineID.java +++ b/java/src/processing/mode/java/debug/LineID.java @@ -1,29 +1,29 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; import java.util.HashSet; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; + import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; @@ -31,251 +31,247 @@ import javax.swing.text.Element; import javax.swing.text.Position; +import processing.app.Messages; + + /** * Describes an ID for a code line. Comprised of a file name and a (0-based) * line number. Can track changes to the line number due to text editing by * attaching a {@link Document}. Registered {@link LineListener}s are notified * of changes to the line number. - * - * @author Martin Leopold */ public class LineID implements DocumentListener { + protected String fileName; // the filename + protected int lineIdx; // the line number, 0-based + protected Document doc; // the Document to use for line number tracking + protected Position pos; // the Position acquired during line number tracking + protected Set listeners = new HashSet(); // listeners for line number changes - protected String fileName; // the filename - protected int lineIdx; // the line number, 0-based - protected Document doc; // the Document to use for line number tracking - protected Position pos; // the Position acquired during line number tracking - protected Set listeners = new HashSet(); // listeners for line number changes - public LineID(String fileName, int lineIdx) { - this.fileName = fileName; - this.lineIdx = lineIdx; - } + public LineID(String fileName, int lineIdx) { + this.fileName = fileName; + this.lineIdx = lineIdx; + } - /** - * Get the file name of this line. - * - * @return the file name - */ - public String fileName() { - return fileName; - } - /** - * Get the (0-based) line number of this line. - * - * @return the line index (i.e. line number, starting at 0) - */ - public synchronized int lineIdx() { - return lineIdx; - } + /** + * Get the file name of this line. + * + * @return the file name + */ + public String fileName() { + return fileName; + } - @Override - public int hashCode() { - return toString().hashCode(); - } - /** - * Test whether this {@link LineID} is equal to another object. Two - * {@link LineID}'s are equal when both their fileName and lineNo are equal. - * - * @param obj the object to test for equality - * @return {@code true} if equal - */ - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final LineID other = (LineID) obj; - if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { - return false; - } - if (this.lineIdx != other.lineIdx) { - return false; - } - return true; - } + /** + * Get the (0-based) line number of this line. + * + * @return the line index (i.e. line number, starting at 0) + */ + public synchronized int lineIdx() { + return lineIdx; + } - /** - * Output a string representation in the form fileName:lineIdx+1. Note this - * uses a 1-based line number as is customary for human-readable line - * numbers. - * - * @return the string representation of this line ID - */ - @Override - public String toString() { - return fileName + ":" + (lineIdx + 1); - } -// /** -// * Retrieve a copy of this line ID. -// * -// * @return the copy -// */ -// @Override -// public LineID clone() { -// return new LineID(fileName, lineIdx); -// } - - /** - * Attach a {@link Document} to enable line number tracking when editing. - * The position to track is before the first non-whitespace character on the - * line. Edits happening before that position will cause the line number to - * update accordingly. Multiple {@link #startTracking} calls will replace - * the tracked document. Whoever wants a tracked line should track it and - * add itself as listener if necessary. - * ({@link LineHighlight}, {@link LineBreakpoint}) - * - * @param doc the {@link Document} to use for line number tracking - */ - public synchronized void startTracking(Document doc) { - //System.out.println("tracking: " + this); - if (doc == null) { - return; // null arg - } - if (doc == this.doc) { - return; // already tracking that doc - } - try { - Element line = doc.getDefaultRootElement().getElement(lineIdx); - if (line == null) { - return; // line doesn't exist - } - String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset()); - // set tracking position at (=before) first non-white space character on line, - // or, if the line consists of entirely white spaces, just before the newline - // character - pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); - this.doc = doc; - doc.addDocumentListener(this); - } catch (BadLocationException ex) { - Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex); - pos = null; - this.doc = null; - } - } + @Override + public int hashCode() { + return toString().hashCode(); + } - /** - * Notify this {@link LineID} that it is no longer in use. Will stop - * position tracking. Call this when this {@link LineID} is no longer - * needed. - */ - public synchronized void stopTracking() { - if (doc != null) { - doc.removeDocumentListener(this); - doc = null; - } - } - /** - * Update the tracked position. Will notify listeners if line number has - * changed. - */ - protected synchronized void updatePosition() { - if (doc != null && pos != null) { - // track position - int offset = pos.getOffset(); - int oldLineIdx = lineIdx; - lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo - if (lineIdx != oldLineIdx) { - for (LineHighlight l : listeners) { - if (l != null) { - l.lineChanged(this, oldLineIdx, lineIdx); - } else { - listeners.remove(l); // remove null listener - } - } - } - } + /** + * Test whether this {@link LineID} is equal to another object. Two + * {@link LineID}'s are equal when both their fileName and lineNo are equal. + * + * @param obj the object to test for equality + * @return {@code true} if equal + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; } - - /** - * Add listener to be notified when the line number changes. - * - * @param l the listener to add - */ - public void addListener(LineHighlight l) { - listeners.add(l); + if (getClass() != obj.getClass()) { + return false; + } + final LineID other = (LineID) obj; + if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { + return false; } + if (this.lineIdx != other.lineIdx) { + return false; + } + return true; + } + + + /** + * Output a string representation in the form fileName:lineIdx+1. Note this + * uses a 1-based line number as is customary for human-readable line + * numbers. + * + * @return the string representation of this line ID + */ + @Override + public String toString() { + return fileName + ":" + (lineIdx + 1); + } - /** - * Remove a listener for line number changes. - * - * @param l the listener to remove - */ - public void removeListener(LineHighlight l) { - listeners.remove(l); + + /** + * Attach a {@link Document} to enable line number tracking when editing. + * The position to track is before the first non-whitespace character on the + * line. Edits happening before that position will cause the line number to + * update accordingly. Multiple {@link #startTracking} calls will replace + * the tracked document. Whoever wants a tracked line should track it and + * add itself as listener if necessary. + * ({@link LineHighlight}, {@link LineBreakpoint}) + * + * @param doc the {@link Document} to use for line number tracking + */ + public synchronized void startTracking(Document doc) { + //System.out.println("tracking: " + this); + if (doc == null) { + return; // null arg + } + if (doc == this.doc) { + return; // already tracking that doc + } + try { + Element line = doc.getDefaultRootElement().getElement(lineIdx); + if (line == null) { + return; // line doesn't exist + } + String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset()); + // set tracking position at (=before) first non-white space character on line, + // or, if the line consists of entirely white spaces, just before the newline + // character + pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); + this.doc = doc; + doc.addDocumentListener(this); + } catch (BadLocationException ex) { + Messages.loge(null, ex); + pos = null; + this.doc = null; } + } - /** - * Calculate the offset of the first non-whitespace character in a string. - * - * @param str the string to examine - * @return offset of first non-whitespace character in str - */ - protected static int nonWhiteSpaceOffset(String str) { - for (int i = 0; i < str.length(); i++) { - if (!Character.isWhitespace(str.charAt(i))) { - return i; - } - } - - /* If we've reached here, that implies the line consists of purely white - * space. So return at a position just after the whitespace (i.e., - * just before the newline). - * - * The " - 1" part resolves issue #3552 - */ - return str.length() - 1; + + /** + * Notify this {@link LineID} that it is no longer in use. Will stop + * position tracking. Call this when this {@link LineID} is no longer + * needed. + */ + public synchronized void stopTracking() { + if (doc != null) { + doc.removeDocumentListener(this); + doc = null; } + } + - /** - * Called when the {@link Document} registered using {@link #startTracking} - * is edited. This happens when text is inserted or removed. - * - * @param de - */ - protected void editEvent(DocumentEvent de) { - //System.out.println("document edit @ " + de.getOffset()); - if (de.getOffset() <= pos.getOffset()) { - updatePosition(); - //System.out.println("updating, new line no: " + lineNo); + /** + * Update the tracked position. Will notify listeners if line number has + * changed. + */ + protected synchronized void updatePosition() { + if (doc != null && pos != null) { + // track position + int offset = pos.getOffset(); + int oldLineIdx = lineIdx; + lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo + if (lineIdx != oldLineIdx) { + for (LineHighlight l : listeners) { + if (l != null) { + l.lineChanged(this, oldLineIdx, lineIdx); + } else { + listeners.remove(l); // remove null listener + } } + } } + } - /** - * {@link DocumentListener} callback. Called when text is inserted. - * - * @param de - */ - @Override - public void insertUpdate(DocumentEvent de) { - editEvent(de); - } - /** - * {@link DocumentListener} callback. Called when text is removed. - * - * @param de - */ - @Override - public void removeUpdate(DocumentEvent de) { - editEvent(de); + /** + * Add listener to be notified when the line number changes. + * + * @param l the listener to add + */ + public void addListener(LineHighlight l) { + listeners.add(l); + } + + + /** + * Remove a listener for line number changes. + * + * @param l the listener to remove + */ + public void removeListener(LineHighlight l) { + listeners.remove(l); + } + + + /** + * Calculate the offset of the first non-whitespace character in a string. + * @param str the string to examine + * @return offset of first non-whitespace character in str + */ + protected static int nonWhiteSpaceOffset(String str) { + for (int i = 0; i < str.length(); i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return i; + } } - /** - * {@link DocumentListener} callback. Called when attributes are changed. - * Not used. - * - * @param de - */ - @Override - public void changedUpdate(DocumentEvent de) { - // not needed. + // If we've reached here, that implies the line consists of purely white + // space. So return at a position just after the whitespace (i.e., + // just before the newline). + // + // The " - 1" part resolves issue #3552 + return str.length() - 1; + } + + + /** + * Called when the {@link Document} registered using {@link #startTracking} + * is edited. This happens when text is inserted or removed. + */ + protected void editEvent(DocumentEvent de) { + //System.out.println("document edit @ " + de.getOffset()); + if (de.getOffset() <= pos.getOffset()) { + updatePosition(); + //System.out.println("updating, new line no: " + lineNo); } + } + + + /** + * {@link DocumentListener} callback. Called when text is inserted. + */ + @Override + public void insertUpdate(DocumentEvent de) { + editEvent(de); + } + + + /** + * {@link DocumentListener} callback. Called when text is removed. + */ + @Override + public void removeUpdate(DocumentEvent de) { + editEvent(de); + } + + + /** + * {@link DocumentListener} callback. Called when attributes are changed. + * Not used. + */ + @Override + public void changedUpdate(DocumentEvent de) { + // not needed. + } } diff --git a/java/src/processing/mode/java/debug/LocalVariableNode.java b/java/src/processing/mode/java/debug/LocalVariableNode.java index 435a230f67..34bb91afc9 100644 --- a/java/src/processing/mode/java/debug/LocalVariableNode.java +++ b/java/src/processing/mode/java/debug/LocalVariableNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; @@ -25,45 +26,34 @@ import com.sun.jdi.LocalVariable; import com.sun.jdi.StackFrame; import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; + +import processing.app.Messages; + /** - * Specialized {@link VariableNode} for representing local variables. Overrides - * {@link #setValue} to properly change the value of the encapsulated local - * variable. - * - * @author Martin Leopold + * Specialized {@link VariableNode} for representing local variables. + * Overrides {@link #setValue} to properly change the value of the + * encapsulated local variable. */ public class LocalVariableNode extends VariableNode { + protected LocalVariable var; + protected StackFrame frame; - protected LocalVariable var; - protected StackFrame frame; - /** - * Construct a {@link LocalVariableNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param var the local variable - * @param frame the stack frame containing the local variable - */ - public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) { - super(name, type, value); - this.var = var; - this.frame = frame; - } + public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) { + super(name, type, value); + this.var = var; + this.frame = frame; + } + - @Override - public void setValue(Value value) { - try { - frame.setValue(var, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; + @Override + public void setValue(Value value) { + try { + frame.setValue(var, value); + } catch (InvalidTypeException | ClassNotLoadedException ex) { + Messages.loge(null, ex); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index e370f7da11..b8b2684471 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. + Copyright (c) 2012-16 The Processing Foundation -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2, as published by the Free Software Foundation. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.mode.java.debug; @@ -33,329 +34,350 @@ /** * Model for a variable in the variable inspector. Has a type and name and - * optionally a value. Can have sub-variables (as is the case for objects, and - * arrays). - * - * @author Martin Leopold + * optionally a value. Can have sub-variables (as is the case for objects, + * and arrays). */ public class VariableNode implements MutableTreeNode { - - public static final int TYPE_UNKNOWN = -1; - public static final int TYPE_OBJECT = 0; - public static final int TYPE_ARRAY = 1; - public static final int TYPE_INTEGER = 2; - public static final int TYPE_FLOAT = 3; - public static final int TYPE_BOOLEAN = 4; - public static final int TYPE_CHAR = 5; - public static final int TYPE_STRING = 6; - public static final int TYPE_LONG = 7; - public static final int TYPE_DOUBLE = 8; - public static final int TYPE_BYTE = 9; - public static final int TYPE_SHORT = 10; - public static final int TYPE_VOID = 11; - protected String type; - protected String name; - protected Value value; - protected List children = new ArrayList(); - protected MutableTreeNode parent; - - /** - * Construct a {@link VariableNode}. - * @param name the name - * @param type the type - * @param value the value - */ - public VariableNode(String name, String type, Value value) { - this.name = name; - this.type = type; - this.value = value; + public static final int TYPE_UNKNOWN = -1; + public static final int TYPE_OBJECT = 0; + public static final int TYPE_ARRAY = 1; + public static final int TYPE_INTEGER = 2; + public static final int TYPE_FLOAT = 3; + public static final int TYPE_BOOLEAN = 4; + public static final int TYPE_CHAR = 5; + public static final int TYPE_STRING = 6; + public static final int TYPE_LONG = 7; + public static final int TYPE_DOUBLE = 8; + public static final int TYPE_BYTE = 9; + public static final int TYPE_SHORT = 10; + public static final int TYPE_VOID = 11; + + protected String type; + protected String name; + protected Value value; + protected List children = new ArrayList<>(); + protected MutableTreeNode parent; + + + /** + * Construct a {@link VariableNode}. + * @param name the name + * @param type the type + * @param value the value + */ + public VariableNode(String name, String type, Value value) { + this.name = name; + this.type = type; + this.value = value; + } + + + public void setValue(Value value) { + this.value = value; + } + + + public Value getValue() { + return value; + } + + + /** + * Get a String representation of this variable nodes value. + * + * @return a String representing the value. + */ + public String getStringValue() { + String str; + if (value != null) { + if (getType() == TYPE_OBJECT) { + str = "instance of " + type; + } else if (getType() == TYPE_ARRAY) { + //instance of int[5] (id=998) --> instance of int[5] + str = value.toString().substring(0, value.toString().lastIndexOf(" ")); + } else if (getType() == TYPE_STRING) { + str = ((StringReference) value).value(); // use original string value (without quotes) + } else { + str = value.toString(); + } + } else { + str = "null"; } + return str; + } - public void setValue(Value value) { - this.value = value; - } - public Value getValue() { - return value; - } + public String getTypeName() { + return type; + } - /** - * Get a String representation of this variable nodes value. - * - * @return a String representing the value. - */ - public String getStringValue() { - String str; - if (value != null) { - if (getType() == TYPE_OBJECT) { - str = "instance of " + type; - } else if (getType() == TYPE_ARRAY) { - //instance of int[5] (id=998) --> instance of int[5] - str = value.toString().substring(0, value.toString().lastIndexOf(" ")); - } else if (getType() == TYPE_STRING) { - str = ((StringReference) value).value(); // use original string value (without quotes) - } else { - str = value.toString(); - } - } else { - str = "null"; - } - return str; - } - public String getTypeName() { - return type; + public int getType() { + if (type == null) { + return TYPE_UNKNOWN; } - - public int getType() { - if (type == null) { - return TYPE_UNKNOWN; - } - if (type.endsWith("[]")) { - return TYPE_ARRAY; - } - if (type.equals("int")) { - return TYPE_INTEGER; - } - if (type.equals("long")) { - return TYPE_LONG; - } - if (type.equals("byte")) { - return TYPE_BYTE; - } - if (type.equals("short")) { - return TYPE_SHORT; - } - if (type.equals("float")) { - return TYPE_FLOAT; - } - if (type.equals("double")) { - return TYPE_DOUBLE; - } - if (type.equals("char")) { - return TYPE_CHAR; - } - if (type.equals("java.lang.String")) { - return TYPE_STRING; - } - if (type.equals("boolean")) { - return TYPE_BOOLEAN; - } - if (type.equals("void")) { - return TYPE_VOID; //TODO: check if this is correct - } - return TYPE_OBJECT; + if (type.endsWith("[]")) { + return TYPE_ARRAY; } - - public String getName() { - return name; + if (type.equals("int")) { + return TYPE_INTEGER; } - - public void setName(String name) { - this.name = name; + if (type.equals("long")) { + return TYPE_LONG; } - - /** - * Add a {@link VariableNode} as child. - * - * @param c the {@link VariableNode} to add. - */ - public void addChild(VariableNode c) { - children.add(c); - c.setParent(this); + if (type.equals("byte")) { + return TYPE_BYTE; } - - /** - * Add multiple {@link VariableNode}s as children. - * - * @param children the list of {@link VariableNode}s to add. - */ - public void addChildren(List children) { - for (VariableNode child : children) { - addChild(child); - } + if (type.equals("short")) { + return TYPE_SHORT; } - - @Override - public TreeNode getChildAt(int i) { - return children.get(i); + if (type.equals("float")) { + return TYPE_FLOAT; } - - @Override - public int getChildCount() { - return children.size(); + if (type.equals("double")) { + return TYPE_DOUBLE; } - - @Override - public TreeNode getParent() { - return parent; + if (type.equals("char")) { + return TYPE_CHAR; } - - @Override - public int getIndex(TreeNode tn) { - return children.indexOf(tn); + if (type.equals("java.lang.String")) { + return TYPE_STRING; } - - @Override - public boolean getAllowsChildren() { - if (value == null) { - return false; - } - - // handle strings - if (getType() == TYPE_STRING) { - return false; - } - - // handle arrays - if (getType() == TYPE_ARRAY) { - ArrayReference array = (ArrayReference) value; - return array.length() > 0; - } - // handle objects - if (getType() == TYPE_OBJECT) { // this also rules out null - // check if this object has any fields - ObjectReference obj = (ObjectReference) value; - return !obj.referenceType().visibleFields().isEmpty(); - } - - return false; + if (type.equals("boolean")) { + return TYPE_BOOLEAN; } - - /** - * This controls the default icon and disclosure triangle. - * - * @return true, will show "folder" icon and disclosure triangle. - */ - @Override - public boolean isLeaf() { - //return children.size() == 0; - return !getAllowsChildren(); + if (type.equals("void")) { + return TYPE_VOID; //TODO: check if this is correct } + return TYPE_OBJECT; + } - @Override - public Enumeration children() { - return Collections.enumeration(children); - } - /** - * Get a String representation of this {@link VariableNode}. - * - * @return the name of the variable (for sorting to work). - */ - @Override - public String toString() { - return getName(); // for sorting - } + public String getName() { + return name; + } - /** - * Get a String description of this {@link VariableNode}. Contains the type, - * name and value. - * - * @return the description - */ - public String getDescription() { - String str = ""; - if (type != null) { - str += type + " "; - } - str += name; - str += " = " + getStringValue(); - return str; - } - @Override - public void insert(MutableTreeNode mtn, int i) { - children.add(i, this); + public void setName(String name) { + this.name = name; + } + + + /** + * Add a {@link VariableNode} as child. + * + * @param c the {@link VariableNode} to add. + */ + public void addChild(VariableNode c) { + children.add(c); + c.setParent(this); + } + + + /** + * Add multiple {@link VariableNode}s as children. + * + * @param children the list of {@link VariableNode}s to add. + */ + public void addChildren(List children) { + for (VariableNode child : children) { + addChild(child); } + } + + + @Override + public TreeNode getChildAt(int i) { + return children.get(i); + } - @Override - public void remove(int i) { - MutableTreeNode mtn = children.remove(i); - if (mtn != null) { - mtn.setParent(null); - } + + @Override + public int getChildCount() { + return children.size(); + } + + + @Override + public TreeNode getParent() { + return parent; + } + + + @Override + public int getIndex(TreeNode tn) { + return children.indexOf(tn); + } + + + @Override + public boolean getAllowsChildren() { + if (value == null) { + return false; } - @Override - public void remove(MutableTreeNode mtn) { - children.remove(mtn); - mtn.setParent(null); + // handle strings + if (getType() == TYPE_STRING) { + return false; } - /** - * Remove all children from this {@link VariableNode}. - */ - public void removeAllChildren() { - for (MutableTreeNode mtn : children) { - mtn.setParent(null); - } - children.clear(); + // handle arrays + if (getType() == TYPE_ARRAY) { + ArrayReference array = (ArrayReference) value; + return array.length() > 0; + } + // handle objects + if (getType() == TYPE_OBJECT) { // this also rules out null + // check if this object has any fields + ObjectReference obj = (ObjectReference) value; + return !obj.referenceType().visibleFields().isEmpty(); } - @Override - public void setUserObject(Object o) { - if (o instanceof Value) { - value = (Value) o; - } + return false; + } + + + /** + * This controls the default icon and disclosure triangle. + * + * @return true, will show "folder" icon and disclosure triangle. + */ + @Override + public boolean isLeaf() { + //return children.size() == 0; + return !getAllowsChildren(); + } + + + @Override + public Enumeration children() { + return Collections.enumeration(children); + } + + + /** + * Get a String representation of this {@link VariableNode}. + * + * @return the name of the variable (for sorting to work). + */ + @Override + public String toString() { + return getName(); // for sorting + } + + + /** + * Get a String description of this {@link VariableNode}. Contains the type, + * name and value. + * + * @return the description + */ + public String getDescription() { + String str = ""; + if (type != null) { + str += type + " "; } + str += name; + str += " = " + getStringValue(); + return str; + } + - @Override - public void removeFromParent() { - parent.remove(this); - this.parent = null; + @Override + public void insert(MutableTreeNode mtn, int i) { + children.add(i, this); + } + + + @Override + public void remove(int i) { + MutableTreeNode mtn = children.remove(i); + if (mtn != null) { + mtn.setParent(null); } + } + - @Override - public void setParent(MutableTreeNode mtn) { - parent = mtn; + @Override + public void remove(MutableTreeNode mtn) { + children.remove(mtn); + mtn.setParent(null); + } + + + /** + * Remove all children from this {@link VariableNode}. + */ + public void removeAllChildren() { + for (MutableTreeNode mtn : children) { + mtn.setParent(null); } + children.clear(); + } + - /** - * Test for equality. To be equal, two {@link VariableNode}s need to have - * equal type, name and value. - * - * @param obj the object to test for equality with this {@link VariableNode} - * @return true if the given object is equal to this {@link VariableNode} - */ - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final VariableNode other = (VariableNode) obj; - if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { - //System.out.println("type not equal"); - return false; - } - if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { - //System.out.println("name not equal"); - return false; - } - if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { - //System.out.println("value not equal"); - return false; - } -// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) { -// System.out.println("parent not equal: " + this.parent + "/" + other.parent); -// return false; -// } - return true; + @Override + public void setUserObject(Object o) { + if (o instanceof Value) { + value = (Value) o; } + } + + + @Override + public void removeFromParent() { + parent.remove(this); + this.parent = null; + } + - /** - * Returns a hash code based on type, name and value. - */ - @Override - public int hashCode() { - int hash = 3; - hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0); - hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); - hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0); -// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0); - return hash; + @Override + public void setParent(MutableTreeNode mtn) { + parent = mtn; + } + + + /** + * Test for equality. To be equal, two {@link VariableNode}s need to have + * equal type, name and value. + * + * @param obj the object to test for equality with this {@link VariableNode} + * @return true if the given object is equal to this {@link VariableNode} + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final VariableNode other = (VariableNode) obj; + if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { + //System.out.println("type not equal"); + return false; + } + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + //System.out.println("name not equal"); + return false; + } + if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { + //System.out.println("value not equal"); + return false; } + return true; + } + + + /** + * Returns a hash code based on type, name and value. + */ + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0); + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0); + return hash; + } } diff --git a/java/src/processing/mode/java/pdex/CompletionCandidate.java b/java/src/processing/mode/java/pdex/CompletionCandidate.java index 6b355db48c..1b7533e822 100644 --- a/java/src/processing/mode/java/pdex/CompletionCandidate.java +++ b/java/src/processing/mode/java/pdex/CompletionCandidate.java @@ -2,7 +2,7 @@ /* Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation +Copyright (c) 2012-18 The Processing Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -32,10 +32,16 @@ import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +// TODO when building the label in some variants in this file, +// getReturnType2() is used instead of getReturnType(). +// need to check whether that's identical in how it performs, +// and if so, use makeLabel() and makeCompletion() more [fry 180326] +// https://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2Fdom%2FMethodDeclaration.html + public class CompletionCandidate implements Comparable { private final String elementName; private final String label; // the toString value - private final String completionString; + private final String completion; private final Object wrappedObject; private final int type; @@ -48,60 +54,38 @@ public class CompletionCandidate implements Comparable { static final int LOCAL_VAR = 6; - public CompletionCandidate(Method method) { + CompletionCandidate(Method method) { + // return value ignored? [fry 180326] method.getDeclaringClass().getName(); elementName = method.getName(); - StringBuilder label = new StringBuilder(""+method.getName() + "("); - StringBuilder cstr = new StringBuilder(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) { - label.append(","); - cstr.append(","); - } - } - if(method.getParameterTypes().length == 1) { - cstr.append(' '); - } - label.append(")"); - if(method.getReturnType() != null) - label.append(" : " + method.getReturnType().getSimpleName()); - label.append(" - " + method.getDeclaringClass().getSimpleName() + ""); - cstr.append(")"); - this.label = label.toString(); - this.completionString = cstr.toString(); + label = makeLabel(method); + completion = makeCompletion(method); type = PREDEF_METHOD; wrappedObject = method; } - public Object getWrappedObject() { - return wrappedObject; - } - public CompletionCandidate(SingleVariableDeclaration svd) { - completionString = svd.getName().toString(); + CompletionCandidate(SingleVariableDeclaration svd) { + completion = svd.getName().toString(); elementName = svd.getName().toString(); - if(svd.getParent() instanceof FieldDeclaration) - type = LOCAL_FIELD; - else - type = LOCAL_VAR; + type = (svd.getParent() instanceof FieldDeclaration) ? + LOCAL_FIELD : LOCAL_VAR; label = svd.getName() + " : " + svd.getType(); wrappedObject = svd; } - public CompletionCandidate(VariableDeclarationFragment vdf) { - completionString = vdf.getName().toString(); + + CompletionCandidate(VariableDeclarationFragment vdf) { + completion = vdf.getName().toString(); elementName = vdf.getName().toString(); - if(vdf.getParent() instanceof FieldDeclaration) - type = LOCAL_FIELD; - else - type = LOCAL_VAR; + type = (vdf.getParent() instanceof FieldDeclaration) ? + LOCAL_FIELD : LOCAL_VAR; label = vdf.getName() + " : " + CompletionGenerator.extracTypeInfo2(vdf); wrappedObject = vdf; } - public CompletionCandidate(MethodDeclaration method) { - // log("ComCan " + method.getName()); + + CompletionCandidate(MethodDeclaration method) { elementName = method.getName().toString(); type = LOCAL_METHOD; @@ -109,193 +93,288 @@ public CompletionCandidate(MethodDeclaration method) { List params = (List) method.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); - StringBuilder label = new StringBuilder(elementName + "("); - StringBuilder cstr = new StringBuilder(method.getName() + "("); - for (int i = 0; i < params.size(); i++) { - label.append(params.get(i).toString()); - if (i < params.size() - 1) { - label.append(","); - cstr.append(","); + { // label + StringBuilder labelBuilder = new StringBuilder(elementName); + labelBuilder.append('('); + for (int i = 0; i < params.size(); i++) { + labelBuilder.append(params.get(i).toString()); + if (i < params.size() - 1) { + labelBuilder.append(','); + } + } + labelBuilder.append(')'); + if (method.getReturnType2() != null) { + labelBuilder.append(" : "); + labelBuilder.append(method.getReturnType2()); } + label = labelBuilder.toString(); } - if (params.size() == 1) { - cstr.append(' '); + + { // completion + StringBuilder compBuilder = new StringBuilder(elementName); + compBuilder.append('('); + + for (int i = 0; i < params.size(); i++) { + if (i < params.size() - 1) { + compBuilder.append(','); + } + } + if (params.size() == 1) { + compBuilder.append(' '); + } + compBuilder.append(')'); + completion = compBuilder.toString(); } - label.append(")"); - if (method.getReturnType2() != null) - label.append(" : " + method.getReturnType2()); - cstr.append(")"); - this.label = label.toString(); - this.completionString = cstr.toString(); + wrappedObject = method; } - public CompletionCandidate(TypeDeclaration td){ + + CompletionCandidate(TypeDeclaration td) { type = LOCAL_CLASS; elementName = td.getName().toString(); label = elementName; - completionString = elementName; + completion = elementName; wrappedObject = td; } - public CompletionCandidate(Field f) { + + CompletionCandidate(Field f) { f.getDeclaringClass().getName(); elementName = f.getName(); type = PREDEF_FIELD; -// "" -// + matchedClass + " : " + "" -// + matchedClass2.substring(0, d) + "", matchedClass -// + "" - label = "" + f.getName() + " : " + f.getType().getSimpleName() + - " - " + f.getDeclaringClass().getSimpleName() + - ""; - completionString = elementName; + label = "" + + f.getName() + " : " + + f.getType().getSimpleName() + " - " + + "" + + f.getDeclaringClass().getSimpleName() + + ""; + completion = elementName; wrappedObject = f; } - public CompletionCandidate(String name, String labelStr, String completionStr, int type) { - elementName = name; - label = labelStr; - completionString = completionStr; - this.type = type; - wrappedObject = null; - } - public CompletionCandidate(String name, int type) { - elementName = name; - label = name; - completionString = name; - this.type = type; - wrappedObject = null; + CompletionCandidate(String elementName, String label, + String completion, int type) { + this(elementName, label, completion, type, null); } + private CompletionCandidate(String elementName, String label, - String completionString, int type, + String completion, int type, Object wrappedObject) { this.elementName = elementName; this.label = label; - this.completionString = completionString; + this.completion = completion; this.type = type; this.wrappedObject = wrappedObject; } + + Object getWrappedObject() { + return wrappedObject; + } + + public String getElementName() { return elementName; } + public String getCompletionString() { - return completionString; + return completion; } - public String toString() { - return label; - } public int getType() { return type; } + public String getLabel() { return label; } - public String getNoHtmlLabel(){ - if(!label.contains("")) { + + // TODO this is gross [fry 180326] + /* + private String getNoHtmlLabel(){ + if (!label.contains("")) { return label; - } - else { + + } else { StringBuilder ans = new StringBuilder(label); - while(ans.indexOf("<") > -1) { + while (ans.indexOf("<") > -1) { int a = ans.indexOf("<"), b = ans.indexOf(">"); - if(a > b) break; + if (a > b) break; ans.replace(a, b+1, ""); -// System.out.println(ans.replace(a, b+1, "")); -// System.out.println(ans + "--"); } return ans.toString(); } } + */ + - public CompletionCandidate withLabelAndCompString(String label, - String completionString) { - return new CompletionCandidate(this.elementName, label, completionString, - this.type, this.wrappedObject); + boolean startsWith(String newWord) { +// System.out.println("checking " + newWord); +// return getNoHtmlLabel().toLowerCase().startsWith(newWord); + // this seems to be elementName in all cases [fry 180326] + return elementName.startsWith(newWord); } - @Override - public int compareTo(CompletionCandidate cc) { - if(type != cc.getType()){ - return cc.getType() - type; - } - return (elementName.compareTo(cc.getElementName())); + + CompletionCandidate withLabelAndCompString(String withLabel, + String withCompletion) { + return new CompletionCandidate(elementName, + withLabel, withCompletion, + type, wrappedObject); } - public CompletionCandidate withRegeneratedCompString() { + + CompletionCandidate withRegeneratedCompString() { if (wrappedObject instanceof MethodDeclaration) { MethodDeclaration method = (MethodDeclaration)wrappedObject; @SuppressWarnings("unchecked") List params = (List) - method.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); + method.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); - StringBuilder label = new StringBuilder(elementName + "("); - StringBuilder cstr = new StringBuilder(method.getName() + "("); + // build the html label + StringBuilder labelBuilder = new StringBuilder(elementName); + labelBuilder.append('('); for (int i = 0; i < params.size(); i++) { - label.append(params.get(i).toString()); + labelBuilder.append(params.get(i)); if (i < params.size() - 1) { - label.append(","); - cstr.append(","); + labelBuilder.append(','); + } + } + labelBuilder.append(')'); + if (method.getReturnType2() != null) { + labelBuilder.append(" : "); + labelBuilder.append(method.getReturnType2()); + } + + // build the completion str + StringBuilder compBuilder = new StringBuilder(); + compBuilder.append(method.getName()); + compBuilder.append('('); + for (int i = 0; i < params.size(); i++) { + if (i < params.size() - 1) { + compBuilder.append(','); } } if (params.size() == 1) { - cstr.append(' '); + compBuilder.append(' '); + } + compBuilder.append(')'); + + return withLabelAndCompString(labelBuilder.toString(), compBuilder.toString()); + + } else if (wrappedObject instanceof Method) { + Method method = (Method) wrappedObject; + Class[] types = method.getParameterTypes(); + + // build html label + StringBuilder labelBuilder = new StringBuilder(); + labelBuilder.append(""); + labelBuilder.append(method.getName()); + labelBuilder.append('('); + + for (int i = 0; i < types.length; i++) { + labelBuilder.append(types[i].getSimpleName()); + if (i < types.length - 1) { + labelBuilder.append(','); + } + } + labelBuilder.append(')'); + if (method.getReturnType() != null) { + labelBuilder.append(" : " + method.getReturnType().getSimpleName()); + } + + labelBuilder.append(" - "); + labelBuilder.append(method.getDeclaringClass().getSimpleName()); + labelBuilder.append(""); + labelBuilder.append(""); + + // make completion string + StringBuilder compBuilder = new StringBuilder(method.getName()); + compBuilder.append('('); + for (int i = 0; i < types.length; i++) { + if (i < types.length - 1) { + compBuilder.append(','); + } + } + if (types.length == 1) { + compBuilder.append(' '); + } + compBuilder.append(')'); + + return withLabelAndCompString(labelBuilder.toString(), compBuilder.toString()); + } + + // fall-through silently does nothing? [fry 180326] + return this; + } + + + static private String makeLabel(Method method) { + Class[] types = method.getParameterTypes(); + + StringBuilder labelBuilder = new StringBuilder(); + labelBuilder.append(""); + labelBuilder.append(method.getName()); + labelBuilder.append('('); + + for (int i = 0; i < types.length; i++) { + labelBuilder.append(types[i].getSimpleName()); + if (i < types.length - 1) { + labelBuilder.append(','); } - label.append(")"); - if (method.getReturnType2() != null) - label.append(" : " + method.getReturnType2()); - cstr.append(")"); - return this.withLabelAndCompString(label.toString(), cstr.toString()); } - else if (wrappedObject instanceof Method) { - Method method = (Method)wrappedObject; - StringBuilder label = new StringBuilder("" + method.getName() + "("); - StringBuilder cstr = new StringBuilder(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) { - label.append(","); - cstr.append(","); - } - } - if(method.getParameterTypes().length == 1) { - cstr.append(' '); - } - label.append(")"); - if(method.getReturnType() != null) - label.append(" : " + method.getReturnType().getSimpleName()); - label.append(" - " + method.getDeclaringClass().getSimpleName() + ""); - cstr.append(")"); - return this.withLabelAndCompString(label.toString(), cstr.toString()); - /* - * StringBuilder label = new StringBuilder(""+method.getName() + "("); - StringBuilder cstr = new StringBuilder(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) { - label.append(","); - cstr.append(","); + labelBuilder.append(")"); + if (method.getReturnType() != null) { + labelBuilder.append(" : "); + labelBuilder.append(method.getReturnType().getSimpleName()); + } + labelBuilder.append(" - "); + labelBuilder.append(method.getDeclaringClass().getSimpleName()); + labelBuilder.append(""); + labelBuilder.append(""); + + return labelBuilder.toString(); + } + + + static private String makeCompletion(Method method) { + Class[] types = method.getParameterTypes(); + + StringBuilder compBuilder = new StringBuilder(); + compBuilder.append(method.getName()); + compBuilder.append('('); + + for (int i = 0; i < types.length; i++) { + if (i < types.length - 1) { + compBuilder.append(','); // wtf? [fry 180326] } } - if(method.getParameterTypes().length == 1) { - cstr.append(' '); + if (types.length == 1) { + compBuilder.append(' '); } - label.append(")"); - if(method.getReturnType() != null) - label.append(" : " + method.getReturnType().getSimpleName()); - label.append(" - " + method.getDeclaringClass().getSimpleName() + ""); - * */ - } - return this; + compBuilder.append(')'); + return compBuilder.toString(); } + + @Override + public int compareTo(CompletionCandidate cc) { + if (type != cc.getType()) { + return cc.getType() - type; + } + return elementName.compareTo(cc.getElementName()); + } + + + public String toString() { + return label; + } } diff --git a/java/src/processing/mode/java/pdex/CompletionGenerator.java b/java/src/processing/mode/java/pdex/CompletionGenerator.java index 6ccc639d58..67ad944196 100644 --- a/java/src/processing/mode/java/pdex/CompletionGenerator.java +++ b/java/src/processing/mode/java/pdex/CompletionGenerator.java @@ -1713,7 +1713,8 @@ protected static List trimCandidates(String newWord, List newCandidate = new ArrayList<>(); newWord = newWord.toLowerCase(); for (CompletionCandidate comp : candidates) { - if(comp.getNoHtmlLabel().toLowerCase().startsWith(newWord)){ + //if (comp.getNoHtmlLabel().toLowerCase().startsWith(newWord)) { + if (comp.startsWith(newWord)) { newCandidate.add(comp); } } diff --git a/java/src/processing/mode/java/pdex/DebugTree.java b/java/src/processing/mode/java/pdex/DebugTree.java new file mode 100644 index 0000000000..a3ccb48e18 --- /dev/null +++ b/java/src/processing/mode/java/pdex/DebugTree.java @@ -0,0 +1,139 @@ +package processing.mode.java.pdex; + +import java.awt.EventQueue; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.function.Consumer; + +import javax.swing.JDialog; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.WindowConstants; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; + +import processing.app.Messages; +import processing.app.ui.ZoomTreeCellRenderer; +import processing.mode.java.JavaEditor; +import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; + + +class DebugTree { + final JDialog window; + final JTree tree; + final Consumer updateListener; + + + DebugTree(JavaEditor editor, PreprocessingService pps) { + updateListener = this::buildAndUpdateTree; + + window = new JDialog(editor); + + tree = new JTree() { + @Override + public String convertValueToText(Object value, boolean selected, + boolean expanded, boolean leaf, + int row, boolean hasFocus) { + if (value instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; + Object o = treeNode.getUserObject(); + if (o instanceof ASTNode) { + ASTNode node = (ASTNode) o; + return CompletionGenerator.getNodeAsString(node); + } + } + return super.convertValueToText(value, selected, expanded, leaf, row, hasFocus); + } + }; + tree.setCellRenderer(new ZoomTreeCellRenderer(editor.getMode())); + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent e) { + pps.unregisterListener(updateListener); + tree.setModel(null); + } + }); + window.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + window.setBounds(new Rectangle(680, 100, 460, 620)); + window.setTitle("AST View - " + editor.getSketch().getName()); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(tree); + window.add(sp); + pps.whenDone(updateListener); + pps.registerListener(updateListener); + + tree.addTreeSelectionListener(e -> { + if (tree.getLastSelectedPathComponent() != null) { + DefaultMutableTreeNode tnode = + (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (tnode.getUserObject() instanceof ASTNode) { + ASTNode node = (ASTNode) tnode.getUserObject(); + pps.whenDone(ps -> { + SketchInterval si = ps.mapJavaToSketch(node); + if (!ps.inRange(si)) return; + EventQueue.invokeLater(() -> { + editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset); + }); + }); + } + } + }); + } + + + void dispose() { + if (window != null) { + window.dispose(); + } + } + + + // Thread: worker + void buildAndUpdateTree(PreprocessedSketch ps) { + CompilationUnit cu = ps.compilationUnit; + if (cu.types().isEmpty()){ + Messages.loge("No Type found in CU"); + return; + } + + Deque treeNodeStack = new ArrayDeque<>(); + + ASTNode type0 = (ASTNode) cu.types().get(0); + type0.accept(new ASTVisitor() { + @Override + public boolean preVisit2(ASTNode node) { + treeNodeStack.push(new DefaultMutableTreeNode(node)); + return super.preVisit2(node); + } + + @Override + public void postVisit(ASTNode node) { + if (treeNodeStack.size() > 1) { + DefaultMutableTreeNode treeNode = treeNodeStack.pop(); + treeNodeStack.peek().add(treeNode); + } + } + }); + + DefaultMutableTreeNode codeTree = treeNodeStack.pop(); + + EventQueue.invokeLater(() -> { + if (tree.hasFocus() || window.hasFocus()) { + return; + } + tree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) tree.getModel()).reload(); + tree.validate(); + if (!window.isVisible()) { + window.setVisible(true); + } + }); + } +} \ No newline at end of file diff --git a/java/src/processing/mode/java/pdex/ErrorChecker.java b/java/src/processing/mode/java/pdex/ErrorChecker.java new file mode 100644 index 0000000000..4c735bc7f9 --- /dev/null +++ b/java/src/processing/mode/java/pdex/ErrorChecker.java @@ -0,0 +1,327 @@ +package processing.mode.java.pdex; + +import java.awt.EventQueue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.jdt.core.compiler.IProblem; + +import com.google.classpath.ClassPath; +import com.google.classpath.ClassPathFactory; +import com.google.classpath.RegExpResourceFilter; + +import processing.app.Language; +import processing.app.Problem; +import processing.mode.java.JavaEditor; +import processing.mode.java.JavaMode; +import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; + + +class ErrorChecker { + // Delay delivering error check result after last sketch change #2677 + private final static long DELAY_BEFORE_UPDATE = 650; + + private ScheduledExecutorService scheduler; + private volatile ScheduledFuture scheduledUiUpdate = null; + private volatile long nextUiUpdate = 0; + private volatile boolean enabled = true; + + private final Consumer errorHandlerListener = this::handleSketchProblems; + + private JavaEditor editor; + private PreprocessingService pps; + + + public ErrorChecker(JavaEditor editor, PreprocessingService pps) { + this.editor = editor; + this.pps = pps; + scheduler = Executors.newSingleThreadScheduledExecutor(); + this.enabled = JavaMode.errorCheckEnabled; + if (enabled) { + pps.registerListener(errorHandlerListener); + } + } + + + public void notifySketchChanged() { + nextUiUpdate = System.currentTimeMillis() + DELAY_BEFORE_UPDATE; + } + + + public void preferencesChanged() { + if (enabled != JavaMode.errorCheckEnabled) { + enabled = JavaMode.errorCheckEnabled; + if (enabled) { + pps.registerListener(errorHandlerListener); + } else { + pps.unregisterListener(errorHandlerListener); + editor.setProblemList(Collections.emptyList()); + nextUiUpdate = 0; + } + } + } + + + public void dispose() { + if (scheduler != null) { + scheduler.shutdownNow(); + } + } + + + private void handleSketchProblems(PreprocessedSketch ps) { + Map suggCache = + JavaMode.importSuggestEnabled ? new HashMap<>() : Collections.emptyMap(); + + final List problems = new ArrayList<>(); + + IProblem[] iproblems = ps.compilationUnit.getProblems(); + + { // Check for curly quotes + List curlyQuoteProblems = checkForCurlyQuotes(ps); + problems.addAll(curlyQuoteProblems); + } + + if (problems.isEmpty()) { // Check for missing braces + List missingBraceProblems = checkForMissingBraces(ps); + problems.addAll(missingBraceProblems); + } + + if (problems.isEmpty()) { + AtomicReference searchClassPath = new AtomicReference<>(null); + List cuProblems = Arrays.stream(iproblems) + // Filter Warnings if they are not enabled + .filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled)) + // Hide a useless error which is produced when a line ends with + // an identifier without a semicolon. "Missing a semicolon" is + // also produced and is preferred over this one. + // (Syntax error, insert ":: IdentifierOrNew" to complete Expression) + // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780 + .filter(iproblem -> !iproblem.getMessage() + .contains("Syntax error, insert \":: IdentifierOrNew\"")) + // Transform into our Problems + .map(iproblem -> { + JavaProblem p = convertIProblem(iproblem, ps); + + // Handle import suggestions + if (p != null && JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) { + ClassPath cp = searchClassPath.updateAndGet(prev -> prev != null ? + prev : new ClassPathFactory().createFromPaths(ps.searchClassPathArray)); + String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0], + name -> getImportSuggestions(cp, name)); + p.setImportSuggestions(s); + } + + return p; + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + problems.addAll(cuProblems); + } + + if (scheduledUiUpdate != null) { + scheduledUiUpdate.cancel(true); + } + // Update UI after a delay. See #2677 + long delay = nextUiUpdate - System.currentTimeMillis(); + Runnable uiUpdater = () -> { + if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) { + EventQueue.invokeLater(() -> editor.setProblemList(problems)); + } + }; + scheduledUiUpdate = + scheduler.schedule(uiUpdater, delay, TimeUnit.MILLISECONDS); + } + + + static private JavaProblem convertIProblem(IProblem iproblem, PreprocessedSketch ps) { + SketchInterval in = ps.mapJavaToSketch(iproblem); + if (in != SketchInterval.BEFORE_START) { + String badCode = ps.getPdeCode(in); + int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); + JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line, badCode); + p.setPDEOffsets(in.startTabOffset, in.stopTabOffset); + return p; + } + return null; + } + + + static private boolean isUndefinedTypeProblem(IProblem iproblem) { + int id = iproblem.getID(); + return id == IProblem.UndefinedType || + id == IProblem.UndefinedName || + id == IProblem.UnresolvedVariable; + } + + + static private boolean isMissingBraceProblem(IProblem iproblem) { + if (iproblem.getID() == IProblem.ParsingErrorInsertToComplete) { + char brace = iproblem.getArguments()[0].charAt(0); + return brace == '{' || brace == '}'; + + } else if (iproblem.getID() == IProblem.ParsingErrorInsertTokenAfter) { + char brace = iproblem.getArguments()[1].charAt(0); + return brace == '{' || brace == '}'; + } + return false; + } + + + static private final Pattern CURLY_QUOTE_REGEX = + Pattern.compile("([“”‘’])", Pattern.UNICODE_CHARACTER_CLASS); + + static private List checkForCurlyQuotes(PreprocessedSketch ps) { + List problems = new ArrayList<>(0); + + // Go through the scrubbed code and look for curly quotes (they should not be any) + Matcher matcher = CURLY_QUOTE_REGEX.matcher(ps.scrubbedPdeCode); + while (matcher.find()) { + int pdeOffset = matcher.start(); + String q = matcher.group(); + + int tabIndex = ps.pdeOffsetToTabIndex(pdeOffset); + int tabOffset = ps.pdeOffsetToTabOffset(tabIndex, pdeOffset); + int tabLine = ps.tabOffsetToTabLine(tabIndex, tabOffset); + + String message = Language.interpolate("editor.status.bad_curly_quote", q); + JavaProblem problem = new JavaProblem(message, JavaProblem.ERROR, tabIndex, tabLine); + problem.setPDEOffsets(tabOffset, tabOffset+1); + + problems.add(problem); + } + + + // Go through iproblems and look for problems involving curly quotes + List problems2 = new ArrayList<>(0); + IProblem[] iproblems = ps.compilationUnit.getProblems(); + + for (IProblem iproblem : iproblems) { + switch (iproblem.getID()) { + case IProblem.ParsingErrorDeleteToken: + case IProblem.ParsingErrorDeleteTokens: + case IProblem.ParsingErrorInvalidToken: + case IProblem.ParsingErrorReplaceTokens: + case IProblem.UnterminatedString: + SketchInterval in = ps.mapJavaToSketch(iproblem); + if (in == SketchInterval.BEFORE_START) continue; + String badCode = ps.getPdeCode(in); + matcher.reset(badCode); + while (matcher.find()) { + int offset = matcher.start(); + String q = matcher.group(); + int tabStart = in.startTabOffset + offset; + int tabStop = tabStart + 1; + // Prevent duplicate problems + if (problems.stream().noneMatch(p -> p.getStartOffset() == tabStart)) { + int line = ps.tabOffsetToTabLine(in.tabIndex, tabStart); + String message; + if (iproblem.getID() == IProblem.UnterminatedString) { + message = Language.interpolate("editor.status.unterm_string_curly", q); + } else { + message = Language.interpolate("editor.status.bad_curly_quote", q); + } + JavaProblem p = new JavaProblem(message, JavaProblem.ERROR, in.tabIndex, line); + p.setPDEOffsets(tabStart, tabStop); + problems2.add(p); + } + } + } + } + + problems.addAll(problems2); + + return problems; + } + + + static private List checkForMissingBraces(PreprocessedSketch ps) { + List problems = new ArrayList<>(0); + for (int tabIndex = 0; tabIndex < ps.tabStartOffsets.length; tabIndex++) { + int tabStartOffset = ps.tabStartOffsets[tabIndex]; + int tabEndOffset = (tabIndex < ps.tabStartOffsets.length - 1) ? + ps.tabStartOffsets[tabIndex + 1] : ps.scrubbedPdeCode.length(); + int[] braceResult = SourceUtils.checkForMissingBraces(ps.scrubbedPdeCode, tabStartOffset, tabEndOffset); + if (braceResult[0] != 0) { + JavaProblem problem = + new JavaProblem(braceResult[0] < 0 + ? Language.interpolate("editor.status.missing.left_curly_bracket") + : Language.interpolate("editor.status.missing.right_curly_bracket"), + JavaProblem.ERROR, tabIndex, braceResult[1]); + problem.setPDEOffsets(braceResult[3], braceResult[3] + 1); + problems.add(problem); + } + } + + if (problems.isEmpty()) { + return problems; + } + + int problemTabIndex = problems.get(0).getTabIndex(); + + IProblem missingBraceProblem = Arrays.stream(ps.compilationUnit.getProblems()) + .filter(ErrorChecker::isMissingBraceProblem) + // Ignore if it is at the end of file + .filter(p -> p.getSourceEnd() + 1 < ps.javaCode.length()) + // Ignore if the tab number does not match our detected tab number + .filter(p -> problemTabIndex == ps.mapJavaToSketch(p).tabIndex) + .findFirst() + .orElse(null); + + // Prefer ECJ problem, shows location more accurately + if (missingBraceProblem != null) { + JavaProblem p = convertIProblem(missingBraceProblem, ps); + if (p != null) { + problems.clear(); + problems.add(p); + } + } + + return problems; + } + + + static public String[] getImportSuggestions(ClassPath cp, String className) { + className = className.replace("[", "\\[").replace("]", "\\]"); + RegExpResourceFilter regf = new RegExpResourceFilter( + Pattern.compile(".*"), + Pattern.compile("(.*\\$)?" + className + "\\.class", + Pattern.CASE_INSENSITIVE)); + + String[] resources = cp.findResources("", regf); + return Arrays.stream(resources) + // remove ".class" suffix + .map(res -> res.substring(0, res.length() - 6)) + // replace path separators with dots + .map(res -> res.replace('/', '.')) + // replace inner class separators with dots + .map(res -> res.replace('$', '.')) + // sort, prioritize clases from java. package + .sorted((o1, o2) -> { + // put java.* first, should be prioritized more + boolean o1StartsWithJava = o1.startsWith("java"); + boolean o2StartsWithJava = o2.startsWith("java"); + if (o1StartsWithJava != o2StartsWithJava) { + if (o1StartsWithJava) return -1; + return 1; + } + return o1.compareTo(o2); + }) + .toArray(String[]::new); + } +} \ No newline at end of file diff --git a/java/src/processing/mode/java/pdex/ErrorMessageSimplifier.java b/java/src/processing/mode/java/pdex/ErrorMessageSimplifier.java index df7909e8ee..f165798d0b 100644 --- a/java/src/processing/mode/java/pdex/ErrorMessageSimplifier.java +++ b/java/src/processing/mode/java/pdex/ErrorMessageSimplifier.java @@ -23,11 +23,14 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Language; +import processing.app.Messages; import processing.core.PApplet; import processing.data.StringList; @@ -42,25 +45,20 @@ public class ErrorMessageSimplifier { */ private static TreeMap constantsMap; + private static final boolean DEBUG = false; - public ErrorMessageSimplifier() { - - new Thread() { - public void run() { - prepareConstantsList(); - } - }.start(); - } - + private static final Pattern tokenRegExp = Pattern.compile("\\b token\\b"); private static void prepareConstantsList() { - constantsMap = new TreeMap(); + constantsMap = new TreeMap<>(); Class probClass = DefaultProblem.class; Field f[] = probClass.getFields(); for (Field field : f) { if (Modifier.isStatic(field.getModifiers())) try { - //System.out.println(field.getName() + " :" + field.get(null)); + if (DEBUG) { + Messages.log(field.getName() + " :" + field.get(null)); + } Object val = field.get(null); if (val instanceof Integer) { constantsMap.put((Integer) (val), field.getName()); @@ -70,12 +68,14 @@ private static void prepareConstantsList() { break; } } - //System.out.println("Total items: " + constantsMap.size()); + if (DEBUG) { + Messages.log("Total items: " + constantsMap.size()); + } } public static String getIDName(int id) { - if (constantsMap == null){ + if (constantsMap == null) { prepareConstantsList(); } return constantsMap.get(id); @@ -85,184 +85,223 @@ public static String getIDName(int id) { /** * Tones down the jargon in the ecj reported errors. */ - public static String getSimplifiedErrorMessage(JavaProblem problem) { - if (problem == null) return null; + public static String getSimplifiedErrorMessage(IProblem iprob, String badCode) { + if (iprob == null) return null; - IProblem iprob = problem.getIProblem(); String args[] = iprob.getArguments(); -// Base.log("Simplifying message: " + problem.getMessage() + " ID: " -// + getIDName(iprob.getID())); -// Base.log("Arg count: " + args.length); -// for (int i = 0; i < args.length; i++) { -// Base.log("Arg " + args[i]); -// } + + if (DEBUG) { + Messages.log("Simplifying message: " + iprob.getMessage() + + " ID: " + getIDName(iprob.getID())); + Messages.log("Arg count: " + args.length); + for (String arg : args) { + Messages.log("Arg " + arg); + } + Messages.log("Bad code: " + badCode); + } String result = null; switch (iprob.getID()) { - case IProblem.ParsingError: - if (args.length > 0) { - result = Language.interpolate("editor.status.error_on", args[0]); - } - break; - - case IProblem.ParsingErrorDeleteToken: - if (args.length > 0) { - result = Language.interpolate("editor.status.error_on", args[0]); - } - break; + case IProblem.ParsingError: + if (args.length > 0) { + result = Language.interpolate("editor.status.error_on", args[0]); + } + break; - case IProblem.ParsingErrorInsertToComplete: - if (args.length > 0) { - if (args[0].length() == 1) { - result = getErrorMessageForBracket(args[0].charAt(0)); + case IProblem.ParsingErrorDeleteToken: + if (args.length > 0) { + if (args[0].equalsIgnoreCase("Invalid Character")) { + result = getErrorMessageForCurlyQuote(badCode); + } + } + break; - } else { - if (args[0].equals("AssignmentOperator Expression")) { - result = Language.interpolate("editor.status.missing.add", "="); + case IProblem.ParsingErrorDeleteTokens: + result = getErrorMessageForCurlyQuote(badCode); + if (result == null) { + result = Language.interpolate("editor.status.error_on", args[0]); + } + break; - } else if (args[0].equalsIgnoreCase(") Statement")) { + case IProblem.ParsingErrorInsertToComplete: + if (args.length > 0) { + if (args[0].length() == 1) { result = getErrorMessageForBracket(args[0].charAt(0)); } else { - result = Language.interpolate("editor.status.error_on", args[0]); + if (args[0].equals("AssignmentOperator Expression")) { + result = Language.interpolate("editor.status.missing.add", "="); + + } else if (args[0].equalsIgnoreCase(") Statement")) { + result = getErrorMessageForBracket(args[0].charAt(0)); + + } else { + result = Language.interpolate("editor.status.error_on", args[0]); + } } } - } - break; + break; - case IProblem.ParsingErrorInvalidToken: - if (args.length > 0) { - if (args[1].equals("VariableDeclaratorId")) { + case IProblem.ParsingErrorInvalidToken: + if (args.length > 0) { if (args[0].equals("int")) { - result = Language.text ("editor.status.reserved_words"); - } else { + if (args[1].equals("VariableDeclaratorId")) { + result = Language.text("editor.status.reserved_words"); + } else { + result = Language.interpolate("editor.status.error_on", args[0]); + } + } else if (args[0].equalsIgnoreCase("Invalid Character")) { + result = getErrorMessageForCurlyQuote(badCode); + } + if (result == null) { result = Language.interpolate("editor.status.error_on", args[0]); } - } else { - result = Language.interpolate("editor.status.error_on", args[0]); } - } - break; + break; - case IProblem.ParsingErrorInsertTokenAfter: - if (args.length > 0) { - if (args[1].length() == 1) { - result = getErrorMessageForBracket(args[1].charAt(0)); - } - else { - // https://github.com/processing/processing/issues/3104 - if (args[1].equalsIgnoreCase("Statement")) { - result = Language.interpolate("editor.status.error_on", args[0]); + case IProblem.ParsingErrorInsertTokenAfter: + if (args.length > 0) { + if (args[1].length() == 1) { + result = getErrorMessageForBracket(args[1].charAt(0)); } else { - result = - Language.interpolate("editor.status.error_on", args[0]) + " " + - Language.interpolate("editor.status.missing.add", args[1]); + // https://github.com/processing/processing/issues/3104 + if (args[1].equalsIgnoreCase("Statement")) { + result = Language.interpolate("editor.status.error_on", args[0]); + } else { + result = + Language.interpolate("editor.status.error_on", args[0]) + " " + + Language.interpolate("editor.status.missing.add", args[1]); + } } } - } - break; - - case IProblem.UndefinedConstructor: - if (args.length == 2) { - String constructorName = args[0]; - // For messages such as "contructor sketch_name.ClassXYZ() is undefined", change - // constructor name to "ClassXYZ()". See #3434 - if (constructorName.contains(".")) { - // arg[0] contains sketch name twice: sketch_150705a.sketch_150705a.Thing - constructorName = constructorName.substring(constructorName.indexOf('.') + 1); - constructorName = constructorName.substring(constructorName.indexOf('.') + 1); + break; + + case IProblem.ParsingErrorReplaceTokens: + result = getErrorMessageForCurlyQuote(badCode); + + case IProblem.UndefinedConstructor: + if (args.length == 2) { + String constructorName = args[0]; + // For messages such as "contructor sketch_name.ClassXYZ() is undefined", change + // constructor name to "ClassXYZ()". See #3434 + if (constructorName.contains(".")) { + // arg[0] contains sketch name twice: sketch_150705a.sketch_150705a.Thing + constructorName = constructorName.substring(constructorName.indexOf('.') + 1); + constructorName = constructorName.substring(constructorName.indexOf('.') + 1); + } + String constructorArgs = removePackagePrefixes(args[args.length - 1]); + result = Language.interpolate("editor.status.undefined_constructor", constructorName, constructorArgs); } - String constructorArgs = removePackagePrefixes(args[args.length - 1]); - result = Language.interpolate("editor.status.undefined_constructor", constructorName, constructorArgs); - } - break; + break; - case IProblem.UndefinedMethod: - if (args.length > 2) { - String methodName = args[args.length - 2]; - String methodArgs = removePackagePrefixes(args[args.length - 1]); - result = Language.interpolate("editor.status.undefined_method", methodName, methodArgs); - } - break; - - case IProblem.ParameterMismatch: - if (args.length > 3) { - // 2nd arg is method name, 3rd arg is correct param list - if (args[2].trim().length() == 0) { - // the case where no params are needed. - result = Language.interpolate("editor.status.empty_param", args[1]); - - } else { - result = Language.interpolate("editor.status.wrong_param", - args[1], args[1], removePackagePrefixes(args[2])); + case IProblem.UndefinedMethod: + if (args.length > 2) { + String methodName = args[args.length - 2]; + String methodArgs = removePackagePrefixes(args[args.length - 1]); + result = Language.interpolate("editor.status.undefined_method", methodName, methodArgs); + } + break; + + case IProblem.ParameterMismatch: + if (args.length > 3) { + // 2nd arg is method name, 3rd arg is correct param list + if (args[2].trim().length() == 0) { + // the case where no params are needed. + result = Language.interpolate("editor.status.empty_param", args[1]); + + } else { + result = Language.interpolate("editor.status.wrong_param", + args[1], args[1], removePackagePrefixes(args[2])); // String method = q(args[1]); // String methodDef = " \"" + args[1] + "(" + getSimpleName(args[2]) + ")\""; // result = result.replace("method", method); // result += methodDef; + } } - } - break; + break; - case IProblem.UndefinedField: - if (args.length > 0) { - result = Language.interpolate("editor.status.undef_global_var", args[0]); - } - break; + case IProblem.UndefinedField: + if (args.length > 0) { + result = Language.interpolate("editor.status.undef_global_var", args[0]); + } + break; - case IProblem.UndefinedType: - if (args.length > 0) { - result = Language.interpolate("editor.status.undef_class", args[0]); - } - break; + case IProblem.UndefinedType: + if (args.length > 0) { + result = Language.interpolate("editor.status.undef_class", args[0]); + } + break; - case IProblem.UnresolvedVariable: - if (args.length > 0) { - result = Language.interpolate("editor.status.undef_var", args[0]); - } - break; + case IProblem.UnresolvedVariable: + if (args.length > 0) { + result = Language.interpolate("editor.status.undef_var", args[0]); + } + break; - case IProblem.UndefinedName: - if (args.length > 0) { - result = Language.interpolate("editor.status.undef_name", args[0]); - } - break; + case IProblem.UndefinedName: + if (args.length > 0) { + result = Language.interpolate("editor.status.undef_name", args[0]); + } + break; - case IProblem.TypeMismatch: - if (args.length > 1) { - result = Language.interpolate("editor.status.type_mismatch", args[0], args[1]); + case IProblem.UnterminatedString: + if (badCode.contains("“") || badCode.contains("”")) { + result = Language.interpolate("editor.status.unterm_string_curly", + badCode.replaceAll("[^“”]", "")); + } + break; + + case IProblem.TypeMismatch: + if (args.length > 1) { + result = Language.interpolate("editor.status.type_mismatch", args[0], args[1]); // result = result.replace("typeA", q(args[0])); // result = result.replace("typeB", q(args[1])); - } - break; + } + break; - case IProblem.LocalVariableIsNeverUsed: - if (args.length > 0) { - result = Language.interpolate("editor.status.unused_variable", args[0]); - } - break; + case IProblem.LocalVariableIsNeverUsed: + if (args.length > 0) { + result = Language.interpolate("editor.status.unused_variable", args[0]); + } + break; - case IProblem.UninitializedLocalVariable: - if (args.length > 0) { - result = Language.interpolate("editor.status.uninitialized_variable", args[0]); - } - break; + case IProblem.UninitializedLocalVariable: + if (args.length > 0) { + result = Language.interpolate("editor.status.uninitialized_variable", args[0]); + } + break; - case IProblem.AssignmentHasNoEffect: - if (args.length > 0) { - result = Language.interpolate("editor.status.no_effect_assignment", args[0]); - } - break; + case IProblem.AssignmentHasNoEffect: + if (args.length > 0) { + result = Language.interpolate("editor.status.no_effect_assignment", args[0]); + } + break; + + case IProblem.HidingEnclosingType: + if (args.length > 0) { + result = Language.interpolate("editor.status.hiding_enclosing_type", args[0]); + } + break; + } - case IProblem.HidingEnclosingType: - if (args.length > 0) { - result = Language.interpolate("editor.status.hiding_enclosing_type", args[0]); + if (result == null) { + String message = iprob.getMessage(); + if (message != null) { + // Remove all instances of token + // "Syntax error on token 'blah', delete this token" + Matcher matcher = tokenRegExp.matcher(message); + message = matcher.replaceAll(""); + result = message; } } - //log("Simplified Error Msg: " + result); - return (result == null) ? problem.getMessage() : result; + if (DEBUG) { + Messages.log("Simplified Error Msg: " + result); + } + + return result; } @@ -308,6 +347,20 @@ static private String getErrorMessageForBracket(char c) { } + /** + * @param badCode The code which may contain curly quotes + * @return Friendly error message if there is a curly quote in badCode, + * null otherwise. + */ + static private String getErrorMessageForCurlyQuote(String badCode) { + if (badCode.contains("‘") || badCode.contains("’") || + badCode.contains("“") || badCode.contains("”")) { + return Language.interpolate("editor.status.bad_curly_quote", + badCode.replaceAll("[^‘’“”]", "")); + } else return null; + } + + // static private final String q(Object quotable) { // return "\"" + quotable + "\""; // } diff --git a/java/src/processing/mode/java/pdex/InspectMode.java b/java/src/processing/mode/java/pdex/InspectMode.java new file mode 100644 index 0000000000..6624f6866d --- /dev/null +++ b/java/src/processing/mode/java/pdex/InspectMode.java @@ -0,0 +1,200 @@ +package processing.mode.java.pdex; + +import java.awt.EventQueue; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.util.function.Predicate; + +import javax.swing.JMenuItem; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclaration; + +import processing.app.Language; +import processing.app.Messages; +import processing.app.Platform; +import processing.mode.java.JavaEditor; +import processing.mode.java.JavaMode; +import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; + +import static processing.mode.java.pdex.ASTUtils.getSimpleNameAt; +import static processing.mode.java.pdex.ASTUtils.resolveBinding; + + +class InspectMode { + final JavaEditor editor; + final PreprocessingService pps; + final ShowUsage usage; + + boolean inspectModeEnabled; + + boolean isMouse1Down; + boolean isMouse2Down; + boolean isHotkeyDown; + + Predicate mouseEventHotkeyTest = Platform.isMacOS() ? + InputEvent::isMetaDown : InputEvent::isControlDown; + Predicate keyEventHotkeyTest = Platform.isMacOS() ? + e -> e.getKeyCode() == KeyEvent.VK_META : + e -> e.getKeyCode() == KeyEvent.VK_CONTROL; + + + InspectMode(JavaEditor editor, PreprocessingService pps, ShowUsage usage) { + this.editor = editor; + this.pps = pps; + this.usage = usage; + + // Add listeners + + JMenuItem showUsageItem = new JMenuItem(Language.text("editor.popup.jump_to_declaration")); + showUsageItem.addActionListener(e -> handleInspect()); + editor.getTextArea().getRightClickPopup().add(showUsageItem); + + editor.getJavaTextArea().getPainter().addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + isMouse1Down = isMouse1Down || (e.getButton() == MouseEvent.BUTTON1); + isMouse2Down = isMouse2Down || (e.getButton() == MouseEvent.BUTTON2); + } + + @Override + public void mouseReleased(MouseEvent e) { + boolean releasingMouse1 = e.getButton() == MouseEvent.BUTTON1; + boolean releasingMouse2 = e.getButton() == MouseEvent.BUTTON2; + if (JavaMode.inspectModeHotkeyEnabled && inspectModeEnabled && + isMouse1Down && releasingMouse1) { + handleInspect(e); + } else if (!inspectModeEnabled && isMouse2Down && releasingMouse2) { + handleInspect(e); + } + isMouse1Down = isMouse1Down && !releasingMouse1; + isMouse2Down = isMouse2Down && !releasingMouse2; + } + }); + + editor.getJavaTextArea().getPainter().addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if (editor.isSelectionActive()) { + // Mouse was dragged too much, disable + inspectModeEnabled = false; + // Cancel possible mouse 2 press + isMouse2Down = false; + } + } + + @Override + public void mouseMoved(MouseEvent e) { + isMouse1Down = false; + isMouse2Down = false; + isHotkeyDown = mouseEventHotkeyTest.test(e); + inspectModeEnabled = isHotkeyDown; + } + }); + + editor.getJavaTextArea().addMouseWheelListener(new MouseAdapter() { + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + // Editor was scrolled while mouse 1 was pressed, disable + if (isMouse1Down) inspectModeEnabled = false; + } + }); + + editor.getJavaTextArea().addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + isHotkeyDown = isHotkeyDown || keyEventHotkeyTest.test(e); + // Enable if hotkey was just pressed and mouse 1 is not down + inspectModeEnabled = inspectModeEnabled || (!isMouse1Down && isHotkeyDown); + } + + @Override + public void keyReleased(KeyEvent e) { + isHotkeyDown = isHotkeyDown && !keyEventHotkeyTest.test(e); + // Disable if hotkey was just released + inspectModeEnabled = inspectModeEnabled && isHotkeyDown; + } + }); + } + + + void handleInspect() { + int off = editor.getSelectionStart(); + int tabIndex = editor.getSketch().getCurrentCodeIndex(); + + pps.whenDoneBlocking(ps -> handleInspect(ps, tabIndex, off)); + } + + + // Thread: EDT + void handleInspect(MouseEvent evt) { + int off = editor.getJavaTextArea().xyToOffset(evt.getX(), evt.getY()); + if (off < 0) return; + int tabIndex = editor.getSketch().getCurrentCodeIndex(); + + pps.whenDoneBlocking(ps -> handleInspect(ps, tabIndex, off)); + } + + + // Thread: worker + private void handleInspect(PreprocessedSketch ps, int tabIndex, int offset) { + ASTNode root = ps.compilationUnit; + int javaOffset = ps.tabOffsetToJavaOffset(tabIndex, offset); + + SimpleName simpleName = getSimpleNameAt(root, javaOffset, javaOffset); + + if (simpleName == null) { + Messages.log("no simple name found at click location"); + return; + } + + IBinding binding = resolveBinding(simpleName); + if (binding == null) { + Messages.log("binding not resolved"); + return; + } + + String key = binding.getKey(); + ASTNode decl = ps.compilationUnit.findDeclaringNode(key); + if (decl == null) { + Messages.log("decl not found, showing usage instead"); + usage.findUsageAndUpdateTree(ps, binding); + return; + } + + SimpleName declName = null; + switch (binding.getKind()) { + case IBinding.TYPE: declName = ((TypeDeclaration) decl).getName(); break; + case IBinding.METHOD: declName = ((MethodDeclaration) decl).getName(); break; + case IBinding.VARIABLE: declName = ((VariableDeclaration) decl).getName(); break; + } + if (declName == null) { + Messages.log("decl name not found " + decl); + return; + } + + if (declName.equals(simpleName)) { + usage.findUsageAndUpdateTree(ps, binding); + } else { + Messages.log("found declaration, offset " + decl.getStartPosition() + ", name: " + declName); + SketchInterval si = ps.mapJavaToSketch(declName); + if (!ps.inRange(si)) return; + EventQueue.invokeLater(() -> { + editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset); + }); + } + } + + + void dispose() { + // Nothing to do + } +} \ No newline at end of file diff --git a/java/src/processing/mode/java/pdex/JavaProblem.java b/java/src/processing/mode/java/pdex/JavaProblem.java index bb4da88987..b8ef76c0ae 100644 --- a/java/src/processing/mode/java/pdex/JavaProblem.java +++ b/java/src/processing/mode/java/pdex/JavaProblem.java @@ -20,9 +20,6 @@ package processing.mode.java.pdex; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.eclipse.jdt.core.compiler.IProblem; import processing.app.Problem; @@ -33,10 +30,6 @@ * according to its tab, including the original IProblem object */ public class JavaProblem implements Problem { - /** - * The IProblem which is being wrapped - */ - private IProblem iProblem; /** * The tab number to which the error belongs to */ @@ -67,25 +60,30 @@ public class JavaProblem implements Problem { public static final int ERROR = 1, WARNING = 2; + public JavaProblem(String message, int type, int tabIndex, int lineNumber) { + this.message = message; + this.type = type; + this.tabIndex = tabIndex; + this.lineNumber = lineNumber; + } + /** * * @param iProblem - The IProblem which is being wrapped * @param tabIndex - The tab number to which the error belongs to * @param lineNumber - Line number(pde code) of the error + * @param badCode - The code iProblem refers to. */ - public JavaProblem(IProblem iProblem, int tabIndex, int lineNumber) { - this.iProblem = iProblem; + public static JavaProblem fromIProblem(IProblem iProblem, + int tabIndex, int lineNumber, String badCode) { + int type = 0; if(iProblem.isError()) { type = ERROR; - } - else if(iProblem.isWarning()) { + } else if (iProblem.isWarning()) { type = WARNING; } - this.tabIndex = tabIndex; - this.lineNumber = lineNumber; - this.message = process(iProblem); - this.message = ErrorMessageSimplifier.getSimplifiedErrorMessage(this); - //ErrorMessageSimplifier.getSimplifiedErrorMessage(this); + String message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem, badCode); + return new JavaProblem(message, type, tabIndex, lineNumber); } public void setPDEOffsets(int startOffset, int stopOffset){ @@ -93,62 +91,41 @@ public void setPDEOffsets(int startOffset, int stopOffset){ this.stopOffset = stopOffset; } + @Override public int getStartOffset() { return startOffset; } + @Override public int getStopOffset() { return stopOffset; } - public String toString() { - return new String("TAB " + tabIndex + ",LN " + lineNumber + "LN START OFF: " - + startOffset + ",LN STOP OFF: " + stopOffset + ",PROB: " - + message); - } - + @Override public boolean isError() { return type == ERROR; } + @Override public boolean isWarning() { return type == WARNING; } + @Override public String getMessage() { return message; } - public IProblem getIProblem() { - return iProblem; - } - + @Override public int getTabIndex() { return tabIndex; } + @Override public int getLineNumber() { return lineNumber; } - /** - * Remember to subtract a -1 to line number because in compile check code an - * extra package statement is added, so all line numbers are increased by 1 - * - * @return - */ - public int getSourceLineNumber() { - return iProblem.getSourceLineNumber(); - } - - public void setType(int ProblemType){ - if(ProblemType == ERROR) - type = ERROR; - else if(ProblemType == WARNING) - type = WARNING; - else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); - } - public String[] getImportSuggestions() { return importSuggestions; } @@ -157,47 +134,11 @@ public void setImportSuggestions(String[] a) { importSuggestions = a; } - private static final Pattern tokenRegExp = Pattern.compile("\\b token\\b"); - - public static String process(IProblem problem) { - return process(problem.getMessage()); - } - - /** - * Processes error messages and attempts to make them a bit more english like. - * Currently performs: - *
  • Remove all instances of token. "Syntax error on token 'blah', delete this token" - * becomes "Syntax error on 'blah', delete this" - * @param message - The message to be processed - * @return String - The processed message - */ - public static String process(String message) { - // Remove all instances of token - // "Syntax error on token 'blah', delete this token" - if(message == null) return null; - Matcher matcher = tokenRegExp.matcher(message); - message = matcher.replaceAll(""); - - return message; - } - - // Split camel case words into separate words. - // "VaraibleDeclaration" becomes "Variable Declaration" - // But sadly "PApplet" become "P Applet" and so on. - public static String splitCamelCaseWord(String word) { - String newWord = ""; - for (int i = 1; i < word.length(); i++) { - if (Character.isUpperCase(word.charAt(i))) { - // System.out.println(word.substring(0, i) + " " - // + word.substring(i)); - newWord += word.substring(0, i) + " "; - word = word.substring(i); - i = 1; - } - } - newWord += word; - // System.out.println(newWord); - return newWord.trim(); + @Override + public String toString() { + return "TAB " + tabIndex + ",LN " + lineNumber + "LN START OFF: " + + startOffset + ",LN STOP OFF: " + stopOffset + ",PROB: " + + message; } } diff --git a/java/src/processing/mode/java/pdex/PDEX.java b/java/src/processing/mode/java/pdex/PDEX.java index 6182faed36..2a6790a7d2 100644 --- a/java/src/processing/mode/java/pdex/PDEX.java +++ b/java/src/processing/mode/java/pdex/PDEX.java @@ -1,99 +1,22 @@ package processing.mode.java.pdex; -import com.google.classpath.ClassPath; -import com.google.classpath.RegExpResourceFilter; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.IBinding; -import org.eclipse.jdt.core.dom.IMethodBinding; -import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclaration; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.EventQueue; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Rectangle; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Deque; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.JTree; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; import javax.swing.text.Document; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeModel; -import processing.app.Language; -import processing.app.Messages; -import processing.app.Platform; -import processing.app.Problem; -import processing.app.Sketch; import processing.app.SketchCode; -import processing.app.syntax.SyntaxDocument; -import processing.app.ui.EditorStatus; -import processing.app.ui.Toolkit; import processing.mode.java.JavaEditor; -import processing.mode.java.JavaMode; -import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; -import static processing.mode.java.pdex.ASTUtils.*; public class PDEX { - - private static final boolean SHOW_DEBUG_TREE = false; + static private final boolean SHOW_DEBUG_TREE = false; private boolean enabled = true; private ErrorChecker errorChecker; - private InspectMode inspectMode; - private ShowUsage showUsage; + private InspectMode inspect; + private ShowUsage usage; private Rename rename; private DebugTree debugTree; @@ -107,9 +30,10 @@ public PDEX(JavaEditor editor, PreprocessingService pps) { errorChecker = new ErrorChecker(editor, pps); - inspectMode = new InspectMode(editor, pps); - showUsage = new ShowUsage(editor, pps); - rename = new Rename(editor, pps); + usage = new ShowUsage(editor, pps); + inspect = new InspectMode(editor, pps, usage); + rename = new Rename(editor, pps, usage); + if (SHOW_DEBUG_TREE) { debugTree = new DebugTree(editor, pps); } @@ -128,7 +52,7 @@ public void addDocumentListener(Document doc) { } - protected final DocumentListener sketchChangedListener = new DocumentListener() { + final DocumentListener sketchChangedListener = new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { sketchChanged(); @@ -161,15 +85,15 @@ public void preferencesChanged() { public void hasJavaTabsChanged(boolean hasJavaTabs) { enabled = !hasJavaTabs; if (!enabled) { - showUsage.hide(); + usage.hide(); } } public void dispose() { - inspectMode.dispose(); + inspect.dispose(); errorChecker.dispose(); - showUsage.dispose(); + usage.dispose(); rename.dispose(); if (debugTree != null) { debugTree.dispose(); @@ -180,995 +104,4 @@ public void dispose() { public void documentChanged(Document newDoc) { addDocumentListener(newDoc); } - - - private class InspectMode { - - boolean inspectModeEnabled; - - boolean isMouse1Down; - boolean isMouse2Down; - boolean isHotkeyDown; - - Predicate mouseEventHotkeyTest = Platform.isMacOS() ? - InputEvent::isMetaDown : InputEvent::isControlDown; - Predicate keyEventHotkeyTest = Platform.isMacOS() ? - e -> e.getKeyCode() == KeyEvent.VK_META : - e -> e.getKeyCode() == KeyEvent.VK_CONTROL; - - JavaEditor editor; - PreprocessingService pps; - - InspectMode(JavaEditor editor, PreprocessingService pps) { - this.editor = editor; - this.pps = pps; - - // Add listeners - - editor.getJavaTextArea().getPainter().addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - isMouse1Down = isMouse1Down || (e.getButton() == MouseEvent.BUTTON1); - isMouse2Down = isMouse2Down || (e.getButton() == MouseEvent.BUTTON2); - } - - @Override - public void mouseReleased(MouseEvent e) { - boolean releasingMouse1 = e.getButton() == MouseEvent.BUTTON1; - boolean releasingMouse2 = e.getButton() == MouseEvent.BUTTON2; - if (JavaMode.inspectModeHotkeyEnabled && inspectModeEnabled && - isMouse1Down && releasingMouse1) { - handleInspect(e); - } else if (!inspectModeEnabled && isMouse2Down && releasingMouse2) { - handleInspect(e); - } - isMouse1Down = isMouse1Down && !releasingMouse1; - isMouse2Down = isMouse2Down && !releasingMouse2; - } - }); - - editor.getJavaTextArea().getPainter().addMouseMotionListener(new MouseAdapter() { - @Override - public void mouseDragged(MouseEvent e) { - if (editor.isSelectionActive()) { - // Mouse was dragged too much, disable - inspectModeEnabled = false; - // Cancel possible mouse 2 press - isMouse2Down = false; - } - } - - @Override - public void mouseMoved(MouseEvent e) { - isMouse1Down = false; - isMouse2Down = false; - isHotkeyDown = mouseEventHotkeyTest.test(e); - inspectModeEnabled = isHotkeyDown; - } - }); - - editor.getJavaTextArea().addMouseWheelListener(new MouseAdapter() { - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - // Editor was scrolled while mouse 1 was pressed, disable - if (isMouse1Down) inspectModeEnabled = false; - } - }); - - editor.getJavaTextArea().addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - isHotkeyDown = isHotkeyDown || keyEventHotkeyTest.test(e); - // Enable if hotkey was just pressed and mouse 1 is not down - inspectModeEnabled = inspectModeEnabled || (!isMouse1Down && isHotkeyDown); - } - - @Override - public void keyReleased(KeyEvent e) { - isHotkeyDown = isHotkeyDown && !keyEventHotkeyTest.test(e); - // Disable if hotkey was just released - inspectModeEnabled = inspectModeEnabled && isHotkeyDown; - } - }); - - } - - - // Thread: EDT - void handleInspect(MouseEvent evt) { - int off = editor.getJavaTextArea().xyToOffset(evt.getX(), evt.getY()); - if (off < 0) return; - int tabIndex = editor.getSketch().getCurrentCodeIndex(); - - pps.whenDoneBlocking(ps -> handleInspect(ps, tabIndex, off)); - } - - - // Thread: worker - private void handleInspect(PreprocessedSketch ps, int tabIndex, int offset) { - ASTNode root = ps.compilationUnit; - int javaOffset = ps.tabOffsetToJavaOffset(tabIndex, offset); - - SimpleName simpleName = getSimpleNameAt(root, javaOffset, javaOffset); - - if (simpleName == null) { - Messages.log("no simple name found at click location"); - return; - } - - IBinding binding = resolveBinding(simpleName); - if (binding == null) { - Messages.log("binding not resolved"); - return; - } - - String key = binding.getKey(); - ASTNode decl = ps.compilationUnit.findDeclaringNode(key); - if (decl == null) { - Messages.log("decl not found, showing usage instead"); - showUsage.findUsageAndUpdateTree(ps, binding); - return; - } - - SimpleName declName = null; - switch (binding.getKind()) { - case IBinding.TYPE: declName = ((TypeDeclaration) decl).getName(); break; - case IBinding.METHOD: declName = ((MethodDeclaration) decl).getName(); break; - case IBinding.VARIABLE: declName = ((VariableDeclaration) decl).getName(); break; - } - if (declName == null) { - Messages.log("decl name not found " + decl); - return; - } - - if (declName.equals(simpleName)) { - showUsage.findUsageAndUpdateTree(ps, binding); - } else { - Messages.log("found declaration, offset " + decl.getStartPosition() + ", name: " + declName); - SketchInterval si = ps.mapJavaToSketch(declName); - if (!ps.inRange(si)) return; - EventQueue.invokeLater(() -> { - editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset); - }); - } - } - - - void dispose() { - // Nothing to do - } - - } - - - - private static class ShowUsage { - - final JDialog window; - final JTree tree; - - final JavaEditor editor; - final PreprocessingService pps; - - final Consumer reloadListener; - - IBinding binding; - - - ShowUsage(JavaEditor editor, PreprocessingService pps) { - this.editor = editor; - this.pps = pps; - - // Add show usage option - JMenuItem showUsageItem = new JMenuItem(Language.text("editor.popup.show_usage")); - showUsageItem.addActionListener(e -> handleShowUsage()); - editor.getTextArea().getRightClickPopup().add(showUsageItem); - - reloadListener = this::reloadShowUsage; - - { // Show Usage window - window = new JDialog(editor); - window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - window.setAutoRequestFocus(false); - window.addComponentListener(new ComponentAdapter() { - @Override - public void componentHidden(ComponentEvent e) { - binding = null; - tree.setModel(null); - pps.unregisterListener(reloadListener); - } - - @Override - public void componentShown(ComponentEvent e) { - pps.registerListener(reloadListener); - } - }); - window.setSize(300, 400); - window.setFocusableWindowState(false); - Toolkit.setIcon(window); - JScrollPane sp2 = new JScrollPane(); - tree = new JTree(); - DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer(); - renderer.setLeafIcon(null); - renderer.setClosedIcon(null); - renderer.setOpenIcon(null); - renderer.setBackgroundSelectionColor(new Color(228, 248, 246)); - renderer.setBorderSelectionColor(new Color(0, 0, 0, 0)); - renderer.setTextSelectionColor(Color.BLACK); - sp2.setViewportView(tree); - window.add(sp2); - } - - tree.addTreeSelectionListener(e -> { - if (tree.getLastSelectedPathComponent() == null) { - return; - } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) tree - .getLastSelectedPathComponent(); - - if (tnode.getUserObject() instanceof ShowUsageTreeNode) { - ShowUsageTreeNode node = (ShowUsageTreeNode) tnode.getUserObject(); - editor.highlight(node.tabIndex, node.startTabOffset, node.stopTabOffset); - } - }); - - } - - - // Thread: EDT - void handleShowUsage() { - int startOffset = editor.getSelectionStart(); - int stopOffset = editor.getSelectionStop(); - int tabIndex = editor.getSketch().getCurrentCodeIndex(); - - pps.whenDoneBlocking(ps -> handleShowUsage(ps, tabIndex, startOffset, stopOffset)); - } - - - // Thread: worker - void handleShowUsage(PreprocessedSketch ps, int tabIndex, - int startTabOffset, int stopTabOffset) { - // Map offsets - int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset); - int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset); - - // Find the node - SimpleName name = ASTUtils.getSimpleNameAt(ps.compilationUnit, startJavaOffset, stopJavaOffset); - if (name == null) { - editor.statusMessage("Cannot find any name under cursor", EditorStatus.NOTICE); - return; - } - - // Find binding - IBinding binding = ASTUtils.resolveBinding(name); - if (binding == null) { - editor.statusMessage("Cannot find usages, try to fix errors in your code first", - EditorStatus.NOTICE); - return; - } - - findUsageAndUpdateTree(ps, binding); - } - - - // Thread: worker - void findUsageAndUpdateTree(PreprocessedSketch ps, IBinding binding) { - - this.binding = binding; - - // Get label - String bindingType = ""; - switch (binding.getKind()) { - case IBinding.METHOD: - IMethodBinding method = (IMethodBinding) binding; - if (method.isConstructor()) bindingType = "Constructor"; - else bindingType = "Method"; - break; - case IBinding.TYPE: - bindingType = "Type"; - break; - case IBinding.VARIABLE: - IVariableBinding variable = (IVariableBinding) binding; - if (variable.isField()) bindingType = "Field"; - else if (variable.isParameter()) bindingType = "Parameter"; - else if (variable.isEnumConstant()) bindingType = "Enum constant"; - else bindingType = "Local variable"; - break; - } - - // Find usages, map to tree nodes, add to root node - String bindingKey = binding.getKey(); - List intervals = - findAllOccurrences(ps.compilationUnit, bindingKey).stream() - .map(ps::mapJavaToSketch) - // remove occurrences which fall into generated header - .filter(ps::inRange) - // remove empty intervals (happens when occurence was inserted) - .filter(in -> in.startPdeOffset < in.stopPdeOffset) - .collect(Collectors.toList()); - - int usageCount = intervals.size(); - - // Get element name from PDE code if possible, otherwise use one from Java - String elementName = intervals.stream() - .findAny() - .map(si -> ps.pdeCode.substring(si.startPdeOffset, si.stopPdeOffset)) - .orElseGet(binding::getName); - - // Create root node - DefaultMutableTreeNode rootNode = - new DefaultMutableTreeNode(bindingType + ": " + elementName); - - intervals.stream() - // Convert to TreeNodes - .map(in -> ShowUsageTreeNode.fromSketchInterval(ps, in)) - // Group by tab index - .collect(Collectors.groupingBy(node -> node.tabIndex)) - // Stream Map Entries of (tab index) <-> (List) - .entrySet().stream() - // Sort by tab index - .sorted(Comparator.comparing(Map.Entry::getKey)) - .map(entry -> { - Integer tabIndex = entry.getKey(); - List nodes = entry.getValue(); - - int count = nodes.size(); - String usageLabel = count == 1 ? "usage" : "usages"; - - // Create new DefaultMutableTreeNode for this tab - String tabLabel = "" + - ps.sketch.getCode(tabIndex).getPrettyName() + - " " + count + " " + usageLabel + ""; - DefaultMutableTreeNode tabNode = new DefaultMutableTreeNode(tabLabel); - - // Stream nodes belonging to this tab - nodes.stream() - // Convert TreeNodes to DefaultMutableTreeNodes - .map(DefaultMutableTreeNode::new) - // Add all as children of tab node - .forEach(tabNode::add); - return tabNode; - }) - // Add all tab nodes as children of root node - .forEach(rootNode::add); - - TreeModel treeModel = new DefaultTreeModel(rootNode); - - // Update tree - EventQueue.invokeLater(() -> { - tree.setModel(treeModel); - - // Expand all nodes - for (int i = 0; i < tree.getRowCount(); i++) { - tree.expandRow(i); - } - - tree.setRootVisible(true); - - if (!window.isVisible()) { - window.setVisible(true); - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice defaultScreen = ge.getDefaultScreenDevice(); - Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds(); - int maxX = (int) rect.getMaxX() - window.getWidth(); - int x = Math.min(editor.getX() + editor.getWidth(), maxX); - int y = (x == maxX) ? 10 : editor.getY(); - window.setLocation(x, y); - } - window.toFront(); - window.setTitle("Usage of \"" + elementName + "\" : " + - usageCount + " time(s)"); - }); - } - - - // Thread: worker - void reloadShowUsage(PreprocessedSketch ps) { - if (binding != null) { - findUsageAndUpdateTree(ps, binding); - } - } - - - void hide() { - window.setVisible(false); - } - - - void dispose() { - if (window != null) { - window.dispose(); - } - } - - } - - - private static class ShowUsageTreeNode { - - final int tabIndex; - final int startTabOffset; - final int stopTabOffset; - - final String text; - - - ShowUsageTreeNode(int tabIndex, int startTabOffset, int stopTabOffset, String text) { - this.tabIndex = tabIndex; - this.startTabOffset = startTabOffset; - this.stopTabOffset = stopTabOffset; - this.text = text; - } - - - static ShowUsageTreeNode fromSketchInterval(PreprocessedSketch ps, SketchInterval in) { - int lineStartPdeOffset = ps.pdeCode.lastIndexOf('\n', in.startPdeOffset) + 1; - int lineStopPdeOffset = ps.pdeCode.indexOf('\n', in.stopPdeOffset); - if (lineStopPdeOffset == -1) lineStopPdeOffset = ps.pdeCode.length(); - - int highlightStartOffset = in.startPdeOffset - lineStartPdeOffset; - int highlightStopOffset = in.stopPdeOffset - lineStartPdeOffset; - - int tabLine = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); - - // TODO: what a mess - String line = ps.pdeCode.substring(lineStartPdeOffset, lineStopPdeOffset); - String pre = line.substring(0, highlightStartOffset) - .replace("&", "&").replace(">", ">").replace("<", "<"); - String highlight = line.substring(highlightStartOffset, highlightStopOffset) - .replace("&", "&").replace(">", ">").replace("<", "<"); - String post = line.substring(highlightStopOffset) - .replace("&", "&").replace(">", ">").replace("<", "<"); - line = pre + "" + highlight + "" + post; - line = line.trim(); - - - String text = "" + - (tabLine + 1) + " " + line + ""; - - return new ShowUsageTreeNode(in.tabIndex, in.startTabOffset, in.stopTabOffset, text); - } - - @Override - public String toString() { - return text; - } - } - - - - private class Rename { - - final JDialog window; - final JTextField textField; - final JLabel oldNameLabel; - - final JavaEditor editor; - final PreprocessingService pps; - - IBinding binding; - PreprocessedSketch ps; - - - Rename(JavaEditor editor, PreprocessingService pps) { - this.editor = editor; - this.pps = pps; - - // Add rename option - JMenuItem renameItem = new JMenuItem(Language.text("editor.popup.rename")); - renameItem.addActionListener(e -> handleRename()); - editor.getTextArea().getRightClickPopup().add(renameItem); - - - window = new JDialog(editor); - window.setTitle("Enter new name:"); - window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - window.setModal(true); - window.setResizable(false); - window.addComponentListener(new ComponentAdapter() { - @Override - public void componentHidden(ComponentEvent e) { - binding = null; - ps = null; - } - }); - window.setSize(250, 130); - window.setLayout(new BoxLayout(window.getContentPane(), BoxLayout.Y_AXIS)); - Toolkit.setIcon(window); - - { // Top panel - - // Text field - textField = new JTextField(); - textField.setPreferredSize(new Dimension(150, 60)); - - // Old name label - oldNameLabel = new JLabel(); - oldNameLabel.setText("Old Name: "); - - // Top panel - JPanel panelTop = new JPanel(); - panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS)); - panelTop.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - panelTop.add(textField); - panelTop.add(Box.createRigidArea(new Dimension(0, 10))); - panelTop.add(oldNameLabel); - window.add(panelTop); - } - - { // Bottom panel - JButton showUsageButton = new JButton("Show Usage"); - showUsageButton.addActionListener(e -> { - showUsage.findUsageAndUpdateTree(ps, binding); - window.setVisible(false); - }); - - JButton renameButton = new JButton("Rename"); - renameButton.addActionListener(e -> { - if (textField.getText().length() == 0) { - return; - } - String newName = textField.getText().trim(); - boolean isNewNameValid = newName.length() >= 1 && - newName.chars().limit(1).allMatch(Character::isUnicodeIdentifierStart) && - newName.chars().skip(1).allMatch(Character::isUnicodeIdentifierPart); - if (!isNewNameValid) { - JOptionPane.showMessageDialog(new JFrame(), "'" + newName - + "' isn't a valid name.", "Uh oh..", JOptionPane.PLAIN_MESSAGE); - } else { - rename(ps, binding, newName); - window.setVisible(false); - } - }); - - JPanel panelBottom = new JPanel(); - panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS)); - panelBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - panelBottom.add(Box.createHorizontalGlue()); - panelBottom.add(showUsageButton); - panelBottom.add(Box.createRigidArea(new Dimension(15, 0))); - panelBottom.add(renameButton); - window.add(panelBottom); - } - - window.setMinimumSize(window.getSize()); - } - - - // Thread: EDT - void handleRename() { - int startOffset = editor.getSelectionStart(); - int stopOffset = editor.getSelectionStop(); - int tabIndex = editor.getSketch().getCurrentCodeIndex(); - - pps.whenDoneBlocking(ps -> handleRename(ps, tabIndex, startOffset, stopOffset)); - } - - - // Thread: worker - void handleRename(PreprocessedSketch ps, int tabIndex, int startTabOffset, int stopTabOffset) { - if (ps.hasSyntaxErrors) { - editor.statusMessage("Can't perform action until syntax errors are fixed", - EditorStatus.WARNING); - return; - } - - ASTNode root = ps.compilationUnit; - - // Map offsets - int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset); - int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset); - - // Find the node - SimpleName name = getSimpleNameAt(root, startJavaOffset, stopJavaOffset); - if (name == null) { - editor.statusMessage("Highlight the class/function/variable name first", - EditorStatus.NOTICE); - return; - } - - // Find binding - IBinding binding = resolveBinding(name); - if (binding == null) { - editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " + - "so it cannot be renamed", EditorStatus.ERROR); - return; - } - - ASTNode decl = ps.compilationUnit.findDeclaringNode(binding.getKey()); - if (decl == null) { - editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " + - "so it cannot be renamed", EditorStatus.ERROR); - return; - } - - // Display the rename dialog - EventQueue.invokeLater(() -> { - if (!window.isVisible()) { - this.ps = ps; - this.binding = binding; - oldNameLabel.setText("Current name: " + binding.getName()); - textField.setText(binding.getName()); - textField.requestFocus(); - textField.selectAll(); - int x = editor.getX() + (editor.getWidth() - window.getWidth()) / 2; - int y = editor.getY() + (editor.getHeight() - window.getHeight()) / 2; - window.setLocation(x, y); - window.setVisible(true); - window.toFront(); - } - }); - } - - - // Thread: EDT (we can't allow user to mess with sketch while renaming) - void rename(PreprocessedSketch ps, IBinding binding, String newName) { - CompilationUnit root = ps.compilationUnit; - - // Renaming constructor should rename class - if (binding.getKind() == IBinding.METHOD) { - IMethodBinding method = (IMethodBinding) binding; - if (method.isConstructor()) { - binding = method.getDeclaringClass(); - } - } - - ASTNode decl = root.findDeclaringNode(binding.getKey()); - if (decl == null) return; - - showUsage.hide(); - - List occurrences = new ArrayList<>(); - occurrences.addAll(findAllOccurrences(root, binding.getKey())); - - // Renaming class should rename all constructors - if (binding.getKind() == IBinding.TYPE) { - ITypeBinding type = (ITypeBinding) binding; - //type = type.getErasure(); - IMethodBinding[] methods = type.getDeclaredMethods(); - Arrays.stream(methods) - .filter(IMethodBinding::isConstructor) - .flatMap(c -> findAllOccurrences(root, c.getKey()).stream()) - .forEach(occurrences::add); - } - - Map> mappedNodes = occurrences.stream() - .map(ps::mapJavaToSketch) - .filter(ps::inRange) - .collect(Collectors.groupingBy(interval -> interval.tabIndex)); - - Sketch sketch = ps.sketch; - - editor.startCompoundEdit(); - - mappedNodes.entrySet().forEach(entry -> { - int tabIndex = entry.getKey(); - SketchCode sketchCode = sketch.getCode(tabIndex); - - SyntaxDocument document = (SyntaxDocument) sketchCode.getDocument(); - - List nodes = entry.getValue(); - nodes.stream() - // Replace from the end so all unprocess offsets stay valid - .sorted(Comparator.comparing((SketchInterval si) -> si.startTabOffset).reversed()) - .forEach(si -> { - // Make sure offsets are in bounds - int documentLength = document.getLength(); - if (si.startTabOffset >= 0 && si.startTabOffset <= documentLength && - si.stopTabOffset >= 0 && si.stopTabOffset <= documentLength) { - // Replace the code - int length = si.stopTabOffset - si.startTabOffset; - try { - document.remove(si.startTabOffset, length); - document.insertString(si.startTabOffset, newName, null); - } catch (BadLocationException e) { /* Whatever */ } - } - }); - - try { - sketchCode.setProgram(document.getText(0, document.getLength())); - } catch (BadLocationException e) { /* Whatever */ } - sketchCode.setModified(true); - }); - - editor.stopCompoundEdit(); - - editor.repaintHeader(); - - int currentTabIndex = sketch.getCurrentCodeIndex(); - final int currentOffset = editor.getCaretOffset(); - - int precedingIntervals = - (int) mappedNodes.getOrDefault(currentTabIndex, Collections.emptyList()) - .stream() - .filter(interval -> interval.stopTabOffset < currentOffset) - .count(); - int intervalLengthDiff = newName.length() - binding.getName().length(); - int offsetDiff = precedingIntervals * intervalLengthDiff; - - editor.getTextArea().setCaretPosition(currentOffset + offsetDiff); - - } - - - void dispose() { - if (window != null) { - window.dispose(); - } - } - - } - - - - private static class DebugTree { - - final JDialog window; - final JTree tree; - - final Consumer updateListener; - - - DebugTree(JavaEditor editor, PreprocessingService pps) { - updateListener = this::buildAndUpdateTree; - - window = new JDialog(editor); - - tree = new JTree() { - @Override - public String convertValueToText(Object value, boolean selected, - boolean expanded, boolean leaf, - int row, boolean hasFocus) { - if (value instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; - Object o = treeNode.getUserObject(); - if (o instanceof ASTNode) { - ASTNode node = (ASTNode) o; - return CompletionGenerator.getNodeAsString(node); - } - } - return super.convertValueToText(value, selected, expanded, leaf, row, hasFocus); - } - }; - window.addComponentListener(new ComponentAdapter() { - @Override - public void componentHidden(ComponentEvent e) { - pps.unregisterListener(updateListener); - tree.setModel(null); - } - }); - window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - window.setBounds(new Rectangle(680, 100, 460, 620)); - window.setTitle("AST View - " + editor.getSketch().getName()); - JScrollPane sp = new JScrollPane(); - sp.setViewportView(tree); - window.add(sp); - pps.whenDone(updateListener); - pps.registerListener(updateListener); - - - tree.addTreeSelectionListener(e -> { - if (tree.getLastSelectedPathComponent() == null) { - return; - } - DefaultMutableTreeNode tnode = - (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); - if (tnode.getUserObject() instanceof ASTNode) { - ASTNode node = (ASTNode) tnode.getUserObject(); - pps.whenDone(ps -> { - SketchInterval si = ps.mapJavaToSketch(node); - if (!ps.inRange(si)) return; - EventQueue.invokeLater(() -> { - editor.highlight(si.tabIndex, si.startTabOffset, si.stopTabOffset); - }); - }); - } - }); - } - - - void dispose() { - if (window != null) { - window.dispose(); - } - } - - - // Thread: worker - void buildAndUpdateTree(PreprocessedSketch ps) { - CompilationUnit cu = ps.compilationUnit; - if (cu.types().isEmpty()){ - Messages.loge("No Type found in CU"); - return; - } - - Deque treeNodeStack = new ArrayDeque<>(); - - ASTNode type0 = (ASTNode) cu.types().get(0); - type0.accept(new ASTVisitor() { - @Override - public boolean preVisit2(ASTNode node) { - treeNodeStack.push(new DefaultMutableTreeNode(node)); - return super.preVisit2(node); - } - - @Override - public void postVisit(ASTNode node) { - if (treeNodeStack.size() > 1) { - DefaultMutableTreeNode treeNode = treeNodeStack.pop(); - treeNodeStack.peek().add(treeNode); - } - } - }); - - DefaultMutableTreeNode codeTree = treeNodeStack.pop(); - - EventQueue.invokeLater(() -> { - if (tree.hasFocus() || window.hasFocus()) { - return; - } - tree.setModel(new DefaultTreeModel(codeTree)); - ((DefaultTreeModel) tree.getModel()).reload(); - tree.validate(); - if (!window.isVisible()) { - window.setVisible(true); - } - }); - } - - } - - - - private static class ErrorChecker { - - // Delay delivering error check result after last sketch change #2677 - private final static long DELAY_BEFORE_UPDATE = 650; - - private ScheduledExecutorService scheduler; - private volatile ScheduledFuture scheduledUiUpdate = null; - private volatile long nextUiUpdate = 0; - private volatile boolean enabled = true; - - private final Consumer errorHandlerListener = this::handleSketchProblems; - - private JavaEditor editor; - private PreprocessingService pps; - - - public ErrorChecker(JavaEditor editor, PreprocessingService pps) { - this.editor = editor; - this.pps = pps; - scheduler = Executors.newSingleThreadScheduledExecutor(); - this.enabled = JavaMode.errorCheckEnabled; - if (enabled) { - pps.registerListener(errorHandlerListener); - } - } - - - public void notifySketchChanged() { - nextUiUpdate = System.currentTimeMillis() + DELAY_BEFORE_UPDATE; - } - - - public void preferencesChanged() { - if (enabled != JavaMode.errorCheckEnabled) { - enabled = JavaMode.errorCheckEnabled; - if (enabled) { - pps.registerListener(errorHandlerListener); - } else { - pps.unregisterListener(errorHandlerListener); - editor.setProblemList(Collections.emptyList()); - nextUiUpdate = 0; - } - } - } - - - public void dispose() { - if (scheduler != null) { - scheduler.shutdownNow(); - } - } - - - private void handleSketchProblems(PreprocessedSketch ps) { - // Process problems - IProblem[] iproblems = ps.compilationUnit.getProblems(); - final List problems = Arrays.stream(iproblems) - // Filter Warnings if they are not enabled - .filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled)) - // Hide a useless error which is produced when a line ends with - // an identifier without a semicolon. "Missing a semicolon" is - // also produced and is preferred over this one. - // (Syntax error, insert ":: IdentifierOrNew" to complete Expression) - // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780 - .filter(iproblem -> !iproblem.getMessage() - .contains("Syntax error, insert \":: IdentifierOrNew\"")) - // Transform into our Problems - .map(iproblem -> { - int start = iproblem.getSourceStart(); - int stop = iproblem.getSourceEnd() + 1; // make it exclusive - SketchInterval in = ps.mapJavaToSketch(start, stop); - if (in == SketchInterval.BEFORE_START) return null; - int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); - JavaProblem p = new JavaProblem(iproblem, in.tabIndex, line); - p.setPDEOffsets(in.startTabOffset, in.stopTabOffset); - return p; - }) - .filter(p -> p != null) - .collect(Collectors.toList()); - - // Handle import suggestions - if (JavaMode.importSuggestEnabled) { - Map> undefinedTypeProblems = problems.stream() - // Get only problems with undefined types/names - .filter(p -> { - int id = ((JavaProblem) p).getIProblem().getID(); - return id == IProblem.UndefinedType || - id == IProblem.UndefinedName || - id == IProblem.UnresolvedVariable; - }) - // Group problems by the missing type/name - .collect(Collectors.groupingBy(p -> ((JavaProblem) p).getIProblem().getArguments()[0])); - - if (!undefinedTypeProblems.isEmpty()) { - final ClassPath cp = ps.searchClassPath; - - // Get suggestions for each missing type, update the problems - undefinedTypeProblems.entrySet().stream() - .forEach(entry -> { - String missingClass = entry.getKey(); - List affectedProblems = entry.getValue(); - String[] suggestions = getImportSuggestions(cp, missingClass); - affectedProblems.forEach(p -> ((JavaProblem) p).setImportSuggestions(suggestions)); - }); - } - } - - if (scheduledUiUpdate != null) { - scheduledUiUpdate.cancel(true); - } - // Update UI after a delay. See #2677 - long delay = nextUiUpdate - System.currentTimeMillis(); - Runnable uiUpdater = () -> { - if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) { - EventQueue.invokeLater(() -> editor.setProblemList(problems)); - } - }; - scheduledUiUpdate = scheduler.schedule(uiUpdater, delay, - TimeUnit.MILLISECONDS); - } - - - public static String[] getImportSuggestions(ClassPath cp, String className) { - RegExpResourceFilter regf = new RegExpResourceFilter( - Pattern.compile(".*"), - Pattern.compile("(.*\\$)?" + className + "\\.class", - Pattern.CASE_INSENSITIVE)); - - String[] resources = cp.findResources("", regf); - return Arrays.stream(resources) - // remove ".class" suffix - .map(res -> res.substring(0, res.length() - 6)) - // replace path separators with dots - .map(res -> res.replace('/', '.')) - // replace inner class separators with dots - .map(res -> res.replace('$', '.')) - // sort, prioritize clases from java. package - .sorted((o1, o2) -> { - // put java.* first, should be prioritized more - boolean o1StartsWithJava = o1.startsWith("java"); - boolean o2StartsWithJava = o2.startsWith("java"); - if (o1StartsWithJava != o2StartsWithJava) { - if (o1StartsWithJava) return -1; - return 1; - } - return o1.compareTo(o2); - }) - .toArray(String[]::new); - } - - } } diff --git a/java/src/processing/mode/java/pdex/PreprocessedSketch.java b/java/src/processing/mode/java/pdex/PreprocessedSketch.java index 9f4fd2005c..3dc328967e 100644 --- a/java/src/processing/mode/java/pdex/PreprocessedSketch.java +++ b/java/src/processing/mode/java/pdex/PreprocessedSketch.java @@ -2,6 +2,7 @@ import com.google.classpath.ClassPath; +import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -25,10 +26,11 @@ public class PreprocessedSketch { public final ClassPath classPath; public final URLClassLoader classLoader; - public final ClassPath searchClassPath; + public final String[] searchClassPathArray; public final int[] tabStartOffsets; + public final String scrubbedPdeCode; public final String pdeCode; public final String javaCode; @@ -75,12 +77,26 @@ public boolean inRange(SketchInterval interval) { } + public String getPdeCode(SketchInterval si) { + if (si == SketchInterval.BEFORE_START) return ""; + int stop = Math.min(si.stopPdeOffset, pdeCode.length()); + int start = Math.min(si.startPdeOffset, stop); + return pdeCode.substring(start, stop); + } + + public SketchInterval mapJavaToSketch(ASTNode node) { return mapJavaToSketch(node.getStartPosition(), node.getStartPosition() + node.getLength()); } + public SketchInterval mapJavaToSketch(IProblem iproblem) { + return mapJavaToSketch(iproblem.getSourceStart(), + iproblem.getSourceEnd() + 1); // make it exclusive + } + + public SketchInterval mapJavaToSketch(int startJavaOffset, int stopJavaOffset) { int length = stopJavaOffset - startJavaOffset; int startPdeOffset = javaOffsetToPdeOffset(startJavaOffset); @@ -117,7 +133,7 @@ private int javaOffsetToPdeOffset(int javaOffset) { } - private int pdeOffsetToTabIndex(int pdeOffset) { + public int pdeOffsetToTabIndex(int pdeOffset) { pdeOffset = Math.max(0, pdeOffset); int tab = Arrays.binarySearch(tabStartOffsets, pdeOffset); if (tab < 0) { @@ -127,7 +143,7 @@ private int pdeOffsetToTabIndex(int pdeOffset) { } - private int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) { + public int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) { int tabStartOffset = tabStartOffsets[clipTabIndex(tabIndex)]; return pdeOffset - tabStartOffset; } @@ -203,10 +219,11 @@ public static class Builder { public ClassPath classPath; public URLClassLoader classLoader; - public ClassPath searchClassPath; + public String[] searchClassPathArray; public int[] tabStartOffsets = new int[0]; + public String scrubbedPdeCode; public String pdeCode; public String javaCode; @@ -237,10 +254,11 @@ private PreprocessedSketch(Builder b) { classPath = b.classPath; classLoader = b.classLoader; - searchClassPath = b.searchClassPath; + searchClassPathArray = b.searchClassPathArray; tabStartOffsets = b.tabStartOffsets; + scrubbedPdeCode = b.scrubbedPdeCode; pdeCode = b.pdeCode; javaCode = b.javaCode; diff --git a/java/src/processing/mode/java/pdex/PreprocessingService.java b/java/src/processing/mode/java/pdex/PreprocessingService.java index 8a3005256f..b50e117990 100644 --- a/java/src/processing/mode/java/pdex/PreprocessingService.java +++ b/java/src/processing/mode/java/pdex/PreprocessingService.java @@ -72,7 +72,6 @@ /** * The main error checking service */ -@SuppressWarnings("unchecked") public class PreprocessingService { protected final JavaEditor editor; @@ -93,7 +92,7 @@ public class PreprocessingService { private CompletableFuture preprocessingTask = new CompletableFuture<>(); private CompletableFuture lastCallback = - new CompletableFuture() {{ + new CompletableFuture() {{ complete(null); // initialization block }}; @@ -275,10 +274,14 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { for (SketchCode sc : sketch.getCode()) { if (sc.isExtension("pde")) { tabStartsList.append(workBuffer.length()); - try { - workBuffer.append(sc.getDocumentText()); - } catch (BadLocationException e) { - e.printStackTrace(); + if (sc.getDocument() != null) { + try { + workBuffer.append(sc.getDocumentText()); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } else { + workBuffer.append(sc.getProgram()); } workBuffer.append('\n'); } @@ -309,6 +312,8 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { SourceUtils.scrubCommentsAndStrings(workBuffer); + result.scrubbedPdeCode = workBuffer.toString(); + Mode sketchMode = PdePreprocessor.parseMode(workBuffer); // Prepare transforms to convert pde code into parsable code @@ -341,7 +346,7 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { boolean rebuildClassPath = reloadCodeFolder || rebuildLibraryClassPath || prevResult.classLoader == null || prevResult.classPath == null || - prevResult.classPathArray == null || prevResult.searchClassPath == null; + prevResult.classPathArray == null || prevResult.searchClassPathArray == null; if (reloadCodeFolder) { codeFolderClassPath = buildCodeFolderClassPath(sketch); @@ -381,13 +386,12 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { searchClassPath.addAll(coreLibraryClassPath); searchClassPath.addAll(codeFolderClassPath); - String[] searchClassPathArray = searchClassPath.stream().toArray(String[]::new); - result.searchClassPath = classPathFactory.createFromPaths(searchClassPathArray); + result.searchClassPathArray = searchClassPath.stream().toArray(String[]::new); } } else { result.classLoader = prevResult.classLoader; result.classPath = prevResult.classPath; - result.searchClassPath = prevResult.searchClassPath; + result.searchClassPathArray = prevResult.searchClassPathArray; result.classPathArray = prevResult.classPathArray; } } @@ -414,7 +418,7 @@ private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) { makeAST(parser, compilableStageChars, COMPILER_OPTIONS); // Get syntax problems from compilable AST - result.hasSyntaxErrors = Arrays.stream(compilableCU.getProblems()) + result.hasSyntaxErrors |= Arrays.stream(compilableCU.getProblems()) .anyMatch(IProblem::isError); // Generate bindings after getting problems - avoids @@ -560,8 +564,8 @@ private static List buildSearchLibraryClassPath(JavaMode mode) { } - private List buildSketchLibraryClassPath(JavaMode mode, - List programImports) { + static private List buildSketchLibraryClassPath(JavaMode mode, + List programImports) { StringBuilder classPath = new StringBuilder(); programImports.stream() @@ -582,19 +586,34 @@ private List buildSketchLibraryClassPath(JavaMode mode, } - private List buildJavaRuntimeClassPath() { + static private List buildJavaRuntimeClassPath() { StringBuilder classPath = new StringBuilder(); - // Java runtime - String rtPath = System.getProperty("java.home") + - File.separator + "lib" + File.separator + "rt.jar"; - if (new File(rtPath).exists()) { - classPath.append(File.pathSeparator).append(rtPath); - } else { - rtPath = System.getProperty("java.home") + File.separator + "jre" + + { // Java runtime + String rtPath = System.getProperty("java.home") + File.separator + "lib" + File.separator + "rt.jar"; if (new File(rtPath).exists()) { classPath.append(File.pathSeparator).append(rtPath); + } else { + rtPath = System.getProperty("java.home") + File.separator + "jre" + + File.separator + "lib" + File.separator + "rt.jar"; + if (new File(rtPath).exists()) { + classPath.append(File.pathSeparator).append(rtPath); + } + } + } + + { // JavaFX runtime + String jfxrtPath = System.getProperty("java.home") + + File.separator + "lib" + File.separator + "ext" + File.separator + "jfxrt.jar"; + if (new File(jfxrtPath).exists()) { + classPath.append(File.pathSeparator).append(jfxrtPath); + } else { + jfxrtPath = System.getProperty("java.home") + File.separator + "jre" + + File.separator + "lib" + File.separator + "ext" + File.separator + "jfxrt.jar"; + if (new File(jfxrtPath).exists()) { + classPath.append(File.pathSeparator).append(jfxrtPath); + } } } @@ -646,7 +665,7 @@ private static CompilationUnit makeASTWithBindings(ASTParser parser, /** * Ignore processing packages, java.*.*. etc. */ - private boolean ignorableImport(String packageName) { + static private boolean ignorableImport(String packageName) { return (packageName.startsWith("java.") || packageName.startsWith("javax.")); } diff --git a/java/src/processing/mode/java/pdex/Rename.java b/java/src/processing/mode/java/pdex/Rename.java new file mode 100644 index 0000000000..b143cd721a --- /dev/null +++ b/java/src/processing/mode/java/pdex/Rename.java @@ -0,0 +1,335 @@ +package processing.mode.java.pdex; + +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JRootPane; +import javax.swing.JTextField; +import javax.swing.WindowConstants; +import javax.swing.text.BadLocationException; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.SimpleName; + +import processing.app.Language; +import processing.app.Platform; +import processing.app.Sketch; +import processing.app.SketchCode; +import processing.app.syntax.SyntaxDocument; +import processing.app.ui.EditorStatus; +import processing.app.ui.Toolkit; +import processing.mode.java.JavaEditor; +import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; + +import static processing.mode.java.pdex.ASTUtils.findAllOccurrences; +import static processing.mode.java.pdex.ASTUtils.getSimpleNameAt; +import static processing.mode.java.pdex.ASTUtils.resolveBinding; + + +class Rename { + final JavaEditor editor; + final PreprocessingService pps; + final ShowUsage showUsage; + + final JDialog window; + final JTextField textField; + final JLabel oldNameLabel; + + IBinding binding; + PreprocessedSketch ps; + + + Rename(JavaEditor editor, PreprocessingService pps, ShowUsage showUsage) { + this.editor = editor; + this.pps = pps; + this.showUsage = showUsage; + + // Add rename option + JMenuItem renameItem = new JMenuItem(Language.text("editor.popup.rename")); + renameItem.addActionListener(e -> handleRename()); + editor.getTextArea().getRightClickPopup().add(renameItem); + + window = new JDialog(editor); + JRootPane rootPane = window.getRootPane(); + window.setTitle("Rename"); + window.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + Toolkit.registerWindowCloseKeys(rootPane, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + window.setVisible(false); + } + }); + Toolkit.setIcon(window); + + window.setModal(true); + window.setResizable(false); + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent e) { + binding = null; + ps = null; + } + }); + //window.setSize(Toolkit.zoom(250, 130)); + //window.setLayout(new BoxLayout(window.getContentPane(), BoxLayout.Y_AXIS)); + Box windowBox = Box.createVerticalBox(); + Toolkit.setBorder(windowBox); + final int GAP = Toolkit.zoom(5); + + { // old name + Box oldBox = Box.createHorizontalBox(); + oldNameLabel = new JLabel("Current Name: "); + oldBox.add(oldNameLabel); + //oldBox.add(Box.createHorizontalStrut(10)); + oldBox.add(Box.createHorizontalGlue()); + windowBox.add(oldBox); + windowBox.add(Box.createVerticalStrut(GAP)); + } + + { // new name + Box newBox = Box.createHorizontalBox(); + JLabel newNameLabel = new JLabel("New Name: "); + newBox.add(newNameLabel); + newBox.add(textField = new JTextField(20)); + newBox.add(Box.createHorizontalGlue()); + windowBox.add(newBox); + windowBox.add(Box.createVerticalStrut(GAP*2)); + } + + { // button panel + JButton showUsageButton = new JButton("Show Usage"); + showUsageButton.addActionListener(e -> { + showUsage.findUsageAndUpdateTree(ps, binding); + window.setVisible(false); + }); + + JButton renameButton = new JButton("Rename"); + renameButton.addActionListener(e -> { + final String newName = textField.getText().trim(); + if (!newName.isEmpty()) { + if (newName.length() >= 1 && + newName.chars().limit(1).allMatch(Character::isJavaIdentifierStart) && + newName.chars().skip(1).allMatch(Character::isJavaIdentifierPart)) { + rename(ps, binding, newName); + window.setVisible(false); + } else { + String msg = String.format("'%s' is not a valid name", newName); + JOptionPane.showMessageDialog(editor, msg, "Naming is Hard", + JOptionPane.PLAIN_MESSAGE); + } + } + }); + rootPane.setDefaultButton(renameButton); + + //JPanel panelBottom = new JPanel(); + //panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS)); + Box buttonBox = Box.createHorizontalBox(); + //Toolkit.setBorder(panelBottom, 5, 5, 5, 5); + + buttonBox.add(Box.createHorizontalGlue()); + buttonBox.add(showUsageButton); + if (!Platform.isMacOS()) { + buttonBox.add(Box.createHorizontalStrut(GAP)); + } + buttonBox.add(renameButton); + buttonBox.add(Box.createHorizontalGlue()); + + Dimension showDim = showUsageButton.getPreferredSize(); + Dimension renameDim = renameButton.getPreferredSize(); + final int niceSize = Math.max(showDim.width, renameDim.width) + GAP; + final Dimension buttonDim = new Dimension(niceSize, showDim.height); + showUsageButton.setPreferredSize(buttonDim); + renameButton.setPreferredSize(buttonDim); + + windowBox.add(buttonBox); + + //window.add(panelBottom); + } + window.add(windowBox); + window.pack(); + //window.setMinimumSize(window.getSize()); + } + + + // Thread: EDT + void handleRename() { + int startOffset = editor.getSelectionStart(); + int stopOffset = editor.getSelectionStop(); + int tabIndex = editor.getSketch().getCurrentCodeIndex(); + + pps.whenDoneBlocking(ps -> handleRename(ps, tabIndex, startOffset, stopOffset)); + } + + + // Thread: worker + void handleRename(PreprocessedSketch ps, int tabIndex, int startTabOffset, int stopTabOffset) { + if (ps.hasSyntaxErrors) { + editor.statusMessage("Cannot rename until syntax errors are fixed", + EditorStatus.WARNING); + return; + } + + ASTNode root = ps.compilationUnit; + + // Map offsets + int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset); + int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset); + + // Find the node + SimpleName name = getSimpleNameAt(root, startJavaOffset, stopJavaOffset); + if (name == null) { + editor.statusMessage("Highlight the class/function/variable name first", + EditorStatus.NOTICE); + return; + } + + // Find binding + IBinding binding = resolveBinding(name); + if (binding == null) { + editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " + + "so it cannot be renamed", EditorStatus.ERROR); + return; + } + + ASTNode decl = ps.compilationUnit.findDeclaringNode(binding.getKey()); + if (decl == null) { + editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " + + "so it cannot be renamed", EditorStatus.ERROR); + return; + } + + // Display the rename dialog + EventQueue.invokeLater(() -> { + if (!window.isVisible()) { + this.ps = ps; + this.binding = binding; + oldNameLabel.setText("Current name: " + binding.getName()); + textField.setText(binding.getName()); + textField.requestFocus(); + textField.selectAll(); + int x = editor.getX() + (editor.getWidth() - window.getWidth()) / 2; + int y = editor.getY() + (editor.getHeight() - window.getHeight()) / 2; + window.setLocation(x, y); + window.setVisible(true); + window.toFront(); + } + }); + } + + + // Thread: EDT (we can't allow user to mess with sketch while renaming) + void rename(PreprocessedSketch ps, IBinding binding, String newName) { + CompilationUnit root = ps.compilationUnit; + + // Renaming constructor should rename class + if (binding.getKind() == IBinding.METHOD) { + IMethodBinding method = (IMethodBinding) binding; + if (method.isConstructor()) { + binding = method.getDeclaringClass(); + } + } + + ASTNode decl = root.findDeclaringNode(binding.getKey()); + if (decl == null) return; + + showUsage.hide(); + + List occurrences = new ArrayList<>(); + occurrences.addAll(findAllOccurrences(root, binding.getKey())); + + // Renaming class should rename all constructors + if (binding.getKind() == IBinding.TYPE) { + ITypeBinding type = (ITypeBinding) binding; + //type = type.getErasure(); + IMethodBinding[] methods = type.getDeclaredMethods(); + Arrays.stream(methods) + .filter(IMethodBinding::isConstructor) + .flatMap(c -> findAllOccurrences(root, c.getKey()).stream()) + .forEach(occurrences::add); + } + + Map> mappedNodes = occurrences.stream() + .map(ps::mapJavaToSketch) + .filter(ps::inRange) + .collect(Collectors.groupingBy(interval -> interval.tabIndex)); + + Sketch sketch = ps.sketch; + + editor.startCompoundEdit(); + + mappedNodes.entrySet().forEach(entry -> { + int tabIndex = entry.getKey(); + SketchCode sketchCode = sketch.getCode(tabIndex); + + SyntaxDocument document = (SyntaxDocument) sketchCode.getDocument(); + + List nodes = entry.getValue(); + nodes.stream() + // Replace from the end so all unprocess offsets stay valid + .sorted(Comparator.comparing((SketchInterval si) -> si.startTabOffset).reversed()) + .forEach(si -> { + // Make sure offsets are in bounds + int documentLength = document.getLength(); + if (si.startTabOffset >= 0 && si.startTabOffset <= documentLength && + si.stopTabOffset >= 0 && si.stopTabOffset <= documentLength) { + // Replace the code + int length = si.stopTabOffset - si.startTabOffset; + try { + document.remove(si.startTabOffset, length); + document.insertString(si.startTabOffset, newName, null); + } catch (BadLocationException e) { /* Whatever */ } + } + }); + + try { + sketchCode.setProgram(document.getText(0, document.getLength())); + } catch (BadLocationException e) { /* Whatever */ } + sketchCode.setModified(true); + }); + + editor.stopCompoundEdit(); + + editor.repaintHeader(); + + int currentTabIndex = sketch.getCurrentCodeIndex(); + final int currentOffset = editor.getCaretOffset(); + + int precedingIntervals = + (int) mappedNodes.getOrDefault(currentTabIndex, Collections.emptyList()) + .stream() + .filter(interval -> interval.stopTabOffset < currentOffset) + .count(); + int intervalLengthDiff = newName.length() - binding.getName().length(); + int offsetDiff = precedingIntervals * intervalLengthDiff; + + editor.getTextArea().setCaretPosition(currentOffset + offsetDiff); + } + + + void dispose() { + if (window != null) { + window.dispose(); + } + } +} diff --git a/java/src/processing/mode/java/pdex/ShowUsage.java b/java/src/processing/mode/java/pdex/ShowUsage.java new file mode 100644 index 0000000000..91bf043839 --- /dev/null +++ b/java/src/processing/mode/java/pdex/ShowUsage.java @@ -0,0 +1,329 @@ +package processing.mode.java.pdex; + +import static processing.mode.java.pdex.ASTUtils.findAllOccurrences; + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import javax.swing.JDialog; +import javax.swing.JMenuItem; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.WindowConstants; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; + +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.SimpleName; + +import processing.app.Language; +import processing.app.ui.EditorStatus; +import processing.app.ui.Toolkit; +import processing.app.ui.ZoomTreeCellRenderer; +import processing.mode.java.JavaEditor; +import processing.mode.java.pdex.PreprocessedSketch.SketchInterval; + + +class ShowUsage { + final JDialog window; + final JTree tree; + + final JavaEditor editor; + final PreprocessingService pps; + + final Consumer reloadListener; + + IBinding binding; + + + ShowUsage(JavaEditor editor, PreprocessingService pps) { + this.editor = editor; + this.pps = pps; + + // Add show usage option + JMenuItem showUsageItem = + new JMenuItem(Language.text("editor.popup.show_usage")); + showUsageItem.addActionListener(e -> handleShowUsage()); + editor.getTextArea().getRightClickPopup().add(showUsageItem); + + reloadListener = this::reloadShowUsage; + + { // Show Usage window + window = new JDialog(editor); + window.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + window.setAutoRequestFocus(false); + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent e) { + binding = null; + tree.setModel(null); + pps.unregisterListener(reloadListener); + } + + @Override + public void componentShown(ComponentEvent e) { + pps.registerListener(reloadListener); + } + }); + window.setSize(Toolkit.zoom(300, 400)); + window.setFocusableWindowState(false); + Toolkit.setIcon(window); + JScrollPane sp2 = new JScrollPane(); + tree = new JTree(); + ZoomTreeCellRenderer renderer = + new ZoomTreeCellRenderer(editor.getMode()); + tree.setCellRenderer(renderer); + renderer.setLeafIcon(null); + renderer.setClosedIcon(null); + renderer.setOpenIcon(null); + renderer.setBackgroundSelectionColor(new Color(228, 248, 246)); + renderer.setBorderSelectionColor(new Color(0, 0, 0, 0)); + renderer.setTextSelectionColor(Color.BLACK); + sp2.setViewportView(tree); + window.add(sp2); + } + + tree.addTreeSelectionListener(e -> { + if (tree.getLastSelectedPathComponent() != null) { + DefaultMutableTreeNode tnode = + (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + + if (tnode.getUserObject() instanceof ShowUsageTreeNode) { + ShowUsageTreeNode node = (ShowUsageTreeNode) tnode.getUserObject(); + editor.highlight(node.tabIndex, node.startTabOffset, node.stopTabOffset); + } + } + }); + } + + + // Thread: EDT + void handleShowUsage() { + int startOffset = editor.getSelectionStart(); + int stopOffset = editor.getSelectionStop(); + int tabIndex = editor.getSketch().getCurrentCodeIndex(); + + pps.whenDoneBlocking(ps -> handleShowUsage(ps, tabIndex, startOffset, stopOffset)); + } + + + // Thread: worker + void handleShowUsage(PreprocessedSketch ps, int tabIndex, + int startTabOffset, int stopTabOffset) { + // Map offsets + int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset); + int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset); + + // Find the node + SimpleName name = ASTUtils.getSimpleNameAt(ps.compilationUnit, startJavaOffset, stopJavaOffset); + if (name == null) { + editor.statusMessage("Cannot find any name under cursor", EditorStatus.NOTICE); + return; + } + + // Find binding + IBinding binding = ASTUtils.resolveBinding(name); + if (binding == null) { + editor.statusMessage("Cannot find usages, try to fix errors in your code first", + EditorStatus.NOTICE); + return; + } + + findUsageAndUpdateTree(ps, binding); + } + + + // Thread: worker + void findUsageAndUpdateTree(PreprocessedSketch ps, IBinding binding) { + + this.binding = binding; + + // Get label + String bindingType = ""; + switch (binding.getKind()) { + case IBinding.METHOD: + IMethodBinding method = (IMethodBinding) binding; + if (method.isConstructor()) bindingType = "Constructor"; + else bindingType = "Method"; + break; + case IBinding.TYPE: + bindingType = "Type"; + break; + case IBinding.VARIABLE: + IVariableBinding variable = (IVariableBinding) binding; + if (variable.isField()) bindingType = "Field"; + else if (variable.isParameter()) bindingType = "Parameter"; + else if (variable.isEnumConstant()) bindingType = "Enum constant"; + else bindingType = "Local variable"; + break; + } + + // Find usages, map to tree nodes, add to root node + String bindingKey = binding.getKey(); + List intervals = + findAllOccurrences(ps.compilationUnit, bindingKey).stream() + .map(ps::mapJavaToSketch) + // remove occurrences which fall into generated header + .filter(ps::inRange) + // remove empty intervals (happens when occurence was inserted) + .filter(in -> in.startPdeOffset < in.stopPdeOffset) + .collect(Collectors.toList()); + + int usageCount = intervals.size(); + + // Get element name from PDE code if possible, otherwise use one from Java + String elementName = intervals.stream() + .findAny() + .map(si -> ps.pdeCode.substring(si.startPdeOffset, si.stopPdeOffset)) + .orElseGet(binding::getName); + + // Create root node + DefaultMutableTreeNode rootNode = + new DefaultMutableTreeNode(bindingType + ": " + elementName); + + intervals.stream() + // Convert to TreeNodes + .map(in -> ShowUsageTreeNode.fromSketchInterval(ps, in)) + // Group by tab index + .collect(Collectors.groupingBy(node -> node.tabIndex)) + // Stream Map Entries of (tab index) <-> (List) + .entrySet().stream() + // Sort by tab index + .sorted(Comparator.comparing(Map.Entry::getKey)) + .map(entry -> { + Integer tabIndex = entry.getKey(); + List nodes = entry.getValue(); + + int count = nodes.size(); + String usageLabel = count == 1 ? "usage" : "usages"; + + // Create new DefaultMutableTreeNode for this tab + String tabLabel = "" + + ps.sketch.getCode(tabIndex).getPrettyName() + + " " + count + " " + usageLabel + ""; + DefaultMutableTreeNode tabNode = new DefaultMutableTreeNode(tabLabel); + + // Stream nodes belonging to this tab + nodes.stream() + // Convert TreeNodes to DefaultMutableTreeNodes + .map(DefaultMutableTreeNode::new) + // Add all as children of tab node + .forEach(tabNode::add); + return tabNode; + }) + // Add all tab nodes as children of root node + .forEach(rootNode::add); + + TreeModel treeModel = new DefaultTreeModel(rootNode); + + // Update tree + EventQueue.invokeLater(() -> { + tree.setModel(treeModel); + + // Expand all nodes + for (int i = 0; i < tree.getRowCount(); i++) { + tree.expandRow(i); + } + + tree.setRootVisible(true); + + if (!window.isVisible()) { + window.setVisible(true); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice defaultScreen = ge.getDefaultScreenDevice(); + Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds(); + int maxX = (int) rect.getMaxX() - window.getWidth(); + int x = Math.min(editor.getX() + editor.getWidth(), maxX); + int y = (x == maxX) ? 10 : editor.getY(); + window.setLocation(x, y); + } + window.toFront(); + window.setTitle("Usage of \"" + elementName + "\" : " + + usageCount + " time(s)"); + }); + } + + + // Thread: worker + void reloadShowUsage(PreprocessedSketch ps) { + if (binding != null) { + findUsageAndUpdateTree(ps, binding); + } + } + + + void hide() { + window.setVisible(false); + } + + + void dispose() { + if (window != null) { + window.dispose(); + } + } +} + + +class ShowUsageTreeNode { + final int tabIndex; + final int startTabOffset; + final int stopTabOffset; + + final String text; + + + ShowUsageTreeNode(int tabIndex, int startTabOffset, int stopTabOffset, String text) { + this.tabIndex = tabIndex; + this.startTabOffset = startTabOffset; + this.stopTabOffset = stopTabOffset; + this.text = text; + } + + + static ShowUsageTreeNode fromSketchInterval(PreprocessedSketch ps, SketchInterval in) { + int lineStartPdeOffset = ps.pdeCode.lastIndexOf('\n', in.startPdeOffset) + 1; + int lineStopPdeOffset = ps.pdeCode.indexOf('\n', in.stopPdeOffset); + if (lineStopPdeOffset == -1) lineStopPdeOffset = ps.pdeCode.length(); + + int highlightStartOffset = in.startPdeOffset - lineStartPdeOffset; + int highlightStopOffset = in.stopPdeOffset - lineStartPdeOffset; + + int tabLine = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset); + + // TODO: what a mess + String line = ps.pdeCode.substring(lineStartPdeOffset, lineStopPdeOffset); + String pre = line.substring(0, highlightStartOffset) + .replace("&", "&").replace(">", ">").replace("<", "<"); + String highlight = line.substring(highlightStartOffset, highlightStopOffset) + .replace("&", "&").replace(">", ">").replace("<", "<"); + String post = line.substring(highlightStopOffset) + .replace("&", "&").replace(">", ">").replace("<", "<"); + line = pre + "" + highlight + "" + post; + line = line.trim(); + + + String text = "" + + (tabLine + 1) + " " + line + ""; + + return new ShowUsageTreeNode(in.tabIndex, in.startTabOffset, in.stopTabOffset, text); + } + + @Override + public String toString() { + return text; + } +} diff --git a/java/src/processing/mode/java/pdex/SourceUtils.java b/java/src/processing/mode/java/pdex/SourceUtils.java index 66703b246d..ec619fd86e 100644 --- a/java/src/processing/mode/java/pdex/SourceUtils.java +++ b/java/src/processing/mode/java/pdex/SourceUtils.java @@ -55,8 +55,12 @@ public static List parseProgramImports(CharSequence source, + // Positive lookahead and lookbehind are needed to match all type constructors + // in code like `int(byte(245))` where first bracket matches as last + // group in "^int(" but also as a first group in "(byte(". Lookahead and + // lookbehind won't consume the shared character. public static final Pattern TYPE_CONSTRUCTOR_REGEX = - Pattern.compile("(?:^|\\W)(int|char|float|boolean|byte)(?:\\s*\\()", + Pattern.compile("(?<=^|\\W)(int|char|float|boolean|byte)(?=\\s*\\()", Pattern.MULTILINE); public static List replaceTypeConstructors(CharSequence source) { @@ -80,7 +84,7 @@ public static List replaceTypeConstructors(CharSequence source) { public static final Pattern HEX_LITERAL_REGEX = - Pattern.compile("(?:^|\\W)(#[A-Fa-f0-9]{6})(?:\\W|$)"); + Pattern.compile("(?<=^|\\W)(#[A-Fa-f0-9]{6})(?=\\W|$)"); public static List replaceHexLiterals(CharSequence source) { // Find all #[webcolor] and replace with 0xff[webcolor] @@ -262,6 +266,14 @@ static public void scrubCommentsAndStrings(StringBuilder p) { for (int i = 0; i <= length; i++) { char ch = (i < length) ? p.charAt(i) : 0; char pch = (i == 0) ? 0 : p.charAt(i-1); + // Get rid of double backslash immediately, otherwise + // the second backslash incorrectly triggers a new escape sequence + if (pch == '\\' && ch == '\\') { + p.setCharAt(i-1, ' '); + p.setCharAt(i, ' '); + pch = ' '; + ch = ' '; + } switch (state) { case OUT: switch (ch) { @@ -272,7 +284,7 @@ static public void scrubCommentsAndStrings(StringBuilder p) { } break; case IN_BLOCK_COMMENT: - if (pch == '*' && ch == '/' && (i - blockStart) > 1) { + if (pch == '*' && ch == '/' && (i - blockStart) > 0) { state = OUT; } break; @@ -319,4 +331,41 @@ static public void scrubCommentsAndStrings(StringBuilder p) { } + + // TODO: move this to a better place when JavaBuild starts using JDT and we + // don't need to check errors at two different places [jv 2017-09-19] + /** + * Checks a single code fragment (such as a tab) for non-matching braces. + * Broken out to allow easy use in JavaBuild. + * @param c Program code scrubbed of comments and string literals. + * @param start Start index, inclusive. + * @param end End index, exclusive. + * @return {@code int[4]} Depth at which the loop stopped, followed by the + * line number, column, and string index (within the range) at which + * an error was found, if any. + */ + static public int[] checkForMissingBraces(CharSequence c, int start, int end) { + int depth = 0; + int lineNumber = 0; + int lineStart = start; + for (int i = start; i < end; i++) { + char ch = c.charAt(i); + switch (ch) { + case '{': + depth++; + break; + case '}': + depth--; + break; + case '\n': + lineNumber++; + lineStart = i; + break; + } + if (depth < 0) { + return new int[] {depth, lineNumber, i - lineStart, i - start}; + } + } + return new int[] {depth, lineNumber - 1, end - lineStart - 2, end - start - 2}; + } } diff --git a/java/src/processing/mode/java/preproc/PdeEmitter.java b/java/src/processing/mode/java/preproc/PdeEmitter.java index c2b5a4ed15..1f1adca228 100644 --- a/java/src/processing/mode/java/preproc/PdeEmitter.java +++ b/java/src/processing/mode/java/preproc/PdeEmitter.java @@ -8,7 +8,6 @@ import java.util.Stack; import processing.app.Preferences; import processing.app.SketchException; -import processing.mode.java.preproc.PdeTokenTypes; import antlr.CommonASTWithHiddenTokens; import antlr.CommonHiddenStreamToken; import antlr.collections.AST; @@ -35,7 +34,7 @@ public class PdeEmitter implements PdeTokenTypes { private final PrintWriter out; private final PrintStream debug = System.err; - private final Stack stack = new Stack(); + private final Stack stack = new Stack<>(); private final static int ROOT_ID = 0; public PdeEmitter(final PdePreprocessor pdePreprocessor, final PrintWriter out) { diff --git a/java/src/processing/mode/java/preproc/PdePreprocessor.java b/java/src/processing/mode/java/preproc/PdePreprocessor.java index 074a3c6c7c..c11b229667 100644 --- a/java/src/processing/mode/java/preproc/PdePreprocessor.java +++ b/java/src/processing/mode/java/preproc/PdePreprocessor.java @@ -4,7 +4,8 @@ PdePreprocessor - wrapper for default ANTLR-generated parser Part of the Processing project - http://processing.org - Copyright (c) 2004-15 Ben Fry and Casey Reas + Copyright (c) 2012-19 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology ANTLR-generated parser and several supporting classes written @@ -27,6 +28,7 @@ package processing.mode.java.preproc; +import java.awt.EventQueue; import java.io.*; import java.util.*; import java.util.regex.MatchResult; @@ -152,6 +154,7 @@ public enum Mode { Set foundMethods; SurfaceInfo sizeInfo; + boolean settingsMethod; /** @@ -174,6 +177,8 @@ public enum Mode { static private final Pattern VOID_SETUP_REGEX = Pattern.compile("(?:^|\\s|;)void\\s+setup\\s*\\(", Pattern.MULTILINE); + static private final Pattern VOID_SETTINGS_REGEX = + Pattern.compile("(?:^|\\s|;)void\\s+settings\\s*\\(", Pattern.MULTILINE); // Can't only match any 'public class', needs to be a PApplet // http://code.google.com/p/processing/issues/detail?id=551 @@ -203,8 +208,9 @@ public PdePreprocessor(final String sketchName, final int tabSize) { } + /** Parse the sketch size and set the internal sizeInfo variable */ public SurfaceInfo initSketchSize(String code, - boolean sizeWarning) throws SketchException { + boolean sizeWarning) throws SketchException { sizeInfo = parseSketchSize(code, sizeWarning); return sizeInfo; } @@ -250,6 +256,13 @@ static private StringList breakCommas(String contents) { } + // if there's a settings() method, we do less moving things around + static public boolean hasSettingsMethod(String code) { + final String uncommented = scrubComments(code); + return findInCurrentScope(VOID_SETTINGS_REGEX, uncommented) != null; + } + + /** * Parse a chunk of code and extract the size() command and its contents. * Also goes after fullScreen(), smooth(), and noSmooth(). @@ -258,26 +271,21 @@ static private StringList breakCommas(String contents) { * @return null if there was an error, otherwise an array (might contain some/all nulls) */ static public SurfaceInfo parseSketchSize(String code, - boolean fussy) throws SketchException { + boolean fussy) throws SketchException { // This matches against any uses of the size() function, whether numbers // or variables or whatever. This way, no warning is shown if size() isn't // actually used in the applet, which is the case especially for anyone // who is cutting/pasting from the reference. -// String scrubbed = scrubComments(sketch.getCode(0).getProgram()); -// String[] matches = PApplet.match(scrubbed, SIZE_REGEX); -// String[] matches = PApplet.match(scrubComments(code), SIZE_REGEX); - - /* - 1. no size() or fullScreen() method at all - will use the non-overridden settings() method in PApplet - 2. size() or fullScreen() found inside setup() (static mode sketch or otherwise) - make sure that it uses numbers (or displayWidth/Height), copy into settings - 3. size() or fullScreen() already in settings() - don't mess with the sketch, don't insert any defaults + // 1. no size() or fullScreen() method at all + // will use the non-overridden settings() method in PApplet + // 2. size() or fullScreen() found inside setup() (static mode sketch or otherwise) + // make sure that it uses numbers (or displayWidth/Height), copy into settings + // 3. size() or fullScreen() already in settings() + // don't mess with the sketch, don't insert any defaults + // + // really only need to deal with situation #2.. nothing to be done for 1 and 3 - really only need to deal with situation #2.. nothing to be done for 1 and 3 - */ // if static mode sketch, all we need is regex // easy proxy for static in this case is whether [^\s]void\s is present @@ -287,33 +295,30 @@ make sure that it uses numbers (or displayWidth/Height), copy into settings String searchArea = null; - switch (mode) { - case JAVA: - // it's up to the user - searchArea = null; - break; - case ACTIVE: - // active mode, limit scope to setup - - // Find setup() in global scope - MatchResult setupMatch = findInCurrentScope(VOID_SETUP_REGEX, uncommented); - if (setupMatch != null) { - int start = uncommented.indexOf("{", setupMatch.end()); - if (start >= 0) { - // Find a closing brace - MatchResult match = findInCurrentScope(CLOSING_BRACE, uncommented, start); - if (match != null) { - searchArea = uncommented.substring(start + 1, match.end() - 1); - } else { - throw new SketchException("Found a { that's missing a matching }", false); - } + if (mode == Mode.JAVA) { + // it's up to the user + searchArea = null; + + } else if (mode == Mode.ACTIVE) { + // active mode, limit scope to setup + + // Find setup() in global scope + MatchResult setupMatch = findInCurrentScope(VOID_SETUP_REGEX, uncommented); + if (setupMatch != null) { + int start = uncommented.indexOf("{", setupMatch.end()); + if (start >= 0) { + // Find a closing brace + MatchResult match = findInCurrentScope(CLOSING_BRACE, uncommented, start); + if (match != null) { + searchArea = uncommented.substring(start + 1, match.end() - 1); + } else { + throw new SketchException("Found a { that's missing a matching }", false); } } - break; - case STATIC: - // static mode, look everywhere - searchArea = uncommented; - break; + } + } else if (mode == Mode.STATIC) { + // static mode, look everywhere + searchArea = uncommented; } if (searchArea == null) { @@ -380,7 +385,9 @@ make sure that it uses numbers (or displayWidth/Height), copy into settings "The size of this sketch could not be determined from your code.\n" + "Use only numbers (not variables) for the size() command.\n" + "Read the size() reference for more details."; - Messages.showWarning("Could not find sketch size", message, null); + EventQueue.invokeLater(() -> { + Messages.showWarning("Could not find sketch size", message, null); + }); // new Exception().printStackTrace(System.out); // return null; throw new SketchException("Please fix the size() line to continue.", false); @@ -417,9 +424,6 @@ make sure that it uses numbers (or displayWidth/Height), copy into settings } info.width = "displayWidth"; info.height = "displayHeight"; -// if (extraStatements.size() != 0) { -// info.statement += extraStatements.join(" "); -// } info.addStatements(extraStatements); info.checkEmpty(); return info; @@ -429,71 +433,21 @@ make sure that it uses numbers (or displayWidth/Height), copy into settings // need to pull out the noSmooth() and smooth(N) methods. if (extraStatements.size() != 0) { SurfaceInfo info = new SurfaceInfo(); -// info.statement = extraStatements.join(" "); info.addStatements(extraStatements); return info; } // not an error, just no size() specified - //return new String[] { null, null, null, null, null }; return new SurfaceInfo(); } -/* - static String readSingleQuote(char[] c, int i) { - StringBuilder sb = new StringBuilder(); - try { - sb.append(c[i++]); // add the quote - if (c[i] == '\\') { - sb.append(c[i++]); // add the escape - if (c[i] == 'u') { - // grabs uNNN and the fourth N will be added below - for (int j = 0; j < 4; j++) { - sb.append(c[i++]); - } - } - } - sb.append(c[i++]); // get the char, escapee, or last unicode digit - sb.append(c[i++]); // get the closing quote - - } catch (ArrayIndexOutOfBoundsException ignored) { - // this means they have bigger problems with their code - } - return sb.toString(); - } - - - static String readDoubleQuote(char[] c, int i) { - StringBuilder sb = new StringBuilder(); - try { - sb.append(c[i++]); // add the quote - while (i < c.length) { - if (c[i] == '\\') { - sb.append(c[i++]); // add the escape - sb.append(c[i++]); // add whatever was escaped - } else if (c[i] == '\"') { - sb.append(c[i++]); - break; - } else { - sb.append(c[i++]); - } - } - } catch (ArrayIndexOutOfBoundsException ignored) { - // this means they have bigger problems with their code - } - return sb.toString(); - } -*/ - /** * Parses the code and determines the mode of the sketch. - * * @param code code without comments * @return determined mode */ static public Mode parseMode(CharSequence code) { - // See if we can find any function in the global scope if (findInCurrentScope(FUNCTION_DECL, code) != null) { return Mode.ACTIVE; @@ -730,10 +684,16 @@ static public String scrubComments(String what) { throw new RuntimeException("Missing the */ from the end of a " + "/* comment */"); } - } else if (p[index] == '"' && index > 0 && p[index-1] != '\\') { + + // switch in/out of quoted region + } else if (p[index] == '"') { insideQuote = !insideQuote; index++; + // skip the escaped char + } else if (insideQuote && p[index] == '\\') { + index += 2; + } else { // any old character, move along index++; } @@ -752,23 +712,12 @@ public boolean hasMethod(String methodName) { } -// public void setFoundMain(boolean foundMain) { -// this.foundMain = foundMain; -// } - - -// public boolean getFoundMain() { -// return foundMain; -// } - - public void setAdvClassName(final String advClassName) { this.advClassName = advClassName; } public void setMode(final Mode mode) { - //System.err.println("Setting mode to " + mode); this.mode = mode; } @@ -811,7 +760,7 @@ private static void checkForUnterminatedMultilineComment(final String program) boolean terminated = false; while (i < length - 1) { if ((program.charAt(i) == '*') && (program.charAt(i + 1) == '/')) { - i += 2; + i++; // advance to the ending '/' terminated = true; break; } else { @@ -888,7 +837,7 @@ private static void checkForUnterminatedMultilineComment(final String program) } - public PreprocessorResult write(final Writer out, String program) + public PreprocessorResult write(final Writer out, final String program) throws SketchException, RecognitionException, TokenStreamException { return write(out, program, null); } @@ -901,15 +850,15 @@ public PreprocessorResult write(Writer out, String program, // these ones have the .* at the end, since a class name might be at the end // instead of .* which would make trouble other classes using this can lop // off the . and anything after it to produce a package name consistently. - final ArrayList programImports = new ArrayList(); + final ArrayList programImports = new ArrayList<>(); // imports just from the code folder, treated differently // than the others, since the imports are auto-generated. - final ArrayList codeFolderImports = new ArrayList(); + final ArrayList codeFolderImports = new ArrayList<>(); // need to reset whether or not this has a main() // foundMain = false; - foundMethods = new HashSet(); + foundMethods = new HashSet<>(); // http://processing.org/bugs/bugzilla/5.html if (!program.endsWith("\n")) { @@ -918,10 +867,6 @@ public PreprocessorResult write(Writer out, String program, checkForUnterminatedMultilineComment(program); - if (Preferences.getBoolean("preproc.substitute_unicode")) { - program = substituteUnicode(program); - } - // For 0215, adding } as a legitimate prefix to the import (along with // newline and semicolon) for cases where a tab ends with } and an import // statement starts the next tab. @@ -936,10 +881,8 @@ public PreprocessorResult write(Writer out, String program, m = importPattern.matcher(scrubbed); found = m.find(offset); if (found) { -// System.out.println("found " + m.groupCount() + " groups"); String before = m.group(1); String piece = m.group(2) + m.group(3) + m.group(4); -// int len = piece.length(); // how much to trim out if (!ignoreImport(m.group(3))) { programImports.add(m.group(3)); // the package name @@ -948,9 +891,6 @@ public PreprocessorResult write(Writer out, String program, // find index of this import in the program int start = m.start() + before.length(); int stop = start + piece.length(); -// System.out.println(start + " " + stop + " " + piece); - //System.out.println("found " + m.group(3)); -// System.out.println("removing '" + program.substring(start, stop) + "'"); // Remove the import from the main program program = program.substring(0, start) + program.substring(stop); @@ -960,8 +900,6 @@ public PreprocessorResult write(Writer out, String program, offset = m.start(); } } while (found); -// System.out.println("program now:"); -// System.out.println(program); if (codeFolderPackages != null) { for (String item : codeFolderPackages) { @@ -977,44 +915,6 @@ public PreprocessorResult write(Writer out, String program, } - static String substituteUnicode(String program) { - // check for non-ascii chars (these will be/must be in unicode format) - char p[] = program.toCharArray(); - int unicodeCount = 0; - for (int i = 0; i < p.length; i++) { - if (p[i] > 127) - unicodeCount++; - } - if (unicodeCount == 0) - return program; - // if non-ascii chars are in there, convert to unicode escapes - // add unicodeCount * 5.. replacing each unicode char - // with six digit uXXXX sequence (xxxx is in hex) - // (except for nbsp chars which will be a replaced with a space) - int index = 0; - char p2[] = new char[p.length + unicodeCount * 5]; - for (int i = 0; i < p.length; i++) { - if (p[i] < 128) { - p2[index++] = p[i]; - } else if (p[i] == 160) { // unicode for non-breaking space - p2[index++] = ' '; - } else { - int c = p[i]; - p2[index++] = '\\'; - p2[index++] = 'u'; - char str[] = Integer.toHexString(c).toCharArray(); - // add leading zeros, so that the length is 4 - //for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0'; - for (int m = 0; m < 4 - str.length; m++) - p2[index++] = '0'; - System.arraycopy(str, 0, p2, index, str.length); - index += str.length; - } - } - return new String(p2, 0, index); - } - - /** * preprocesses a pde file and writes out a java file * @return the class name of the exported Java @@ -1027,35 +927,32 @@ private String write(final String program, final PrintWriter stream) String uncomment = scrubComments(program); PdeRecognizer parser = createParser(program); Mode mode = parseMode(uncomment); - switch (mode) { - case JAVA: + + if (mode == Mode.JAVA) { + try { + final PrintStream saved = System.err; try { - final PrintStream saved = System.err; - try { - // throw away stderr for this tentative parse - System.setErr(new PrintStream(new ByteArrayOutputStream())); - parser.javaProgram(); - } finally { - System.setErr(saved); - } - setMode(Mode.JAVA); - } catch (Exception e) { - // I can't figure out any other way of resetting the parser. - parser = createParser(program); - parser.pdeProgram(); + // throw away stderr for this tentative parse + System.setErr(new PrintStream(new ByteArrayOutputStream())); + parser.javaProgram(); + } finally { + System.setErr(saved); } - break; - case ACTIVE: - setMode(Mode.ACTIVE); - parser.activeProgram(); - break; - case STATIC: + setMode(Mode.JAVA); + } catch (Exception e) { + // I can't figure out any other way of resetting the parser. + parser = createParser(program); parser.pdeProgram(); - break; + } + } else if (mode == Mode.ACTIVE) { + setMode(Mode.ACTIVE); + parser.activeProgram(); + + } else if (mode == Mode.STATIC) { + parser.pdeProgram(); } // set up the AST for traversal by PdeEmitter - // ASTFactory factory = new ASTFactory(); AST parserAST = parser.getAST(); AST rootNode = factory.create(ROOT_ID, "AST ROOT"); @@ -1064,7 +961,6 @@ private String write(final String program, final PrintWriter stream) makeSimpleMethodsPublic(rootNode); // unclear if this actually works, but it's worth a shot - // //((CommonAST)parserAST).setVerboseStringConversion( // true, parser.getTokenNames()); // (made to use the static version because of jikes 1.22 warning) @@ -1072,7 +968,7 @@ private String write(final String program, final PrintWriter stream) final String className; if (mode == Mode.JAVA) { - // if this is an advanced program, the classname is already defined. + // in this mode, the class name is already defined. className = getFirstClassName(parserAST); } else { className = this.name; @@ -1080,7 +976,6 @@ private String write(final String program, final PrintWriter stream) // if 'null' was passed in for the name, but this isn't // a 'java' mode class, then there's a problem, so punt. - // if (className == null) return null; @@ -1282,41 +1177,14 @@ protected void writeFooter(PrintWriter out, String className) { } if ((mode == Mode.STATIC) || (mode == Mode.ACTIVE)) { - // doesn't remove the original size() method, but calling size() - // again in setup() is harmless. + // doesn't remove the original size() method, + // but calling size() again in setup() is harmless. if (!hasMethod("settings") && sizeInfo.hasSettings()) { out.println(indent + "public void settings() { " + sizeInfo.getSettings() + " }"); -// out.println(indent + "public void settings() {"); -// out.println(indent + indent + sizeStatement); -// out.println(indent + "}"); - } - /* - if (sketchWidth != null && !hasMethod("sketchWidth")) { - // Only include if it's a number (a variable will be a problem) - if (PApplet.parseInt(sketchWidth, -1) != -1 || sketchWidth.equals("displayWidth")) { - out.println(indent + "public int sketchWidth() { return " + sketchWidth + "; }"); - } - } - if (sketchHeight != null && !hasMethod("sketchHeight")) { - // Only include if it's a number - if (PApplet.parseInt(sketchHeight, -1) != -1 || sketchHeight.equals("displayHeight")) { - out.println(indent + "public int sketchHeight() { return " + sketchHeight + "; }"); - } - } - if (sketchRenderer != null && !hasMethod("sketchRenderer")) { - // Only include if it's a known renderer (otherwise it might be a variable) - //if (PConstants.rendererList.hasValue(sketchRenderer)) { - out.println(indent + "public String sketchRenderer() { return " + sketchRenderer + "; }"); - //} - } - if (sketchOutputPath != null && !hasMethod("sketchOutputPath")) { - out.println(indent + "public String sketchOutputPath() { return " + sketchOutputPath + "; }"); } - */ if (!hasMethod("main")) { out.println(indent + "static public void main(String[] passedArgs) {"); - //out.print(indent + indent + "PApplet.main(new String[] { "); out.print(indent + indent + "String[] appletArgs = new String[] { "); if (Preferences.getBoolean("export.application.present")) { @@ -1331,11 +1199,6 @@ protected void writeFooter(PrintWriter out, String className) { } else { out.print("\"" + PApplet.ARGS_HIDE_STOP + "\", "); } -// } else { -// // This is set initially based on the system control color, just -// // sets the color for what goes behind the sketch before it's added. -// String farbe = Preferences.get("run.window.bgcolor"); -// out.print("\"" + PApplet.ARGS_BGCOLOR + "=" + farbe + "\", "); } out.println("\"" + className + "\" };"); @@ -1472,4 +1335,4 @@ private String debugHiddenTokens(antlr.CommonHiddenStreamToken t) { } return sb.toString(); } -} \ No newline at end of file +} diff --git a/java/src/processing/mode/java/preproc/SurfaceInfo.java b/java/src/processing/mode/java/preproc/SurfaceInfo.java index 6e5f57f0b8..04834de8b2 100644 --- a/java/src/processing/mode/java/preproc/SurfaceInfo.java +++ b/java/src/processing/mode/java/preproc/SurfaceInfo.java @@ -138,4 +138,15 @@ public boolean hasSettings() { public String getSettings() { return statements.join(" "); } + + + // Added for Android Mode to check whether OpenGL is in use + // https://github.com/processing/processing/issues/4441 + /** + * Return the renderer specified (null if none specified). + * @since 3.2.2 + */ + public String getRenderer() { + return renderer; + } } diff --git a/java/src/processing/mode/java/preproc/TokenUtil.java b/java/src/processing/mode/java/preproc/TokenUtil.java index e6c4721eab..71e418dd9c 100644 --- a/java/src/processing/mode/java/preproc/TokenUtil.java +++ b/java/src/processing/mode/java/preproc/TokenUtil.java @@ -2,10 +2,9 @@ import java.lang.reflect.Field; import antlr.collections.AST; -import processing.mode.java.preproc.PdeTokenTypes; /** - * + * * @author Jonathan Feinberg <jdf@pobox.com> * */ diff --git a/java/src/processing/mode/java/runner/Runner.java b/java/src/processing/mode/java/runner/Runner.java index be8845a478..5d2bbe9fef 100644 --- a/java/src/processing/mode/java/runner/Runner.java +++ b/java/src/processing/mode/java/runner/Runner.java @@ -24,15 +24,19 @@ import processing.app.*; import processing.app.exec.StreamRedirectThread; -import processing.app.ui.Editor; +import processing.app.ui.Toolkit; import processing.core.*; import processing.data.StringList; import processing.mode.java.JavaBuild; +import processing.mode.java.JavaEditor; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.io.*; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.*; import com.sun.jdi.*; @@ -58,7 +62,7 @@ public class Runner implements MessageConsumer { protected RunnerListener listener; // Running remote VM - protected VirtualMachine vm; + protected volatile VirtualMachine vm; protected boolean vmReturnedError; // Thread transferring remote error stream to our error stream @@ -68,21 +72,26 @@ public class Runner implements MessageConsumer { protected Thread outThread = null; protected SketchException exception; - protected Editor editor; + protected JavaEditor editor; protected JavaBuild build; protected Process process; protected PrintStream sketchErr; protected PrintStream sketchOut; + protected volatile boolean cancelled; + protected final Object cancelLock = new Object[0]; + public Runner(JavaBuild build, RunnerListener listener) throws SketchException { this.listener = listener; // this.sketch = sketch; this.build = build; - if (listener instanceof Editor) { - this.editor = (Editor) listener; + checkLocalHost(); + + if (listener instanceof JavaEditor) { + this.editor = (JavaEditor) listener; sketchErr = editor.getConsole().getErr(); sketchOut = editor.getConsole().getOut(); } else { @@ -115,6 +124,29 @@ public Runner(JavaBuild build, RunnerListener listener) throws SketchException { } + /** + * Has the user screwed up their hosts file? + * https://github.com/processing/processing/issues/4738 + */ + static private void checkLocalHost() throws SketchException { + try { + InetAddress address = InetAddress.getByName("localhost"); + if (!address.getHostAddress().equals("127.0.0.1")) { + System.err.println("Your computer is not properly mapping 'localhost' to '127.0.0.1',"); + System.err.println("which prevents sketches from working properly because 'localhost'"); + System.err.println("is needed to connect the PDE to your sketch while it's running."); + System.err.println("If you don't recall making this change, or know how to fix it:"); + System.err.println("https://www.google.com/search?q=add+localhost+to+hosts+file+" + Platform.getName()); + throw new SketchException("Cannot run due to changes in your 'hosts' file. " + + "See the console for details.", false); + } + + } catch (UnknownHostException e) { + e.printStackTrace(); + } + } + + public VirtualMachine launch(String[] args) { if (launchVirtualMachine(false, args)) { generateTrace(); @@ -190,6 +222,13 @@ public boolean launchVirtualMachine(boolean present, String[] args) { commandArgs.append(vmParams); commandArgs.append(sketchParams); + + // Opportunistically quit if the launch was cancelled, + // the next chance to cancel will be after connecting to the VM + if (cancelled) { + return false; + } + launchJava(commandArgs.array()); AttachingConnector connector = (AttachingConnector) @@ -220,21 +259,37 @@ public boolean launchVirtualMachine(boolean present, String[] args) { // while (!available) { while (true) { try { - vm = connector.attach(arguments); + Messages.log(getClass().getName() + " attempting to attach to VM"); + synchronized (cancelLock) { + vm = connector.attach(arguments); + if (cancelled && vm != null) { + // cancelled and connected to the VM, handle closing now + Messages.log(getClass().getName() + " aborting, launch cancelled"); + close(); + return false; + } + } // vm = connector.attach(arguments); if (vm != null) { + Messages.log(getClass().getName() + " attached to the VM"); // generateTrace(); // available = true; return true; } - } catch (IOException e) { + } catch (ConnectException ce) { + // This will fire ConnectException (socket not available) until + // the VM finishes starting up and opens its socket for us. + Messages.log(getClass().getName() + " socket for VM not ready"); // System.out.println("waiting"); // e.printStackTrace(); try { Thread.sleep(100); - } catch (InterruptedException e1) { - e1.printStackTrace(sketchErr); + } catch (InterruptedException ie) { + Messages.loge(getClass().getName() + " interrupted", ie); +// ie.printStackTrace(sketchErr); } + } catch (IOException e) { + Messages.loge(getClass().getName() + " while attaching to VM", e); } } // } catch (IOException exc) { @@ -286,9 +341,12 @@ protected StringList getMachineParams() { } if (Platform.isMacOS()) { + // This successfully sets the application menu name, + // but somehow, not the dock name itself. params.append("-Xdock:name=" + build.getSketchClassName()); -// params.add("-Dcom.apple.mrj.application.apple.menu.about.name=" + -// sketch.getMainClassName()); + // No longer needed / doesn't seem to do anything differently + //params.append("-Dcom.apple.mrj.application.apple.menu.about.name=" + + // build.getSketchClassName()); } // sketch.libraryPath might be "" // librariesClassPath will always have sep char prepended @@ -321,7 +379,9 @@ protected StringList getSketchParams(boolean present, String[] args) { } else { params.append("processing.core.PApplet"); - // get the stored device index (starts at 1) + // Get the stored device index (starts at 1) + // By default, set to -1, meaning 'the default display', + // which is the same display as the one being used by the Editor. int runDisplay = Preferences.getInteger("run.display"); // If there was a saved location (this guy has been run more than once) @@ -341,20 +401,23 @@ protected StringList getSketchParams(boolean present, String[] args) { // Make sure the display set in Preferences actually exists GraphicsDevice runDevice = editorDevice; if (runDisplay > 0 && runDisplay <= devices.length) { - runDevice = devices[runDisplay-1]; + runDevice = devices[runDisplay-1]; } else { - // If a bad display is selected, use the same display as the editor + // If a bad display (or -1 display) is selected, use the same display as the editor if (runDisplay > 0) { // don't complain about -1 or 0 System.err.println("Display " + runDisplay + " not available."); } runDevice = editorDevice; for (int i = 0; i < devices.length; i++) { if (devices[i] == runDevice) { + // Prevent message on the first run + if (runDisplay != -1) { + System.err.println("Setting 'Run Sketches on Display' preference to display " + (i+1)); + } + runDisplay = i + 1; // Wasn't setting the pref to avoid screwing things up with // something temporary. But not setting it makes debugging one's // setup just too damn weird, so changing that behavior. - runDisplay = i + 1; - System.err.println("Setting 'Run Sketches on Display' preference to display " + runDisplay); Preferences.setInteger("run.display", runDisplay); break; } @@ -412,6 +475,10 @@ protected StringList getSketchParams(boolean present, String[] args) { // removed for 3.0a6 because it would break the args passed to sketches. params.append(PApplet.ARGS_SKETCH_FOLDER + "=" + build.getSketchPath()); + if (Toolkit.zoom(100) >= 200) { // Use 100 to bypass possible rounding in zoom() + params.append(PApplet.ARGS_DENSITY + "=2"); + } + params.append(build.getSketchClassName()); } // Add command-line arguments to be given to the sketch itself @@ -487,29 +554,28 @@ protected void generateTrace() { //vm.setDebugTraceMode(debugTraceMode); // vm.setDebugTraceMode(VirtualMachine.TRACE_ALL); // vm.setDebugTraceMode(VirtualMachine.TRACE_NONE); // formerly, seems to have no effect - - // Calling this seems to set something internally to make the - // Eclipse JDI wake up. Without it, an ObjectCollectedException - // is thrown on excReq.enable(). No idea why this works, - // but at least exception handling has returned. (Suspect that it may - // block until all or at least some threads are available, meaning - // that the app has launched and we have legit objects to talk to). - vm.allThreads(); - // The bug may not have been noticed because the test suite waits for - // a thread to be available, and queries it by calling allThreads(). - // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example. - - EventRequestManager mgr = vm.eventRequestManager(); - // get only the uncaught exceptions - ExceptionRequest excReq = mgr.createExceptionRequest(null, false, true); -// System.out.println(excReq); - // this version reports all exceptions, caught or uncaught -// ExceptionRequest excReq = mgr.createExceptionRequest(null, true, true); - // suspend so we can step - excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL); -// excReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); -// excReq.setSuspendPolicy(EventRequest.SUSPEND_NONE); // another option? - excReq.enable(); + try { + // Calling this seems to set something internally to make the + // Eclipse JDI wake up. Without it, an ObjectCollectedException + // is thrown on excReq.enable(). No idea why this works, + // but at least exception handling has returned. (Suspect that it may + // block until all or at least some threads are available, meaning + // that the app has launched and we have legit objects to talk to). + vm.allThreads(); + // The bug may not have been noticed because the test suite waits for + // a thread to be available, and queries it by calling allThreads(). + // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example. + + EventRequestManager mgr = vm.eventRequestManager(); + // get only the uncaught exceptions + ExceptionRequest excReq = mgr.createExceptionRequest(null, false, true); + // this version reports all exceptions, caught or uncaught + // suspend so we can step + excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL); + excReq.enable(); + } catch (VMDisconnectedException ignore) { + return; + } Thread eventThread = new Thread() { public void run() { @@ -574,7 +640,9 @@ public void run() { // or the user manually closes the sketch window. // TODO this should be handled better, should it not? if (editor != null) { - editor.deactivateRun(); + java.awt.EventQueue.invokeLater(() -> { + editor.onRunnerExiting(Runner.this); + }); } } catch (InterruptedException exc) { // we don't interrupt @@ -643,7 +711,9 @@ public void exceptionEvent(ExceptionEvent event) { handleCommonErrors(exceptionName, message, listener, sketchErr); if (editor != null) { - editor.deactivateRun(); + java.awt.EventQueue.invokeLater(() -> { + editor.onRunnerExiting(Runner.this); + }); } } @@ -696,9 +766,9 @@ public static boolean handleCommonErrors(final String exceptionClass, } else if (exceptionClass.equals("java.lang.UnsupportedClassVersionError")) { listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java."); - err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.6 or earlier."); - err.println("A library used by this sketch was compiled for Java 1.7 or later, "); - err.println("and needs to be recompiled to be compatible with Java 1.6."); + err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.8 or earlier."); + err.println("A library used by this sketch was compiled for Java 1.9 or later, "); + err.println("and needs to be recompiled to be compatible with Java 1.8."); } else if (exceptionClass.equals("java.lang.NoSuchMethodError") || exceptionClass.equals("java.lang.NoSuchFieldError")) { @@ -811,19 +881,22 @@ protected SketchException findException(String message, ObjectReference or, Thre public void close() { - // TODO make sure stop() has already been called to exit the sketch + synchronized (cancelLock) { + cancelled = true; + + // TODO make sure stop() has already been called to exit the sketch - // TODO actually kill off the vm here - if (vm != null) { - try { - vm.exit(0); + // TODO actually kill off the vm here + if (vm != null) { + try { + vm.exit(0); - } catch (com.sun.jdi.VMDisconnectedException vmde) { - // if the vm has disconnected on its own, ignore message - //System.out.println("harmless disconnect " + vmde.getMessage()); - // TODO shouldn't need to do this, need to do more cleanup + } catch (com.sun.jdi.VMDisconnectedException vmde) { + // if the vm has disconnected on its own, ignore message + //System.out.println("harmless disconnect " + vmde.getMessage()); + // TODO shouldn't need to do this, need to do more cleanup + } } - vm = null; } } @@ -844,7 +917,9 @@ synchronized public void message(String s) { if (editor != null) { // editor.internalCloseRunner(); // [091124] // editor.handleStop(); // prior to 0192 - editor.internalCloseRunner(); // 0192 + java.awt.EventQueue.invokeLater(() -> { + editor.internalCloseRunner(); // 0192 + }); } return; } diff --git a/java/src/processing/mode/java/tweak/SketchParser.java b/java/src/processing/mode/java/tweak/SketchParser.java index fd2843d87a..d2a85e0504 100644 --- a/java/src/processing/mode/java/tweak/SketchParser.java +++ b/java/src/processing/mode/java/tweak/SketchParser.java @@ -117,7 +117,7 @@ private void addAllDecimalNumbers() { Pattern p = Pattern.compile("[\\[\\{<>(),\\t\\s\\+\\-\\/\\*^%!|&=?:~]\\d+\\.?\\d*"); for (int i = 0; i < codeTabs.length; i++) { - List handles = new ArrayList(); + List handles = new ArrayList<>(); allHandles.add(handles); String c = codeTabs[i]; @@ -327,7 +327,7 @@ private void addAllWebColorNumbers() { private ArrayList findAllColorModes() { - ArrayList modes = new ArrayList(); + ArrayList modes = new ArrayList<>(); for (int i=0; i colorBox = new ArrayList(); + List colorBox = new ArrayList<>(); colorBoxes.add(colorBox); String tab = codeTabs[i]; Matcher m = p.matcher(tab); while (m.find()) { - ArrayList colorHandles = new ArrayList(); + ArrayList colorHandles = new ArrayList<>(); // look for the '(' and ')' positions int openPar = tab.indexOf("(", m.start()); @@ -459,7 +459,7 @@ private void createColorBoxesForLights() { Matcher m = p.matcher(tab); while (m.find()) { - ArrayList colorHandles = new ArrayList(); + ArrayList colorHandles = new ArrayList<>(); // look for the '(' and ')' positions int openPar = tab.indexOf("(", m.start()); @@ -558,7 +558,7 @@ private ColorMode getColorModeForContext(String context) { private void handleMultipleColorModes() { // count how many color modes per context - Map modeCount = new HashMap(); + Map modeCount = new HashMap<>(); for (ColorMode cm : colorModes) { Integer prev = modeCount.get(cm.drawContext); if (prev == null) { @@ -568,7 +568,7 @@ private void handleMultipleColorModes() { } // find the contexts that have more than one color mode - ArrayList multipleContexts = new ArrayList(); + ArrayList multipleContexts = new ArrayList<>(); Set allContexts = modeCount.keySet(); for (String context : allContexts) { if (modeCount.get(context) > 1) { @@ -579,7 +579,7 @@ private void handleMultipleColorModes() { // keep only hex and web color boxes in color calls // that belong to 'multipleContexts' contexts for (int i = 0; i < codeTabs.length; i++) { - List toDelete = new ArrayList(); + List toDelete = new ArrayList<>(); for (String context : multipleContexts) { for (ColorControlBox ccb : colorBoxes.get(i)) { if (ccb.drawContext.equals(context) && !ccb.isHex) { @@ -597,7 +597,7 @@ private List> getAllScientificNotations() { Pattern p = Pattern.compile("[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?[eE][+\\-]?\\d+"); for (String code : codeTabs) { - List notation = new ArrayList(); + List notation = new ArrayList<>(); Matcher m = p.matcher(code); while (m.find()) { notation.add(new Range(m.start(), m.end())); @@ -767,7 +767,7 @@ private boolean isGlobal(int pos, int codeTabIndex) { static private List getCommentBlocks(String code) { - List commentBlocks = new ArrayList(); + List commentBlocks = new ArrayList<>(); int lastBlockStart=0; boolean lookForEnd = false; diff --git a/todo.txt b/todo.txt old mode 100755 new mode 100644 index 5e7d747376..3cdc06d422 --- a/todo.txt +++ b/todo.txt @@ -1,103 +1,167 @@ -0253 (3.2.1) -X "Could not replace preferences.old" error message -X https://github.com/processing/processing/issues/4626 -X Version 3.2 won't run from paths with spaces on Windows -X https://github.com/processing/processing/issues/4623 -X might be ext.dirs trouble with spaces in path names? -X or the backwards slashes? -X fixes for Python Mode crashing on startup -X disable ext.dirs on Linux export and set jna.nosys as well -X Java not included properly with 32-bit Linux export -X JavaInputHandler not registering - - -_ library compilations handled oddly -_ https://github.com/processing/processing/issues/4630 +0271 (3.5.5 unlikely) +X get the jre download to work by using a cached copy +X https://github.com/processing/processing/issues/5827 +X https://github.com/processing/processing/issues/5860 +X https://github.com/processing/processing/issues/5942 +X https://github.com/processing/processing/issues/6089 + +contribs +X rename-variable menu allows Java identifiers +X https://github.com/processing/processing/issues/5828 +X https://github.com/processing/processing/pull/5906 +X Replace C/C++ style array declarations with Java style array declarations +X https://github.com/processing/processing/pull/5981 +X Updates and fixes for PDE_pt.properties (Portugese translation) +X https://github.com/processing/processing/pull/6097 +X https://github.com/processing/processing/pull/6098 + + +from Casey +_ Issue with https and downloading the binaries, +Checksums? +_ https://github.com/processing/processing-docs/issues/766 +_ Math for BLEND incorrect in the reference? +_ https://github.com/processing/processing-docs/issues/762 +_ .setAngle() for PVector? +_ https://github.com/processing/processing-docs/issues/744 +_ Installation on Linux +_ https://github.com/processing/processing-docs/issues/645 +_ How much of the attrib*() functions should be documented? +_ https://github.com/processing/processing-docs/issues/172 + +_ "Could not get the settings folder" isn't very helpful +_ https://github.com/processing/processing/issues/5744 +_ need to check the locations it'd be writing to, and see if available +_ then tell the user which folder to fix + +_ i18n support for Modes +_ https://github.com/processing/processing/commit/0ed2fc139c3c5dfe0a1702ed8348987b3c6a5c9d + +_ show the recommended sw version on the download page +_ just skip the welcome screen on Windows hidpi dipslays? + +_ refresh option for sketchbook +_ import option for sketchbook +_ 'show sketch folder' weird when in temp folder +_ ask to save first (sketch has not been saved yet) +_ same with adding files to an unsaved sketch, do we block that? + + +contrib +_ Saving sketch with the same name as a class +_ https://github.com/processing/processing/pull/4033 +_ Pasting text into PDE results in "Clipboard does not contain a string" +_ https://github.com/processing/processing/pull/4040 -_ update launch4j to 3.9 -_ https://sourceforge.net/projects/launch4j/files/launch4j-3/3.9/ -_ editor windows always open on display 1 -_ https://github.com/processing/processing/issues/1566 +high +_ windows anti-malware leaves browser stuck at 100% +_ https://github.com/processing/processing/issues/5893 +_ run button not deactivating +_ https://github.com/processing/processing/issues/5786 +_ Find in Reference disabled for various keywords (draw, for, if, catch, while) +_ https://github.com/processing/processing/issues/5562 +_ https://github.com/processing/processing/pull/5642 +_ sketch window placement not recorded +_ https://github.com/processing/processing/issues/5781 +_ errors inside setup() aren't coming through at all? +_ seen in Eclipse; have to turn on the debugger... same as #4703? +_ Welcome screen doesn't size properly for HiDPI screens +_ https://github.com/processing/processing/issues/4896 +_ sketch window resets position after each run (regression from 3.4?) +_ https://github.com/processing/processing/issues/5781 + + +temp +_ inside Sketch, makeTempFolder() would be the place to modify the location +_ perhaps make a 'temp' inside the sketchbook folder? +_ on startup, check to see if there are a lot of files, remove them? +_ or maybe auto-delete once older than 24 hours? +_ also don't search it when walking the sketchbook +_ untitled folders are stored in temp folder +_ add a note about temp dir to the bug on windows temp dirs +_ move away from using a temp dir at all for sketches +_ -Djava.io.tmpdir=Z:\temp +_ clean up /tmp folders used during build +_ https://github.com/processing/processing/issues/1896 +_ don't let people into the /tmp folder for sketches +o don't use tmp folder for sketches? +_ restrict more things like "show sketch folder" +_ don't allow adding files w/o saving +_ others? +_ clean Windows temp folders +_ https://github.com/processing/processing/issues/1896 +_ could not write to temporary directory (virus checker problems) +_ https://github.com/processing/processing/issues/4757 + +modes +_ sketch.properties not being written if initial mode is p5.js? +_ when creating a sketch within non-Java mode, should write the settings file +_ so that it re-loads in the proper environment +_ remove sketch.properties when moving back to the default? +_ or can we not do this, because it's used to set the 'next' mode _ allow modes to specify their own base file name _ need to move "is this a sketch?" handling into Mode +_ fix extension check for other modes +_ https://github.com/processing/processing/issues/3980 +_ mode list does not update after changing sketchbook folder +_ already reported? -_ blank window on startup where the "welcome" screen should be -_ https://github.com/processing/processing/issues/3933 - -_ modify line number color when no lines extend that far? -_ https://github.com/processing/processing/pull/4560 -_ text gutter doesn't seem to be hidpi -X or is it b/c screen not quite 2x? (nope) -_ swap out the fonts? - -_ Help Menu disabled on OS X -_ https://github.com/processing/processing/issues/4353#issuecomment-237715947 +sketch/launching +_ what to double-click when opening p5 projects +_ lack of a project file makes this a pain +_ dropping a sketch folder onto the PDE should also be implemented +_ some type of sketch archive format for posting examples (.psk?) +_ would be nice to open a sketch directly from a zip file +_ https://github.com/processing/processing/issues/73 +_ maybe just open from a zip file, since psk doesn't help anything +_ also have a means of importing sketches +_ https://github.com/processing/processing/issues/3987 +_ also see several notes below re: examples +_ add means to import .zip files from file/url into sketchbook, library, etc. +_ super easy given current code implementation, might help usability +_ put the reference (and examples?) into .zip files +_ unzipping the app takes forever +_ see the 'examples' section below +_ how are file associations handled in Linux? (for .pde, .psk) -high -_ Pasting code from editor to empty editor produces Exception -_ https://github.com/processing/processing/issues/4522 -_ possible infinite loop on modified externally -_ https://github.com/processing/processing/issues/3965 -medium -_ detect changes in case with libraries -_ https://github.com/processing/processing/issues/4507 -_ make when opening new editor window, open on the same display as current -_ https://github.com/processing/processing/issues/4526 -_ hidpi scaling via font changes? -_ http://stackoverflow.com/a/34152675 -_ hi-dpi support on Linux -_ https://github.com/processing/processing/issues/4183 -_ PDE and sketches are 2x smaller on high-res Windows machines -_ https://github.com/processing/processing/issues/2411 -_ System.setProperty("sun.java2d.dpiaware", "false"); -_ though that seems broken in Java 8: http://superuser.com/a/1007783 +teaching +_ teacher wants user input on the console +_ https://github.com/processing/processing/issues/5779 _ did we lose settings.path because it was too buggy? _ https://github.com/processing/processing/issues/3948 -_ Library path mismatch between processing-java and export -_ https://github.com/processing/processing/issues/4493 +_ proxy trouble with p5? since adding the system proxy? +_ https://github.com/processing/processing/pull/3251/files +_ larger problem thread https://github.com/processing/processing/issues/3891 +_ ideen2011.blogspot.de/2011/08/java-proxyselector-usesystemproxies-and.html +_ malformed proxy issues http://stackoverflow.com/q/376101 +_ docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html +_ https://github.com/processing/processing/issues/1476#issuecomment-23229990 -shortcuts -_ ctrl-J (for debugger) is inserting newline -_ https://github.com/processing/processing/issues/3830 -_ problems with non-US keyboards and some shortcuts -_ https://github.com/processing/processing/issues/2199 -_ Determine shortcut for Export vs Use Selection for Find -_ https://github.com/processing/processing/issues/2985 -_ Determine new keyboard shortcut for Step Out -_ https://github.com/processing/processing/issues/3538 +_ "Required files could not be found" when trying to run from the .zip file +_ https://github.com/processing/processing/issues/5022 +_ use an installer instead? -needs more review -_ createPreprocessor() added to JavaEditor, creating a mess -_ https://github.com/processing/processing/commit/2ecdc36ac7c680eb36e271d17ad80b657b3ae6a0 -_ patch to core classpath by Manindra? +_ "error during export" message, but no error message contents come through +_ e.g. https://github.com/processing/processing/issues/4792 -_ spacing of the updates number/circle in the lower right is off -_ https://github.com/processing/processing/issues/4094 -_ https://github.com/processing/processing/pull/4097 +_ library compilations not ordered properly w/ sorting +_ do we still support library compilations? that was from 2016 +_ https://github.com/processing/processing/issues/4630 -_ need docs for translations -_ https://github.com/processing/processing/issues/4018 +_ editor windows always open on display 1 +_ https://github.com/processing/processing/issues/1566 -_ setting a bad font/size causes a crash on startup -_ https://github.com/processing/processing/issues/4085 -o https://github.com/processing/processing/pull/4087 + +needs review +_ createPreprocessor() added to JavaEditor, creating a mess +_ https://github.com/processing/processing/commit/2ecdc36ac7c680eb36e271d17ad80b657b3ae6a0 +_ patch to core classpath by Manindra? -more contribs -_ question about PDE_pt-br instead of PDE_pt -_ https://github.com/processing/processing/issues/4018 -_ Saving sketch with the same name as a class -_ https://github.com/processing/processing/pull/4033 -_ infinite "file changed" popups -_ https://github.com/processing/processing/issues/3965 -_ https://github.com/processing/processing/pull/4037 -_ Pasting text into PDE results in "Clipboard does not contain a string" -_ https://github.com/processing/processing/pull/4040 known issues _ launch4j doesn't work from folders with non-native charsets @@ -106,23 +170,28 @@ _ but anything else reports "font sadness" b/c it's using the system JRE _ https://github.com/processing/processing/issues/3543 _ move to javapackager or another option? _ http://www.excelsiorjet.com/kb/35/howto-create-a-single-exe-from-your-java-application +_ Export Application fails on machines w/ non-ASCII chars in user name +_ at least give a warning about this? +_ https://github.com/processing/processing/issues/4736 +_ related: https://github.com/processing/processing/issues/3543 _ mouse events (i.e. toggle breakpoint) seem to be firing twice -run/debug -_ Tweak Mode sometimes freezes while running, require a force quit -_ https://github.com/processing/processing/issues/3928 -_ TweakMode listener mess in JavaTextArea -_ https://github.com/processing/processing/issues/4605 - - gui +_ spacing of the updates number/circle in the lower right is off +_ https://github.com/processing/processing/issues/4094 +_ https://github.com/processing/processing/pull/4097 +_ solution is to create a sprite sheet as a psd that'll have better type +_ no way we're gonna fix the sizing and spacing for all platforms +_ more than a certain amount should just be 10+, +, or whatever +_ text gutter doesn't seem to be hidpi +X or is it b/c screen not quite 2x? (nope) _ Tooltip over variable decl has wrong style and content _ make all tooltips run through our style _ https://github.com/processing/processing/issues/3940 _ import suggestions box needs design review _ https://github.com/processing/processing/issues/3407 -_ fix background color for selected lines in VariableInspector +_ fix background color for selected lines in VariableInspector _ https://github.com/processing/processing/issues/3925 _ implement 2x versions of the icons for the debugger window/variable inspector _ https://github.com/processing/processing/issues/3921 @@ -145,27 +214,33 @@ _ rather than post-compile _ https://github.com/processing/processing/issues/136 -welcome -_ click "show this welcome" text to check/uncheck the box -_ https://github.com/processing/processing/issues/3912 -_ submit the form (as if 'get started' clicked) when closing the window -_ whether hitting ESC or the close box on the window -_ https://github.com/processing/processing/issues/3911 - - fonts _ fonts are still really ugly (on non-retina) _ may need to drop use of Source Sans _ what do these do, and are we doing it already? _ System.setProperty("awt.useSystemAAFontSettings","on"); _ System.setProperty("swing.aatext", "true"); -_ how are we going to handle fonts for other languages? +_ how are we going to handle fonts for other languages? _ two new fonts have been added, other languages will need more _ need a decent sans with with Unicode coverage _ i.e. https://github.com/processing/processing/pull/3025 +_ Implement fallback fonts so we can use Source et al with CJK/Greek/Arabic +_ https://github.com/processing/processing/issues/5023 pde/build +_ update list of optional JRE files for Java 8 +_ Andres provided some updates +_ https://github.com/processing/processing/issues/3288 +_ these will change again for Java 11, so wait until then +_ fix appbundler problems due to rollback +_ https://github.com/processing/processing/issues/3790 +_ the rollback re-introduces two bugs (serial export and scrolling) +_ and any other changes later than 16 November 2014: +_ https://github.com/processing/processing/commits/master/build/macosx/appbundler.jar +_ https://github.com/processing/processing/commits/master/build/macosx/appbundler/native/main.m +_ https://github.com/processing/processing/commit/fa27b983e76fdbc5c4c1451a1f0d854c652b1639 +_ https://bitbucket.org/infinitekind/appbundler _ unsupported java version when trying ant run with 7u65 _ no helpful message about how to automatically download 8u51 _ ignore-tools in build.xml not being called for some reason @@ -189,8 +264,6 @@ _ https://github.com/processing/processing/issues/3843 _ clean out the repo _ https://github.com/processing/processing/issues/1898 _ search the source for 'applet' references (i.e. SVG docs) -_ update list of optional JRE files -_ https://github.com/processing/processing/issues/3288 _ PreferencesFrame is a misnomer (not a frame itself) _ change to PreferencesDialog, and make it a dialog? _ move Library to LibraryContribution and into contrib? @@ -208,29 +281,15 @@ _ don't allow users to create 'blah.java' when 'blah.pde' already in sketch sketchbook -_ Mode.rebuildLibraryList() called too many times on startup? +_ Mode.rebuildLibraryList() called too many times on startup? _ and when sketches saved as well? _ makes saving *really* slow with a lot of libraries -_ need to handle the 2.x to 3.x sketchbook transition -_ prefs are the same file, but sketchbook location pref is different _ New/Rename/Save As is reloading the whole sketchbook, argh -_ sketchbook window doesn't update when sketches are added, renamed, etc -_ https://github.com/processing/processing/issues/2944 -_ possible PR for updating sketchbook stuff -_ https://github.com/processing/processing/pull/3081 _ improve start time by populating sketchbook/libraries on threads _ https://github.com/processing/processing/issues/2945 -_ longer PR about sketchbook stuff, but closed -_ https://github.com/processing/processing/pull/3178 help me -_ Horizontal scrollbar does not scroll textarea all the way -_ https://github.com/processing/processing/issues/3591 -_ clean up 'ant doc' target to remove warnings -_ https://github.com/processing/processing/issues/1492 -_ fix encodings, line endings, and mime types in the repo -_ https://github.com/processing/processing/issues/2955 _ Add support for localizing contributions _ https://github.com/processing/processing/pull/2833 _ https://github.com/processing/processing/issues/3154 @@ -241,6 +300,10 @@ _ might be something with libraries (native or otherwise) medium +_ detect changes in case with libraries +_ https://github.com/processing/processing/issues/4507 +_ Library path mismatch between processing-java and export +_ https://github.com/processing/processing/issues/4493 _ remove toolbar menu references and code to rebuild _ fix single instance server on OS X to load double-clicked files _ when run from Eclipse, the single instance thing punts @@ -269,7 +332,7 @@ _ the Find window (also the save windows) also have the same problem _ move old Google Code SVN back to processing.org _ then cull out the old branches/tags from the Github repo _ and/or start bundling separate source downloads -_ look through all isPopupTrigger() code +_ look through all isPopupTrigger() code _ make sure both press/release are implemented _ emacs style errors in commander aren't quite right _ https://github.com/processing/processing/issues/2158 @@ -279,7 +342,7 @@ _ modes are being loaded multiple times, which can cause trouble _ add minimum version required (or max version?) to libraries/modes/etc -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DOC / Misc @@ -307,7 +370,7 @@ _ and that java2d should complain if people try it _ method to go from function name to the included examples where used? _ encourage use of set() instead of point() in the drawing api _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114204116 -_ other projects on which p5 is built +_ other projects on which p5 is built _ no longer oro matcher and jikes _ add: quaqua, jna, registry stuff, .. ? _ noLoop() isn't the same as "finished", though it's sometimes used that way @@ -328,7 +391,6 @@ _ problem with big floats: http://processing.org/discourse/yabb/YaBB.cgi?board _ problem with small floats: http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1115500448 _ console stored in prefs location _ console may be useful for debugging -_ untitled folders are stored in temp folder DOC / Text @@ -343,12 +405,12 @@ _ textMode(SCREEN) for P2D and P3D for nice fast text in screen space _ currently slow in JAVA2D and OPENGL, but this will improve _ what is the vlw font file format? _ shapes from 3D type -_ the way to do it (will improve later) is to use some undocumented features -_ 1) you have to use the OPENGL renderer -_ 2) use textMode(SHAPE); -_ 3) use createFont() (which you already are) -_ this will convert all the shape data from the fonts for writing. -_ it will be *extremely* slow, which is part of why it's not documented yet. +_ the way to do it (will improve later) is to use some undocumented features +_ 1) you have to use the OPENGL renderer +_ 2) use textMode(SHAPE); +_ 3) use createFont() (which you already are) +_ this will convert all the shape data from the fonts for writing. +_ it will be *extremely* slow, which is part of why it's not documented yet. _ but it will work with beginRaw(). _ improve documentation of the pdf stuff _ be clearer about the font setup stuff @@ -357,16 +419,13 @@ _ fonts by default not working that well? DOC / Other -_ why adding .0001 to a float doesn't work -_ and how they're imprecise in general (use nf) -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1130877990 _ why strong typing? (link also to language thing on main page) _ we cannot commit to any sort of timeframe on releases _ under the hood - basic _ it's all java _ don't use awt _ most things are imported by default -_ under the hood - complex +_ under the hood - complex _ how to get started with coding _ everything subclasses PApplet _ if you need a particular name, add it with "extends PApplet" @@ -376,16 +435,8 @@ _ in doing so, you'll lose access to 'g' _ add main() to your app to make it run on its own _ preproc stuff.. have to make setup() into public void setup() _ (same for key events and all that) -_ performance -_ video stinks.. java2d stinks.. macs stink -_ note in the 'drawing in 2d' section of faq -_ fastest machine possible -_ turn off hyperthreading in the bios -_ nice gfx card only helps opengl -_ dual processor not particularly useful, unless you make more threads -_ but making more threads is often more work than is useful _ is there a way to do xxx? -_ advanced users who are outgrowing the basic reference: +_ advanced users who are outgrowing the basic reference: _ be sure to check the "complete" reference _ change bugs.html to issues.html _ and add a redirect in httpd.conf @@ -418,10 +469,10 @@ _ write an example that uses HashMap (or Hashtable) _ write an example that uses ArrayList properly _ get xml library example in there _ simple method for having a clickable region or sprite with rollover -_ post to web example +_ post to web example _ particularly for uploading image data _ along with php script to handle receive -_ this is in hacks, but +_ this is in hacks, but _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=VideoCamera;action=display;num=1117194066#7 @@ -504,7 +555,7 @@ _ link out to further documentation (e.g. AIOOBE, NPE) low (common errors around reserved names/class naming) _ Saving sketch with the same name as a class or primitive breaks sketch _ https://github.com/processing/processing/issues/196 -_ don't allow people to override methods like paint() +_ don't allow people to override methods like paint() _ make them final? just improve the error messages? _ https://github.com/processing/processing/issues/1058 _ Processing chokes if a sketch defines a class with same name as the sketch @@ -518,25 +569,12 @@ _ https://github.com/processing/processing/issues/533 PDE / Editor -_ clean up /tmp folders used during build -_ https://github.com/processing/processing/issues/1896 _ 'recent' menu doesn't respect examples folder of other p5 versions _ could write that into the file, that it's an example _ or write the path as shown in the PDE to the file as simpler _ 'recent' menu paths can get enormous -_ don't let people into the /tmp folder for sketches -o don't use tmp folder for sketches? -_ restrict more things like "show sketch folder" -_ don't allow adding files w/o saving -_ others? -_ when creating a sketch within non-Java mode, should write the settings file -_ so that it re-loads in the proper environment -_ remove sketch.properties when moving back to the default? -_ or can we not do this, because it's used to set the 'next' mode -_ add means to import .zip files from file/url into sketchbook, library, etc. -_ super easy given current code implementation, might help usability _ active editor not being set null -_ in Base.nextEditorLocation(), changed to "editors.size() == 0" +_ in Base.nextEditorLocation(), changed to "editors.size() == 0" _ instead of (activeEditor == null), but that's papering over a problem _ where the active editor is not being set null _ renaming RGB (.pde) to Rgb.java says "a file named RGB.pde already exists" @@ -587,16 +625,16 @@ _ or don't allow it to be exported _ add bug reference to the faq once added to the db X or at least add a note about this to the faq _ show error when no main() is included but class extends PApplet -_ error can happen or be checked -_ exporting application copies .java files +_ error can happen or be checked +_ exporting application copies .java files _ .java files are copied to the root folder as well as the source folder PDE / Examples -_ keep examples.zip in a zip file? (5000 files @ 30 MB instead of 15 MB zip) -_ mark examples as untitled (rather than read-only) -_ maybe even pull these directly from the zip file? +o keep examples.zip in a zip file? (5000 files @ 30 MB instead of 15 MB zip) +o mark examples as untitled (rather than read-only) +o maybe even pull these directly from the zip file? _ load examples from zip files _ https://github.com/processing/processing/issues/182 _ don't make examples read-only @@ -616,11 +654,13 @@ _ see how library installation goes, then possibly do same w/ examples PDE / Libraries +_ alternate handling of duplicate library conflicts +_ https://github.com/processing/processing/pull/5126 _ Add a means to specify packages to import in library.properties _ https://github.com/processing/processing/issues/2134 _ need to deal with classpath conflicts _ avoid garbage that people have installed on their machines -_ antlr.jar in the classpath will cause trouble.. +_ antlr.jar in the classpath will cause trouble.. _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1138652326 _ jogl jar files, or jogl install will cause trouble _ /System/Library/Java/Extensions or /Library/Java/Extensions @@ -641,12 +681,12 @@ _ i.e. even if not specified, the stuff will be in the classpath _ need to make classpath code be less promiscuous _ the order of adding libraries to classpath should be opposite _ the important local libraries should be first in cp, user contrib later -_ make sure there aren't library jar files named the same thing +_ make sure there aren't library jar files named the same thing _ i.e. if one library has db.jar, then that's gonna kill another db.jar _ when the files are copied over _ java.ext.dirs for /System/Library/Java/Extensions _ http://java.sun.com/j2se/1.5.0/docs/guide/extensions/spec.html -_ can set java.ext.dirs to something else +_ can set java.ext.dirs to something else _ on osx, just ignore anything in /Library/Java/Extensions (but not others)? _ native lib stuff, use native.txt in lib folder, then: _ String osName = System.getProperty("os.name"); @@ -658,6 +698,30 @@ _ e.g. ocd is broken in 0125 because of method signature changes PDE / Manager +_ Manager fails to complete install of PythonMode when no windows open +_ https://github.com/processing/processing/issues/5309 +_ Python Mode not downloading? +_ https://github.com/processing/processing/issues/5918 +_ an incompatible Mode prevents the PDE from quitting after last window is closed +_ https://github.com/processing/processing/issues/5112 +_ “could not move the contribution to the backup folder” message while updating +_ problem is that any sketch that uses a library, the lib is stuck as "in use" +_ https://github.com/processing/processing/issues/4973 +_ issues with updating modes +_ https://github.com/processing/processing/issues/5424 +_ examples window not updating on install +_ open examples window +_ mode > add mode > libraries > install video +_ did not update the examples window, had to restart pde +_ was able to save over the video capture examples b/c they were a library +_ lib examples not properly marked as read-only +_ "Could not find a examples in the downloaded file" is a poorly worded message +_ 'version' should be x.y or x.y.z, not some extra long string +_ enforce this by disallowing spaces? on the import script? +_ Progress bar height on macOS is too thin +_ https://github.com/processing/processing/issues/4734 +_ proper error handling when downloading contribs listing +_ https://github.com/processing/processing/issues/4732 _ update CM entries when sketchbook location changes _ https://github.com/processing/processing/issues/3927 _ ugly white gap at the top of scroll bar @@ -679,10 +743,10 @@ _ why wasn't Library moved to LibraryContribution? _ or that LibraryContribution needs to be a wrapper around it? _ send info on 'check for updates' so we know about libs/modes/etc? _ how to disclose to users? -_ only send for items that are part of the public list +_ only send for items that are part of the public list _ otherwise we're sending private libraries/installs _ although this won't pick up old libraries not on the new system -_ classpath conflicts.. +_ classpath conflicts.. _ getPackageList.. from Library... maybe others? _ really need to make sure that a weird core.jar isn't being imported _ coffeescript was doing this and breaking the pde @@ -698,8 +762,6 @@ _ "Update 4 items" as a button name _ new libraries not picked up when changing sketchbook location _ make sure contrib manager can run w/o a network connection _ or if a bad document comes through, it can recover -_ gracefully recover from proxy problems -_ https://github.com/processing/processing/issues/1601 _ alternating blue/white backgrounds aren't updated after changing filter _ just need to call a repaint() after a filter change? _ check with Casey about coloring for error messages @@ -708,7 +770,7 @@ _ font size for "Downloading" on progress bar is too large _ but changing the size breaks the vertical centering _ highlight color seems to be incorrect? _ after installing, the item in the manager list doesn't change color -_ wheel mouse is super jumpy +_ wheel mouse is super jumpy _ something about unit increment in ContributionListPanel _ arrow keys up/down move scroll bar, not selection _ fonts/etc need to be set in one place where they can be edited @@ -726,12 +788,13 @@ _ when are prefs saved? could instead save whenever changes are made _ and then if the file gets modified, it'll put up an error message _ also, this may be part of why other sketches aren't reloading properly _ simple prefs implementation to set key/value pairs using a JTable +_ https://github.com/processing/processing/issues/5425 _ prefs window doesn't swap ok/cancel properly for mac vs. windows/linux _ don't bother having a "cancel" for the prefs window _ make prefs dialog modal? -PDE / Runner +PDE / Runner _ if RuntimeException thrown, needs to check if it's a wrapped exception _ for instance, if there's a crash inside makeGraphics() @@ -746,9 +809,15 @@ _ https://github.com/processing/processing/issues/4445 _ need to set dock icon title on osx +PDE / Tweak + +_ TweakMode listener mess in JavaTextArea +_ https://github.com/processing/processing/issues/4605 + + PDE / Sketch & Sketchbook -_ Large number of files in sketchbook folder can cause slow startup +_ Large number of files in sketchbook folder can cause slow startup _ and/or errors with launch4j _ https://github.com/processing/processing/issues/1190 _ error that sketch is read-only can't be canceled @@ -759,11 +828,6 @@ _ because there's a dash in the name _ and instead only loads StemCell.pde _ show progress dialog during export and save _ hitting ESC on "create this, move file, continue" opened anyway -_ some type of sketch archive format for posting examples (.psk?) -_ would be nice to open a sketch directly from a zip file -_ https://github.com/processing/processing/issues/73 -_ maybe just open from a zip file, since psk doesn't help anything -_ also have a means of importing sketches @@ -780,7 +844,7 @@ _ for tools, maybe don't run on event thread? (makes the gui hang) _ but instead, things that affect gui need to be called w/ invokeLater? -TOOLS / Ideas +TOOLS / Ideas _ eclipse import/export _ simple mechanism to export to eclipse @@ -801,7 +865,7 @@ TOOLS / Auto Format _ Switch block cases not indented _ https://github.com/processing/processing/issues/1042 -_ do a better job of maintaining cursor +_ do a better job of maintaining cursor _ only auto-format a particular section of code _ set the 'tabs' var based on how many spaces on previous line _ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1087227217 @@ -837,9 +901,9 @@ DIST How the environment gets packed up, downloaded, and installed. -DIST / General +DIST / General -_ move processing-java inside the Java Mode? +_ move processing-java inside the Java Mode? _ make a Tool that installs it for all platforms, not just OS X _ not really part of the 'build' anymore _ line ending issues @@ -862,12 +926,12 @@ _ need .psk file icon _ need exported application icons _ need more comprehensive list of 'known bugs' _ need more comprehensive list of 'known suggestions' -_ write notes about running p5 on another platforms +_ write notes about running p5 on another platforms _ this was some feedback from running on bsd: -_ /usr/local/jdk1.3.1/bin/java -cp lib:lib/build:lib/pde.jar:lib/kjc.jar:lib/oro.jar:java/lib/ext/comm.jar PdeBase +_ /usr/local/jdk1.3.1/bin/java -cp lib:lib/build:lib/pde.jar:lib/kjc.jar:lib/oro.jar:java/lib/ext/comm.jar PdeBase _ need to use the 1.3 vm, and get a fake platform name _ otherwise, goes looking for lib/pde_.properties or something -_ about box +_ about box _ bring up information about gpl, lgpl, and ibmpl _ jedit syntax is under mit license _ http://www.opensource.org/licenses/mit-license.php @@ -880,8 +944,6 @@ _ p5 assets need to be licensed differently from the source DIST / Windows -_ PDE and sketches are 2x smaller on high-res Windows 8 machines -_ https://github.com/processing/processing/issues/2411 _ does launching p5 from inside the .zip folder cause it to quit immediately? _ how can we provide an error message here? _ how to handle double-clicked files on windows? @@ -891,19 +953,13 @@ _ this may already work with SingleInstance stuff DIST / Mac OS X -_ client properties +_ Help Menu disabled on OS X (looks like a JVM bug) +_ https://github.com/processing/processing/issues/4353#issuecomment-237715947 +_ Java bug prevents us from setting the dock name of a sketch run from the PDE +_ https://github.com/processing/processing/issues/5045 +_ client properties _ https://developer.apple.com/library/mac/technotes/tn2007/tn2196.html _ built-in images: http://nadeausoftware.com/articles/2008/12/mac_java_tip_how_access_mac_specific_nsimage_icons -_ replace appbundler with the Java 8 packager -_ https://github.com/processing/processing/issues/3071 -_ fix appbundler problems due to rollback -_ https://github.com/processing/processing/issues/3790 -_ appbundler is no longer being developed by Oracle, switch to "packager" -_ this re-introduces two bugs (serial export and scrolling) -_ and any other changes later than 16 November 2014: -_ https://github.com/processing/processing/commits/master/build/macosx/appbundler.jar -_ https://github.com/processing/processing/commits/master/build/macosx/appbundler/native/main.m -_ https://github.com/processing/processing/commit/fa27b983e76fdbc5c4c1451a1f0d854c652b1639 _ Update QuickLook plugin for Processing 3 _ https://github.com/processing/processing/issues/3261 _ Find a long-term solution for OS X bundler to address signing/symlink issues @@ -915,11 +971,11 @@ _ more OS X-specific hackery for improved appearance _ https://developer.apple.com/library/mac/technotes/tn2007/tn2196.html _ possible better option for doing retina? _ g.getFontRenderContext().getTransform().equals(AffineTransform.getScaleInstance(2.0, 2.0)) -_ LWJGL forum discussion +_ LWJGL forum discussion _ http://lwjgl.org/forum/index.php/topic,4711.225.html -_ change cmd line for OS X to use symlink? +_ change cmd line for OS X to use symlink? _ otherwise updates are going to require reinstall.. -_ or that it's gonna need to parse and say "update command line?" +_ or that it's gonna need to parse and say "update command line?" _ look into LCD rendering problems w/ Java (see if Lion still a problem) _ fonts were showing up with very different fatness _ we're breaking some mac human interface guidelines @@ -984,7 +1040,7 @@ _ argh.. more path and shell issues.. -FUTURE +FUTURE Notes for some indefinite later release... @@ -1011,18 +1067,18 @@ _ https://github.com/processing/processing/issues/218 _ changing number of screens between run causes things to show up off-screen _ so when running, check to make sure that things are out of the area _ improve the speed of file copying -_ use FileChannels, see FileInputStream.getChannel(), +_ use FileChannels, see FileInputStream.getChannel(), _ and use transferFrom() or transferTo().) _ could also use FileUtils in Apache's common io _ http://commons.apache.org/io/api-release/index.html -_ go through libraries and clean things up +_ go through libraries and clean things up protected void finalize() throws Throwable { try { - close(); + close(); } catch (Exception e) { - // do something - } finally { + // do something + } finally { super.finalize(); - // more code can be written here as per need of application + // more code can be written here as per need of application } }