diff --git a/.gitignore b/.gitignore index 4eb469196ddba..362e15727b328 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,7 @@ vtest/Pictures .vs dependencies -# Downloaded files during build process +# Files generated or downloaded during build process MS_General.sf3 MS_General-License.md MS_General-changelog.txt @@ -49,3 +49,5 @@ MuseScore_General-changelog.txt VERSION /mscore/data/mscore.aps /msvc.* +/mscore/data/splash.svg +/mscore/data/icons/mscore.svg diff --git a/.travis.yml b/.travis.yml index 06923aab17e57..a95ca5e185902 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,12 @@ matrix: - libpulse-dev - libgtk2.0-bin - expect + # assets build + - imagemagick + - pngcrush + - libxml2-utils # xmllint + - icnsutils # png2icns + - fonts-roboto cache: directories: - $HOME/.ccache @@ -128,6 +134,7 @@ matrix: install: - source ./build/travis/job_macos_lupdate/install.sh script: + - "./build/travis/job_macos_lupdate/build-assets.sh" - "./build/travis/job_macos_lupdate/script.sh" notifications: diff --git a/CMakeLists.txt b/CMakeLists.txt index a54f936f80098..19dfb4d4679d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,15 @@ option(COVERAGE "Build with instrumentation to record code coverage." OFF) option(BUILD_64 "Build 64 bit version of editor" ON) option(BUILD_AUTOUPDATE "Build with autoupdate support" OFF) +# set options for assets build (overrides defaults set in assets/CMakeLists.txt) +option(DOWNLOAD_ASSETS "Download pre-built assets (icons and images) rather than attempting to build from source SVGs." ON) +option(ONLY_BUILD_ASSETS "Only build the assets (icons and images), don't compile MuseScore." OFF) +if(MSCORE_UNSTABLE) + option(OPTIMIZE_PNGS_BRUTE "Use maximum PNG compression for assets (takes time)" OFF) +else(MSCORE_UNSTABLE) + option(OPTIMIZE_PNGS_BRUTE "Use maximum PNG compression for assets (takes time)" ON) +endif(MSCORE_UNSTABLE) + if (APPLE) set (CMAKE_CXX_COMPILER clang++) set (CMAKE_CXX_COMPILER_ID "Clang") @@ -264,6 +273,58 @@ SET(MUSESCORE_NAME_VERSION "${MUSESCORE_NAME} ${MUSESCORE_VERSION_MAJOR}") # SET(MUSESCORE_VERSION_FULL "${MUSESCORE_VERSION}.${MUSESCORE_VERSION_PATCH}") +set(ASSETS_BINARY_DIR "${PROJECT_BINARY_DIR}/assets") # assets generated here +set(ASSETS_ARCHIVE_NAME "${MUSESCORE_NAME}-assets-${MUSESCORE_VERSION_FULL}.zip") +# NOTE: Different branches may share assets or have different assets depending +# on whether the branches have the same value for ${ASSETS_ARCHIVE_NAME}. +if (DOWNLOAD_ASSETS) + # Download assets instead of building from source + set(ASSETS_REMOTE "https://transfer.sh/QCx9R/${ASSETS_ARCHIVE_NAME}") # TODO: fetch from MuseScore server + set(ASSETS_LOCAL "${ASSETS_BINARY_DIR}/${ASSETS_ARCHIVE_NAME}") + set(ASSETS_PREVIOUS "${ASSETS_BINARY_DIR}/last_extracted") # file contains name of the last archive extracted + set(EXTRACT_ASSETS TRUE) # whether to extract the archive + if(EXISTS "${ASSETS_LOCAL}") + message("Using existing assets archive: ${ASSETS_LOCAL}") + # Although we can reuse the archive, we still need to extract it if an + # archive from a branch with different assets has been extracted + if(EXISTS "${ASSETS_PREVIOUS}") + file(STRINGS "${ASSETS_PREVIOUS}" PREVIOUS_ARCHIVE) + string(COMPARE NOTEQUAL "${ASSETS_ARCHIVE_NAME}" "${PREVIOUS_ARCHIVE}" EXTRACT_ASSETS) + endif(EXISTS "${ASSETS_PREVIOUS}") + else(EXISTS "${ASSETS_PREVIOUS}") + message("Downloading assets...") + file(DOWNLOAD "${ASSETS_REMOTE}" "${ASSETS_LOCAL}" SHOW_PROGRESS STATUS DL_STATUS) + list(GET DL_STATUS 0 RET_VAL) + if (NOT RET_VAL EQUAL 0) + list(GET DL_STATUS 1 STATUS_TEXT) + message(FATAL_ERROR "Unable to download assets. Error ${RET_VAL}: ${STATUS_TEXT}") + endif(NOT RET_VAL EQUAL 0) + endif(EXISTS "${ASSETS_LOCAL}") + if(EXTRACT_ASSETS) + message("Extracting assets...") + # Extract with CMake's built-in tar to avoid depending on system tar + execute_process( + COMMAND "${CMAKE_COMMAND}" -E tar "xfv" "${ASSETS_ARCHIVE_NAME}" + WORKING_DIRECTORY "${ASSETS_BINARY_DIR}" + RESULT_VARIABLE RET_VAL + ) + if(NOT RET_VAL STREQUAL "0") # compare strings as RET_VAL not always a number + message(FATAL_ERROR "Unable to extract assets archive. Error ${RET_VAL}") + endif(NOT RET_VAL STREQUAL "0") + file(WRITE "${ASSETS_PREVIOUS}" "${ASSETS_ARCHIVE_NAME}") + endif(EXTRACT_ASSETS) +else (DOWNLOAD_ASSETS) + # build icons and resources from source files + add_subdirectory(assets) + # NOTE: downloaded assets are available immediately whereas built assets will + # not be available until the build takes place. This affects which CMake + # commands can be used to interact with them. See assets/README.md. +endif (DOWNLOAD_ASSETS) + +if (ONLY_BUILD_ASSETS) + return() # exit here +endif (ONLY_BUILD_ASSETS) + if (BUILD_WEBENGINE) if (MINGW) SET (USE_WEBENGINE 0) diff --git a/Makefile b/Makefile index 89d875e1dd853..23980beeec829 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ BUILD_WEBENGINE="ON" # Override with "OFF" to disable. USE_SYSTEM_FREETYPE="OFF" # Override with "ON" to enable. Requires freetype >= 2.5.2. COVERAGE="OFF" # Override with "ON" to enable. DOWNLOAD_SOUNDFONT="ON" # Override with "OFF" to disable latest soundfont download. +DOWNLOAD_ASSETS="ON" # Override with "OFF" to ensure build fails if assets cannot be built from source. UPDATE_CACHE="TRUE"# Override if building a DEB or RPM, or when installing to a non-standard location. NO_RPATH="FALSE"# Package maintainers may want to override this (e.g. Debian) @@ -63,6 +64,7 @@ release: -DBUILD_WEBENGINE="${BUILD_WEBENGINE}" \ -DUSE_SYSTEM_FREETYPE="${USE_SYSTEM_FREETYPE}" \ -DDOWNLOAD_SOUNDFONT="${DOWNLOAD_SOUNDFONT}" \ + -DDOWNLOAD_ASSETS="${DOWNLOAD_ASSETS}" \ -DCMAKE_SKIP_RPATH="${NO_RPATH}" ..; \ make lrelease; \ make -j ${CPUS}; \ @@ -92,6 +94,7 @@ debug: -DUSE_SYSTEM_FREETYPE="${USE_SYSTEM_FREETYPE}" \ -DCOVERAGE="${COVERAGE}" \ -DDOWNLOAD_SOUNDFONT="${DOWNLOAD_SOUNDFONT}" \ + -DDOWNLOAD_ASSETS="${DOWNLOAD_ASSETS}" \ -DCMAKE_SKIP_RPATH="${NO_RPATH}" ..; \ make lrelease; \ make -j ${CPUS}; \ diff --git a/all.h b/all.h index 3c0cdd715ac74..8334ac7012d66 100644 --- a/all.h +++ b/all.h @@ -178,6 +178,7 @@ #include #include +#include // use in preference to QPixmap and QLabel where possible #include #include diff --git a/assets/.editorconfig b/assets/.editorconfig new file mode 100644 index 0000000000000..801f2eacdcbc0 --- /dev/null +++ b/assets/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# Text editors and IDEs that support the EditorConfig standard will format and +# indent text files according to the rules in this file. You can use `eclint` +# to check code files against these rules +# and flag any violations: simply run `eclint check` from this directory. You +# could set up a pre-commit hook to run the check each time you commit. + +# top-most EditorConfig file (treat assets as independent project) +root = true + +# Formatting rules for all text files +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 diff --git a/assets/.gitignore b/assets/.gitignore new file mode 100644 index 0000000000000..378eac25d3117 --- /dev/null +++ b/assets/.gitignore @@ -0,0 +1 @@ +build diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt new file mode 100644 index 0000000000000..ddd33f45c9674 --- /dev/null +++ b/assets/CMakeLists.txt @@ -0,0 +1,117 @@ +# Create a new CMake project for the assets to allow them to be generated +# independently of MuseScore's build. +project("MuseScore assets" + DESCRIPTION "Build MuseScore's icons and resources from SVG source files" + LANGUAGES NONE + ) + +cmake_minimum_required(VERSION 3.0) + +if(WIN32) + set(WIN_NOT_AVAIL "Not available on Windows") + option(BUILD_MACOS_ICONS "${WIN_NOT_AVAIL}" OFF) +endif(WIN32) + +# The following options are enabled/disabled as appropriate for somebody +# building the assets alone. If MuseScore requires different settings then +# these should be made in MuseScore's top-level CMakeLists.txt. Options with +# the same name in MuseScore's CMakeLists.txt will override the ones here. +option(TESTS "Run code validation and other checks during the build process" ON) +option(STRICT_FONTS "Fail build if required fonts are not installed (disable to allow build to proceed using a fallback font)" ON) +option(STRICT_VARIABLES "Fail build if required variables are not defined (disable to allow build to proceed using default values)" ON) +option(BUILD_WINDOWS_ICONS "Build ICO icon files for Windows" ON) +option(BUILD_MACOS_ICONS "Build ICNS icon files for macOS" ON) +option(BUILD_FREEDESKTOP_ICONS "Build PNG icons for Linux and other systems that follow the FreeDesktop.org specifications" ON) +option(OPTIMIZE_SVGS "Optimize SVG file size using SVGO" ON) +option(OPTIMIZE_PNGS "Optimize PNG file size using PNGCRUSH" ON) +option(OPTIMIZE_PNGS_BRUTE "Try all PNG compression methods to ensure smallest possible size (takes time)" OFF) + +# Load CMake functions defined in other files - modular programming (sort of) +include("basic-functions.cmake") +include("image-functions.cmake") +if(STRICT_FONTS) + include("font-dependencies.cmake") +else(STRICT_FONTS) + message(STATUS "Not checking system fonts (STRICT_FONTS is OFF)") +endif(STRICT_FONTS) + +# Some assets depend on variables defined in MuseScore's CMakeLists.txt +# set default values here to allow independent building of the assets. +required_variable(MUSESCORE_NAME "MuseScore") +required_variable(MUSESCORE_VERSION_FULL "X.Y.Z") + +# Optionally pack assets into a ZIP file for easy distribution. +set(ASSETS_ARCHIVE_NAME "${MUSESCORE_NAME}-assets-${MUSESCORE_VERSION_FULL}.zip") + +# Store a list of all assets generated as part of the build. +set(ASSETS_MANIFEST "assets-manifest.txt") # used for archiving and CI tests. +# As a basic CI test, a reference copy of this file is checked into the repo +# and compared to the one generated during the build to ensure they match. +# This will catch simple errors, but assets must still be compared visually. + +# create empty manifest file to append to +file(WRITE "${PROJECT_BINARY_DIR}/${ASSETS_MANIFEST}" "# DO NOT EDIT!!! This file is generated during the build.\n") + +function(add_to_manifest # add assets to the manifest file + ASSET # name of asset file to be added to manifest + # ARGN optionally specify more asset files as additional arguments + ) + foreach(FILE "${ASSET}" ${ARGN}) + # expand path to asset file to make it relative to the build directory + file(RELATIVE_PATH PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/${FILE}") + file(APPEND "${PROJECT_BINARY_DIR}/${ASSETS_MANIFEST}" "${PATH}\n") + endforeach(FILE) +endfunction(add_to_manifest) + +add_subdirectory(resources) # resources first (everything depends on them) + +add_custom_target("assets" ALL) # main target to build all other assets + +add_subdirectory(brand) +add_subdirectory(platform) +add_subdirectory(splash) + +# Read in the manifest we just created (ignore lines that begin with '#') +file(STRINGS "${PROJECT_BINARY_DIR}/${ASSETS_MANIFEST}" ASSET_FILES REGEX "^[^#]") +set(ASSET_FILES_ABS "") +foreach(ASSET ${ASSET_FILES}) + list(APPEND ASSET_FILES_ABS "${PROJECT_BINARY_DIR}/${ASSET}") +endforeach(ASSET) + +# optional target to create a compressed ZIP archive containing all assets +add_custom_target("assets_archive" DEPENDS "${ASSETS_ARCHIVE_NAME}") +add_dependencies("assets_archive" "assets") # assets must be built first +add_custom_command( + OUTPUT "${ASSETS_ARCHIVE_NAME}" + DEPENDS ${ASSET_FILES_ABS} # rebuild if any of these files have changed (absolute paths required) + COMMAND "${CMAKE_COMMAND}" -E tar "cfv" "${ASSETS_ARCHIVE_NAME}" --format=zip ${ASSET_FILES} + VERBATIM + ) + +if(TESTS) + # POST CONFIGURE CHECKS - these are run by CMake just before it exits. + # NOTE: CMake only runs on the first build or when the CMake or configured + # files change. All other files must be checked at build time. + required_program(GIT "Distributed VCS - https://git-scm.com/" "git") + execute_process( + COMMAND "${GIT}" diff --color --no-index "${PROJECT_SOURCE_DIR}/${ASSETS_MANIFEST}" "${ASSETS_MANIFEST}" + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}" + RESULT_VARIABLE RET_VAL + ) + if(RET_VAL STREQUAL "1") # compare strings as RET_VAL not always a number + message(FATAL_ERROR "Generated manifest doesn't match the repository version.") + elseif(NOT RET_VAL STREQUAL "0") + message(FATAL_ERROR "Diff command exited with '${RET_VAL}' indicating an error occured.") + endif(RET_VAL STREQUAL "1") + + # PRE BUILD CHECKS - Run by the native build tool as soon as it starts. + # NOTE: The build tool runs on every build, so these checks do too. + required_program(ECLINT "Tool for checking code formatting and indentation - https://github.com/jedmao/eclint" "eclint") + add_custom_target("assets_sanitycheck" ALL + COMMAND "${ECLINT}" check # ignores all files in .gitignore + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + VERBATIM USES_TERMINAL + ) + # now ensure check runs before everything else + add_dependencies("assets_resources" "assets_sanitycheck") +endif(TESTS) diff --git a/assets/CONTRIBUTING.md b/assets/CONTRIBUTING.md new file mode 100644 index 0000000000000..52966d4683428 --- /dev/null +++ b/assets/CONTRIBUTING.md @@ -0,0 +1,614 @@ +Contributing to MuseScore's Assets +================================== + +- [Basic Requirements] + - [Requirements for source files] + - [CMake files] + - [Source SVGs] + - [Source rasters] + - [Requirements for generated files] + - [Generated SVGs] + - [Generated rasters] + - [Generated icon files] +- [Coding Techniques] + - [DRY: Don't Repeat Yourself!] +- [SVG Best Practice] + - [Editing SVGs] + - [Re-using SVG content] + - [Fonts and SVG text] + - [Font licensing] + - [SVG Compatibility] +- [Understanding the build process] + - [Why CMake?] + - [CMake files] + - [Where the build begins] + - [CMake functions and macros] + - [Command execution order] + +## Basic Requirements +[Basic Requirements]: #basic-requirements + +### Requirements for source files +[Requirements for source files]: #requirements-for-source-files + +These requirements apply to all files that get checked into the repository. + +#### CMake files +[CMake files]: #cmake-files + +Files named `CMakeLists.txt` or `*.cmake` contain the code used by the CMake +build system to generate the assets. Try to employ good [Coding Techniques]. + +#### Source SVGs +[Source SVGs]: #source-svgs + +SVG files in the repository must be fully editable "master" files. This means: + +- Any text visible in an SVG image must be stored as editable text (i.e. not + converted to paths). +- Any [images included in the file][Source rasters] are linked to rather than + embedded (use relative paths for links!). +- No duplicated content (see [Re-using SVG content]). + +If the source file requires some form of pre-processing as part of the build +process then you should indicate this through the file extension. Keep the +existing `.svg` extension and append `.xml` for files that contain XML syntax +that is not part of the SVG specification, and `.in` for files that must be +configured with CMake. + +#### Source rasters +[Source rasters]: #source-rasters + +You should avoid using raster images (PNGs, JPEG, etc.) as source files if at +all possible. If they are necessary (e.g. as a background texture) then they +should be optimized to reduce the file size as much as possible *without loss +of quality* and stored in the [resources] folder. + +[resources]: resources "Textures and basic shapes used in other assets" + +- Use JPEG for photographs and textures +- Use PNG for computer generated images (e.g. screenshots) + +Raster images can be included in SVGs using the `` element: + +```svg + +``` + +Technically this also works to include other SVG files, but you shouldn't use +it for that purpose as there are better ways to do this. + +### Requirements for generated files +[Requirements for generated files]: #requirements-for-generated-files + +These requirements apply to all files intended for external use (i.e. the ones +listed in the [assets manifest]). + +[assets manifest]: assets-manifest.txt + +The CMake files already define helper functions to get generated files to meet +these requirements automatically, so it's usually just a case of making sure +the source SVG is listed in one of the CMakeLists.txt files and that it is +passed through the right helper functions. + +There are additional requirements for files that must integrate with the +operating system. These are explained in the [platform README]. + +[platform README]: platform/README.md + +#### Generated SVGs +[Generated SVGs]: #generated-svgs + +Generated SVGs must also be optimized in terms of file size, while remaining +fully portable and self-contained (standalone). This means: + +- All `` elements converted to paths to ensure they are displayed + correctly regardless of whether the user has the right fonts installed. +- All raster images embedded into the SVG as [Base64 Data URIs] to ensure the + files never become separated. +- No linking elements that point to external files (e.g. ``, ``). +- Formatting stored as XML attributes (`attr="val"`) rather than CSS styles + (`style="attr:val"`) for compatibility reasons. +- No specialist SVG syntax that is not widely supported by SVG viewers. See + [SVG Compatibility]. + +[Base64 Data URIs]: https://en.wikipedia.org/wiki/Data_URI_scheme#SVG + +__Helper functions:__ + +- `standalone_svg()` +- `optimize_svg()` + +### Generated rasters +[Generated rasters]: #generated-rasters + +These should be generated from SVGs at each required size. Do not generate one +PNG at the largest size and then scale it down to the other required sizes; +this leads to reduced quality and increased file size compared to generating +each size of PNG straight from the SVG. All PNGs should be run through +`pngcrush` to optimize the file size, and this must be done before the PNG is +used for other things, such as embedding into icon files. + +__Helper functions:__ + +- `rasterize_svg()` +- `optimize_png()` + +### Generated icon files +[Generated icon files]: #generated-icon-files + +ICO and ICNS icon files contain the same image at multiple image sizes. Many +icon tools allow you to create an icon from a single PNG file, but you __must +not__ use this feature. Instead, generate a separate PNG at each required size +as outlined in the section above, and then embed all the sizes into the icon. + +Additional requirements for icon files are given in the [platform README]. + +## Coding Techniques +[Coding Techniques]: #coding-techniques + +### DRY: Don't Repeat Yourself! +[DRY: Don't Repeat Yourself!]: #dry-dont-repeat-yourself + +Try to avoid copying and pasting code as much as possible as this makes things +harder to understand and maintain. Instead, make use of functions and links +that you define once and then call upon elsewhere in the code. This means that +changes can be made easily by updating the definition; there's no need to go +hunting for other places where the same code is used. + +These sections explain how to apply this principle in various parts of the +code: + +- [Re-using SVG content] +- [CMake functions and macros] + +See the [splash images](splash) and associated build rules for examples of all +the techniques explained in those sections. + +## SVG Best Practice +[SVG Best Practice]: #svg-best-practice + +### Editing SVGs +[Editing SVGs]: #editing-svgs + +You should create and edit SVGs manually in a text editor. Do not use a +graphical SVG editing program as these tend to add unnecessary bloat to the +SVG code. They also tend to convert simple shapes like circles to complicated +Bézier paths, making the code difficult to understand and edit later on. + +However, you may use a graphical editor to help you edit complicated paths, +where necessary. Simply save the edited file under a different name and then +copy the relevant part of the SVG code (`d="..."`) back into the source file. +However, it is preferable to define paths manually where possible. + +For help with paths, see: + +- https://www.w3schools.com/graphics/svg_path.asp +- https://css-tricks.com/svg-path-syntax-illustrated-guide/ +- https://www.w3.org/TR/SVG11/paths.html#PathData + +#### Re-using SVG content +[Re-using SVG content]: #re-using-svg-content + +##### Cloning elements within an SVG file +[Cloning elements within an SVG file]: #cloning-elements-within-an-svg-file + +If any SVG group or shape is given an ID (e.g. `` element +(``). You can assign different properties to the +clone, such as giving it a different fill or stroke, and apply transformations +like `translate` (move), `scale` and `rotate`. If you make a change to the +original shape then all of the clones will be updated automatically. + +##### Cloning elements from other SVG files +[Cloning elements from other SVG files]: #cloning-elements-from-other-svg-files + +The `` element also allows you to clone elements defined in other SVG +files (``), and you can +even insert an entire SVG using the `` element. However, __you mustn't +use either of these features__ because it means the SVG is no longer a +standalone file (there are ways around this but they are less than ideal) and +there are other limitations besides. + +Instead, if two SVGs share some of the same content, use [XInclude] to grab +the content from one file and dump it in the other at build time. (This makes +use of the fact that SVG files are also XML files.) + +[XInclude]: https://en.wikipedia.org/wiki/XInclude + +__Include an entire SVG (or XML) file:__ + +```xml + +``` + +If you only want to include part of a file, you can use an [XPointer]. The +most intuitive ways to use XPointers with XInclude are as follows: + +[XPointer]: https://en.wikipedia.org/wiki/XPointer + +__Include everything inside the outermost SVG (or XML) tag:__ + +```xml + +``` + +__Include the SVG (or XML) element with attribute `id="name"`:__ + +```xml + +``` + +__Include everything inside the SVG (or XML) element with attribute `id="name"`:__ + +```xml + +``` + +IDs are stripped during the build as part of the SVG optimization process, so +you can't use the `[@id='name']` expression on files that have been optimized. +There should be equivalent optimized and non-optimized versions of every SVG +generated during the build. The non-optimized version of `file.svg` should be +called `file-standalone.svg`. SVGs in the [resources] folder do not get +optimized, so you can include those with `file.svg`. + +Most SVG programs don't understand XInclude syntax, so you won't be able to +see the included elements in viewers until after you have run the build. + +### Fonts and SVG text +[Fonts and SVG text]: #fonts-and-svg-text + +If the SVG contains text then the text must specify a font, like this: + +```xml +Hello World! +``` + +Other font attributes are available, such as `font-variant="small-caps"`, and +you can see the full list [here][font properties in SVG]. Be aware that most +fonts don't provide glyphs for every possible combination of attribute values. +For example, a particular font might provide **bold** and *italic* but not +***bold italic***. You can use Inkscape to see which styles are available for +your font, and you can use Inkscape's built-in [XML viewer/editor] to check +the syntax for the particular text attributes you are interested in (or save a +copy and open it in a text editor) but be aware that most of the information +in the file will be redundant. + +[font properties in SVG]: https://www.w3.org/TR/SVG11/text.html#FontPropertiesUsedBySVG +[XML viewer/editor]: http://tavmjong.free.fr/INKSCAPE/MANUAL/html/XML-Basic.html + +__Tip:__ you can use the CMake function [`configure_file()`] to substitute +CMake variables inside SVG source files. This allows you to add things like +version numbers to SVGs and have them update automatically, or to use a single +SVG as a template from which multiple other SVGs can be created. + +[`configure_file()`]: https://cmake.org/cmake/help/latest/command/configure_file.html + +#### Font licensing +[Font licensing]: #font-licensing + +The rules around font licensing are extremely complicated. To make it easy: + +- Try to only use fonts available from [Google Fonts]. +- The font __MUST__ use the [Open Font License] by SIL. + +[Google Fonts]: https://fonts.google.com/ +[Open Font License]: https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=OFL + +Not all Google Fonts use the Open Font License, so make sure you check. The +license is stated at the bottom right of the font page for each font family. + +If you have already used a proprietary font in your design then try to find a +replacement. Many proprietary fonts have an open source equivalent that can be +used as a drop-in replacement. Simply do an online search for "open source +alternative to ..." and then check to see if it uses the Open Font License. + +In case you are interested, the main licensing requirement is obviously that +the font is free and open source. However, the license must also: + +- Allow the font to be embedded in documents. +- Allow the font glyphs to vectorized (converted to outlines/paths). +- Apply only to the font itself and not to any documents that use the font, + either in embedded or vector form. + +This excludes pretty much any font covered by any of the familiar open source +software licenses, including the GPL, as those licenses were not written with +fonts in mind. This can make it difficult to distribute fonts with open source +software, but we can still distribute documents that *use* the font as long as +the font's license meets the above requirements. + +### SVG Compatibility +[SVG Compatibility]: #svg-compatibility + +Support for SVG features varies widely between SVG viewer applications. +Fortunately, pretty much all viewers support a core set of features, and most +of the specialist features can be "faked" using the core set. + +A good way to test for compatibility is to see how the SVG looks when opened +in [Qt's example SVG Viewer][QT-svg-viewer] application. The viewer can be +loaded and built [from the Welcome screen in Qt Creator][Qt-examples]. + +[QT-svg-viewer]: https://doc.qt.io/qt-5/qtsvg-svgviewer-example.html +[Qt-examples]: https://doc.qt.io/qt-5/qtexamplesandtutorials.html + +Qt only supports a subset of the SVG specification called SVG Tiny, and its +implementation appears to be somewhat buggy and incomplete. SVGs that are +displayed within MuseScore are rendered using Qt, so it is essential that they +are displayed correctly in the viewer. + +As always, you should include a comment at the relevant place in the source +file if compatibility issues force you to do anything that is not obvious. + +## The Build Process +[The build process]: #the-build-process + +### Why CMake? +[Why CMake?]: #why-cmake + +The CMake build system is used to generate the assets. It uses a strange +syntax which is very verbose and not particularly friendly for beginners. +We could generate the assets using simple Bash scripts, but there are +advantages to using CMake, as it: + +- Behaves more consistently than Bash on certain systems (i.e. Windows). +- Integrates well with native build tools and IDEs. +- Is already used for MuseScore's build. + +Finally, CMake provides various features that Bash doesn't (Bash isn't a build +tool after all), such as: + +- Checking whether targets have already been generated and only building the + ones for which the source files have changed. +- Running builds in parallel (i.e. building more than one target at a time). +- Handling dependencies (i.e. when some targets must be built before others). + +These abilities help to save a lot of time on successive builds and reduce the +number of writes made to disk. These features could be written in Bash, but we +would have to write them ourselves whereas CMake gives us them for free. + +### Editing CMake Files +[CMake files]: #cmake-files + +CMake builds the assets based on the instructions in the `CMakeList.txt` and +`*.cmake` files. Each directory has its own CMake files that contain the rules +needed to build all the assets in that directory and any subdirectories. + +- If you are just making changes within an existing SVG then it probably won't + be necessary to make any changes to the CMake files at all. + +- If you are adding new SVGs to an existing directory then you just need to + modify the `CMakeLists.txt` file in that directory. Use its existing rules + as a guide. + +- If you create a new directory then you need to create a new `CMakeLists.txt` + file to go inside it. Use an existing `CMakeLists.txt` as a template. + +None of those situations require detailed knowledge of how the build process +works or of CMake in general. However, if you are trying to do something a bit +more complicated then it is helpful if you know a bit about how CMake works. + +### Understanding the build process +[Understanding the build process]: #understanding-the-build-process + +The most difficult thing to understand is the order in which things happen. +The build rules are defined in the CMake files, but events don't necessarily +take place in the order in which they appear in those files. To see why this +is, you first need to understand that CMake doesn't actually build anything +itself. Instead, the building is done by a native build tool (usually Make, +Xcode or MSCV). CMake simply gets things ready for the native build tool. + +#### The `configure` step + +##### Types of CMake command + +The `configure` step is performed entirely by CMake based on commands in the +CMake files. It basically has two jobs to do: + +1. Perform any necessary housekeeping (e.g. with `configure_file()`). +2. Generate code (called "targets") for the native build tool. + - CMake generates this code immediately, but the code is not executed + until the native build tool runs in the `build` step. + +This means there are essentially two types of command you will come across in +the CMake files: + +1. Things CMake does itself (i.e. immediately). +2. Things it tells the native build tool to do later. + +In general, commands that CMake does immediately can only interact with source +files (i.e. files in the Git repository) or configured files (i.e. files +created by CMake, usually with `file(WRITE)` or `configure_file()`). These +commands can get and set CMake variables, but they cannot interact with files +that are created during the `build` step because those files do not exist when +CMake is run. + +On the other hand, commands that tell CMake to generate targets for the native +build tool are generally able to interact with all files, including files that +are created in the `build` step. However, these commands cannot be used to set +CMake variables because the `build` step is not performed by CMake (you can +still pass variables in as input to these commands). + +Sometimes there are two commands that serve a similar purpose, but one is for +CMake and the other is for the native build tool. For an example of this see +[`execute_process()` vs `add_custom_target()`]. + +##### Order of command execution + +When you run CMake in the `configure` step, it begins by looking at the code +in the [top-level CMakeList.txt]. The code in this file sets the project name +(we treat the assets as a separate project to MuseScore) and various options +and variables. CMake works its way through this file, running each command in +turn, until it reaches an `include()` or `add_subdirectory()` command, which +tell it to run some code from one of the other CMake files in the project. The +code in the other file is also executed in-turn, and then CMake returns to the +first file and picks up where it left off. Once it reaches the end of the +top-level CMakeLists.txt CMake exits and the `configure` step is complete. + +[top-level CMakeLists.txt]: CMakeLists.txt + +So in reality everything does happen in the order we would expect. There is of +course some added complexity due to the presence of control statements like +`if()` and `foreach()`, and [CMake functions and macros], but this is pretty +much the same as in any programming language. The only difference is that some +commands don't just contain instructions for CMake; they also contain +instructions for the native build tool. This can make it look like CMake is +ignoring your commands, when in reality it did what it was supposed to do and +added them to the code it generates for the native build tool. + +##### The `build` step + +The `build` step is performed entirely by the native build tool based on the +instructions given to it by CMake. Everything in the `configure` step either +happened in the order we would expect or it was deferred until the `build` +step. Unfortunately, the `build` step is not so simple. + +Recall that some CMake commands created code (called "targets") for the native +build tool to perform. Targets are not necessarily run in the order in which +they were defined in the CMake files. In fact, the native build tool will +ideally build multiple targets simultaneously to save time, and this can lead +to the order being essentially random, so you have no way of knowing when +things will happen! + +Sometimes a target cannot run until another target is complete. For example, +there might be a target to generate an SVG and another target to convert the +SVG into a PNG. Clearly the PNG cannot be created before the SVG has been +generated, so the PNG *depends* on the SVG. It is up to you to tell the build +system that this dependency exists otherwise it could try to build the targets +in the wrong order. Notice that this means you can still encounter errors in +the `build` step even if the `configure` step appeared to be successful. + +The native build tool's code is generated by CMake so we don't want to go +editing it ourselves. The only (sensible) way to declare a dependency is +through the CMake files. This is explained in +[`add_custom_target()` vs `add_custom_command()`]. + +### Similar commands + +#### `execute_process()` vs `add_custom_target()` +[`execute_process()` vs `add_custom_target()`]: #execute_process-vs-add_custom_target + +Both of these are commands accept a `COMMAND` argument which is used to run +a program on the command line with the specified options. The difference is +that `execute_process()` *tells CMake* to run a program on the command line, +whereas `add_custom_target()` *tells CMake to tell the native build tool* to +run a program on the command line. This can be a bit confusing, but the +distinction is important because it affects when the program gets run and what +what you are able do with it. + +In the case of `execute_process()`, CMake runs the program straight away and +then waits for it to finish. There is an option to store the program's return +status and outputs (from `stdout` and `stderr`) in variables to use later in +the CMake code. However, since the program is run during the `configure` step, +it is only able to interact with source files and configured files (e.g. those +created with `configure_file()`), because files created during the `build` +step will not exist yet. + +In the case of `add_custom_target()`, CMake generates a target for the native +build tool to run during the `build` step. The target can specify a program to +run on the command line (but it doesn't have to). Since the program is not run +by CMake, you are not able to access its output or return status in CMake +variables. However, it is able to interact with files built during the `build` +step, but only if those files are built first (i.e. the target must specify a +dependency on those files and/or the targets that create them). It can of +course interact with any source files or configured files since those are +guaranteed to exist at this point in the build, but there is no need to +specify them as a dependency. + +#### `add_custom_target()` vs `add_custom_command()` +[`add_custom_target()` vs `add_custom_command()`]: #add_custom_target-vs-add_custom_command + +Both of these are commands can be used to run programs on the command line and +both of them do this during the `build` step (use `execute_process()` to run +a program during the `configure` step). This means the program (or programs) +is not run by CMake but by the native build tool. If any of the programs +return a non-zero exit status then the build is failed and an error message is +displayed. + +In general, you should use `add_custom_command()` whenever you want to run a +program to *create or modify a file* on the filesystem. You should specify +this file as `OUTPUT` to the custom command, and any files that the program +needs look at first as dependencies (with the `DEPENDS` argument). The native +build tool will only run the command if the `OUTPUT` doesn't already exist +(i.e. on a clean build) or if one of the dependencies has changed since the +command was last run. This saves a lot of time on future builds, allowing the +build to complete more or less instantly if nothing has changed. However, +__the command will not run at all unless its `OUTPUT` is depended on by a +custom target or by another custom command__, and the same applies to the +other custom command, so there must be a custom target involved somewhere. + +You should use `add_custom_target()` when you want to run a program that +doesn't modify any files on the filesystem. You might do this to run some kind +of code validation check that will return a non-zero status if it fails, thus +stopping the build (hopefully with a useful error message printed on the +console). However, the most common use of custom targets is simply to cause +custom commands to get built, which you do by specifying the `OUTPUT` of the +custom command as the `DEPENDS` argument to the custom target (there is no +need to specify a `COMMAND` argument in this case). The target itself will not +be built unless one of the following conditions is met: + +- You specifically ask the native build tool to build the target: + - e.g. for Make: `make TARGETNAME` + - or in general: `cmake --build . --target=TARGETNAME` +- The target was defined with the `ALL` keyword and you don't specify any + targets for the native tool, i.e. you build the `all`/`default` target: + - e.g. for Make: `make` + - or in general: `cmake --build .` +- The target is depended on by another target which is being built. + - You do this with the `add_dependencies()` command in CMake. + +Sometimes you might create a top-level target that simply serves as a shortcut +to build lots of other targets: + +```cmake +add_custom_target(bigtarget) +add_dependencies(bigtarget smalltarget1 smalltarget2 smalltarget3 ...) +``` + +##### Depending on a custom command in another directory + +The following situation can sometimes arise: + +- In directory `A`: + - the target `targetA` is used to run a custom command that outputs a file + called `fileA`. +- In directory `B`: + - the target `targetB` is used to run a custom command that outputs a file + called `fileB`. + +Let's say that the command for `fileB` needs to use `fileA` as input. It +should be enough to say this: + +```cmake +custom_command(OUTPUT fileB DEPENDS ../A/fileA COMMAND ...) +``` + +However, due to some quirks of CMake and various native build tools, it is +actually necessary to __also__ say: + +```cmake +add_dependencies(targetB targetA) # no need to specify a directory for targets +``` + +This ensures that `targetA` is built before `targetB` and that `fileB` will be +rebuilt if `fileA` changes. + +### CMake Functions and Macros +[CMake functions and macros]: #cmake-functions-and-macros + +CMake allows you to create [functions] and [macros] that you can use later in +the project. This avoids having to write out the code in the function multiple +times, which is considered [bad coding practice][DRY: Don't Repeat Yourself!]. + +[functions]: https://cmake.org/cmake/help/latest/command/function.html "Custom CMake functions" +[macros]: https://cmake.org/cmake/help/latest/command/macro.html "Custom CMake macros" + +__Tip:__ the difference between a macro and a function is that variables set +in functions are not available outside the function (not unless you ask them +to be by setting them with the [`PARENT_SCOPE`] keyword). Variables set in +macros are *always* available outside the macro, which means they overwrite +other variables with the same name. __Always use a function unless you have a +specific need for a macro.__ If you ever find that you *do* need to create a +macro in order to perform a particular task then make sure you leave a comment +to say why a function wouldn't do the job. + +[`PARENT_SCOPE`]: https://cmake.org/cmake/help/latest/command/set.html#set-normal-variable diff --git a/assets/README.md b/assets/README.md new file mode 100644 index 0000000000000..6d73d71092476 --- /dev/null +++ b/assets/README.md @@ -0,0 +1,364 @@ +![MuseScore Logo](resources/mscore.svg) + +MuseScore Assets +================ + +This is where all assets are stored as SVG (Scalable Vector Graphics) files. +These source files are processed by various command line tools, including +[Inkscape], to produce more SVGs as well as icons (ICO, ICNS) and other raster +images (PNG) at build time. There is a list of all the files generated during +the build in [assets-manifest.txt]. + +[Inkscape]: https://inkscape.org/ "Inkscape open source vector graphics editor" + +- [Justification] +- [Structure] + - [Files] + - [Directories] +- [Building the Assets] + - [Building with MuseScore] + - [Building Alone] + - [The First Build] + - [CMake Generators] + - [Dependencies] + - [Subsequent Builds] +- [Contributing to the Assets] +- [Using Assets in MuseScore's Build] + +## Justification +[Justification]: #justification + +Why compile assets? Why not just commit PNG & ICO files into the repository? + +- __Binary files do not give readable diffs when they are edited.__ + - It is hard to see what has changed and to understand why it was necessary. +- __Compressed files are not stored efficiently by `git`.__ + - Make a small change to a text file or uncompressed binary file and only + the changes (i.e. the diff) need to be stored. + - Compression mixes the changed and unchanged parts of a file, so if you + make a small change to a PNG then a whole new file will be stored. + - The old file will forever be part of the history, slowing checkouts and + branch operations, and wasting disk space and bandwidth. +- __The GPL requires all source files to be distributed.__ + - Source files are resources in their most editable form, such as SVGs with + editable text, not PNGs with text 'burned in' to the pixel data. +- __Building assets saves having to generate the files manually.__ + - Reduced potential for mistakes and human error. + - No possibility of forgetting to update assets for one of the platforms. + +## Structure +[Structure]: #structure + +### Files +[Files]: #files + +- `CMakeLists.txt`, `*.cmake` - scripts used by the CMake build system to + generate the assets. +- `*.svg`, `*.jpg`, `*.png` - source SVG, JPEG and PNG images. +- [assets-manifest.txt] - list of files generated during the build process. + - NOTE: Paths in this file are relative to the build directory. +- [CONTRIBUTING.md] - read this before making any changes to the assets. + +[assets-manifest.txt]: assets-manifest.txt "Assets manifest" +[CONTRIBUTING.md]: CONTRIBUTING.md "Information for contributors" + +### Directories +[Directories]: #directories + +- __[resources]:__ Textures and basic shapes that are used in other assets +- __[brand]:__ Logos +- __[platform]:__ Application and document icons used by the operating system +- __[splash]:__ Splash screen images displayed during MuseScore's startup +- *glyphs:* in-app icons for MuseScore's buttons and menus are not currently + part of the assets build (they are in [../mscore/data/icons][glyphs]). + +[resources]: resources "Textures and basic shapes used in other assets" +[brand]: brand "Logos" +[platform]: platform "App and document icons used by the operating system" +[splash]: splash "Splash screen images displayed during MuseScore's startup" +[glyphs]: ../mscore/data/icons "Icons for MuseScore's buttons and menus" + +The [platform] directory produces assets that must integrate into the user's +desktop environment (file manager and system menu). This means there are extra +requirements for those files, as explained in the [platform README]. + +[platform README]: platform/README.md + +## Building the assets +[Building the assets]: #building-the-assets + +The assets can be built automatically as part of MuseScore's build, or they +can be built separately (i.e. without building MuseScore). This is useful for +development and testing purposes. + +Like MuseScore, the assets build uses the [CMake build system], and the steps +are pretty much the same as for any CMake project. + +[CMake build system]: https://cmake.org/ + +### Building with MuseScore +[Building with MuseScore]: #building-with-musescore + +Follow the [instructions to compile MuseScore][MuseScore compilation] and +ensure it is building and running correctly. + +[MuseScore compilation]: https://musescore.org/en/handbook/developers-handbook/compilation "MuseScore Developers Handbook - Compilation" + +MuseScore has a build option called `DOWNLOAD_ASSETS` which disables the +assets build and causes assets to be download pre-built. This option is +enabled by default to save time and reduce the number of dependencies +developers have to install on their machines. + +If you want to build the assets simply set MuseScore's `DOWNLOAD_ASSETS` build +option to `OFF` and then run the build again. The build will probably fail now +due to missing programs or fonts, so see the [Dependencies] section to get it +working again. + +MuseScore has another build option `ONLY_BUILD_ASSETS` that you can enable if +you want MuseScore's build to finish as soon as the assets have finished +building (i.e. you are not interested in compiling MuseScore itself). This is +useful when working on the assets, but you should always run a complete build +of MuseScore before contributing any changes to the assets, as some changes +will require MuseScore's own build process to be updated. + +When building with MuseScore the assets are built inside the assets sub-folder +of MuseScore's build directory (i.e. `build.debug/assets` or similar). + +### Building Alone +[Building Alone]: #building-alone + +MuseScore's build takes much longer than the assets build alone, so you may +want to build the assets without building MuseScore. This saves time when +working on the assets and can help you to gain experience with CMake. + +Note that you will still need MuseScore's source code (since the assets are +part of it), and it will be very helpful if you have already managed to build +MuseScore in the past, with or without the assets. + +Thanks to the fact CMake does out of source builds (i.e. builds are done in a +separate directory to the source code) you can continue to use the same source +tree for MuseScore's builds, assets builds, and combined builds. + +#### The First Build +[The First Build]: #the-first-build + +Assuming you have already downloaded MuseScore's source code and managed to +compile it, to access the assets source code all you need to do is change +directory into the assets folder: + +```bash +cd /path/to/MuseScore/assets +``` + +Once inside the assets source directory you can ignore everything outside it +and simply (try to) build the assets as you would any other CMake project: + +```bash +mkdir build # create a directory for the assets build +cd build +cmake .. # this is the `configure` step (notice the two dots/periods) +cmake --build . # this is the `build` step (notice the single dot/period) +``` + +These commands are __likely to fail__ at the `configure` step, but don't worry +as we will try to get it working in the next couple of sections. + +__Tip:__ CMake version 3.12 and later have a `-j` option to specify the number +of parallel build jobs to run. The more jobs you run the faster the build, up +to a point, but if you run too many the build will go more slowly and your +computer may hang (become unresponsive) until the build is complete. The +optimum number of build jobs is usually the same as the number of physical CPU +cores in your machine, or twice that number if your CPU has hyper-threading: + +``` +cmake --build -j8 . # `build` step with 4 cores + HT (8 logical cores) +``` + +Most systems report the number of logical cores rather than the number of +physical cores, so you don't need to double it. + +##### CMake Generators +[CMake Generators]: #cmake-generators + +Read this section if you see an error like this when trying to run CMake: + +- `CMake Error: CMake was unable to find a build program corresponding to "[name of generator]".` + +CMake doesn't actually perform the `build` step itself. Instead, it calls a +[native build tool] to do the work. CMake's job is to _generate_ instructions +for the native build tool (it does this during the `configure` step). + +[native build tool]: https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html "Native build tools supported by CMake" + +The error message means that CMake couldn't find the native build tool it was +trying to generate instructions for. You could solve this issue by installing +the program mentioned in the message, or by telling CMake to use another build +tool that you know is already installed. + +If you have managed to compile MuseScore before then __you already have a +build tool installed__. Run `cmake --help` and look under "generators" to see +a list of build tools supported on your system. Compare this list with the +programs you installed while following [MuseScore's compilation guide] to work +out which build tool you have installed. + +[MuseScore's compilation guide]: https://musescore.org/en/handbook/developers-handbook/compilation "MuseScore Developers Handbook - Compilation" + +Once you know which build tool you have, you can use CMake's `-G` (generator) +option to specify the build tool to generate for during the `configure` step: + +```bash +cmake "-GXcode" .. # `configure` step for Xcode on macOS +``` + +Sometimes you also need to tell CMake what the build tool is called on the +command line. You do this by defining (with `-D`) the CMake variable +[`CMAKE_MAKE_PROGRAM`][CMAKE_MAKE_PROGRAM] during the `configure` step: + +[CMAKE_MAKE_PROGRAM]: https://cmake.org/cmake/help/latest/variable/CMAKE_MAKE_PROGRAM.html "CMAKE_MAKE_PROGRAM CMake Variable" + +```bash +# `configure` step for MinGW Make on Windows +cmake "-GMinGW" "-DCMAKE_MAKE_PROGRAM=mingw32-make.exe" .. +``` + +Once the configuration is done you need to run the native build tool on the +build script that CMake generated for it. Each build tool has a different name +and takes different options. Fortunately CMake knows how to call the one it +just generated for and it provides a `--build` option to us as a convenience: + +```bash +cmake --build . # `build` step with any native build tool +``` + +CMake's job was done during the `configure` step, so this command doesn't do +anything except call the native build tool. + +##### Dependencies +[Dependencies]: #dependencies + +The first time you try to build the assets project you are likely to get an +error message saying the build has failed due to a missing dependency: + +- `Program not found: [name of program]` +- `Font not found: [name of font]` +- `Variable not defined: [name of variable]` + +###### Fonts and Programs + +For missing fonts and programs, simply install the required program or font +and run CMake again. If the program has been installed and still is not found +then make sure its location is included in your `PATH` environment variable. + +###### Variables + +If variables are not defined then you can set the `STRICT_VARIABLES` option to +`OFF` to allow the build to proceed using default values. This can be done by +calling CMake with the `-D` (define) option during the `configure` step: + +```bash +cmake "-DSTRICT_VARIABLES=OFF" .. # `configure` step with option specified +``` + +This is OK for development and testing, but for production use you should +leave the `STRICT_VARIABLES` option enabled and instead give appropriate +values to the variables, again using the `-D` flag: + +```bash +cmake "-DVAR1=Val 1" "-DVAR2=Val 2" .. # `configure` step with variables set +``` + +You shouldn't see the `Variable not defined` message when building the assets +as part of MuseScore's build. If you do see it then make sure the relevant +variables are set in [MuseScore's CMakeLists.txt] *before* the assets project +gets called (i.e. before the line `add_subdirectory(assets)`). + +[MuseScore's CMakeLists.txt]: ../CMakeLists.txt + +#### Subsequent Builds +[Subsequent Builds]: #subsequent-builds + +The `configure` step only has to be done on the first build. On subsequent +builds it is enough to simply run `cmake --build .` to rebuild any files that +have changed. + +If you run into problems you can try running `cmake --build --target clean .` +to delete all generated files, thereby forcing them all to be built again the +next time you run `cmake --build .`. (You can also use the all-in-one command +`cmake --build --clean-first .`.) + +If cleaning doesn't fix the problem then you can try starting from scratch by +making a fresh build directory and doing the `configure` step again. + +## Contributing to the Assets +[Contributing to the Assets]: #contributing-to-the-assets + +The assets sub-project is very different to the rest of MuseScore's source +code, so make sure you read the [CONTRIBUTING file][CONTRIBUTING.md] before +you make any changes to the code. + +## Using Assets in MuseScore's Build and Other Projects +[Using Assets in MuseScore's Build]: #using-assets-in-musescores-build + +When it comes to the assets, MuseScore's build must only make use of: + +- The assets CMakeLists.txt (used to trigger the assets build). +- Generated files listed in [assets-manifest.txt]. +- The assets archive (ZIP file that contains all assets in the manifest). + +Those files represent the API for the assets project. Everything else is an +implementation detail and off-limits to projects using the assets. + +MuseScore's build shouldn't modify the asset files in any way, except to: + +- Move or rename the files as necessary to install them on the user's system. +- Change their timestamps or file permissions as necessary to bundle them for + distribution. +- Embed them in an installation package or binary executable. + +All other modifications, including conversion to other image formats, should +be done as part of the assets build. + +[MuseScore's CMakeLists.txt] defines a variable called `ASSETS_BINARY_DIR`, +which points to where the asset files are built or downloaded. Simply look for +the file you need in [assets-manifest.txt] and reference its path like this: + +```cmake +"${ASSETS_BINARY_DIR}/path/to/asset/file.ext" + +``` + +Assets are built during the `build` step, which occurs when the native build +tool is run (usually either Make, Xcode or MSCV). This means the assets are +*not* available during the `configure` step when CMake is run, so you can't +use commands like [`file(COPY)`] with the assets. However, since you already +know what the asset filepaths will be you can use [`configure_file()`] to +embed asset paths in source files such as [Qt Resources] (`.qrc` files). +(Source files are not compiled until the `build` step, so the assets will be +available by then.) + +[`file(COPY)`]: https://cmake.org/cmake/help/latest/command/file.html "CMake commands - file()" +[`configure_file()`]: https://cmake.org/cmake/help/latest/command/configure_file.html "CMake commands - configure_file()" +[Qt Resources]: https://doc.qt.io/qt-5/resources.html + +You can also use the assets with custom commands inside build targets (see +[`add_custom_target()`] and [`add_custom_command()`]) as the targets do not +run until the `build` step, but make sure that the commands you use will work +on all platforms. (CMake provides a number of cross-platform command line +tools which you can access using the `-E` option, such as `cmake -E copy` to +copy files and `cmake -E rename` to move or rename them. See the [man page].) +However, it is best to avoid custom commands if possible as there are better +ways to do this. The only reason to use custom commands would be if you have +to do something that can *only* be done during the `build` step. + +[man page]: https://cmake.org/cmake/help/latest/manual/cmake.1.html#command-line-tool-mode "CMake Command Line Options" + +Naturally, it is safe to use the assets with any commands or scripts that run +after the `build` step is complete (e.g. in the `install` or `package` steps). +If all you need to do is copy an asset straight from where it was generated +to its final destination, without any modification other than renaming it or +changing file permissions, then this is best done with the [`install()`] +command. + +[`add_custom_command()`]: https://cmake.org/cmake/help/latest/command/add_custom_command.html "CMake commands - add_custom_command()" +[`add_custom_target()`]: https://cmake.org/cmake/help/latest/command/add_custom_target.html "CMake commands - add_custom_target()" +[`install()`]: https://cmake.org/cmake/help/latest/command/install.html "CMake commands - install()" diff --git a/assets/assets-manifest.txt b/assets/assets-manifest.txt new file mode 100644 index 0000000000000..edf08eb04eaaf --- /dev/null +++ b/assets/assets-manifest.txt @@ -0,0 +1,83 @@ +# DO NOT EDIT!!! This file is generated during the build. +brand/mscore-logo.svg +platform/app-icons/musescore-icon-round.svg +platform/app-icons/musescore-icon-round.ico +platform/app-icons/musescore-icon-round.icns +platform/app-icons/musescore-icon-round_16x16.png +platform/app-icons/musescore-icon-round_22x22.png +platform/app-icons/musescore-icon-round_24x24.png +platform/app-icons/musescore-icon-round_32x32.png +platform/app-icons/musescore-icon-round_48x48.png +platform/app-icons/musescore-icon-round_64x64.png +platform/app-icons/musescore-icon-round_96x96.png +platform/app-icons/musescore-icon-round_128x128.png +platform/app-icons/musescore-icon-round_256x256.png +platform/app-icons/musescore-icon-round_512x512.png +platform/app-icons/musescore-icon-square.svg +platform/app-icons/musescore-icon-square.ico +platform/app-icons/musescore-icon-square.icns +platform/app-icons/musescore-icon-square_16x16.png +platform/app-icons/musescore-icon-square_22x22.png +platform/app-icons/musescore-icon-square_24x24.png +platform/app-icons/musescore-icon-square_32x32.png +platform/app-icons/musescore-icon-square_48x48.png +platform/app-icons/musescore-icon-square_64x64.png +platform/app-icons/musescore-icon-square_96x96.png +platform/app-icons/musescore-icon-square_128x128.png +platform/app-icons/musescore-icon-square_256x256.png +platform/app-icons/musescore-icon-square_512x512.png +platform/file-icons/mscx.svg +platform/file-icons/mscx.ico +platform/file-icons/mscx.icns +platform/file-icons/mscx_16x16.png +platform/file-icons/mscx_22x22.png +platform/file-icons/mscx_24x24.png +platform/file-icons/mscx_32x32.png +platform/file-icons/mscx_48x48.png +platform/file-icons/mscx_64x64.png +platform/file-icons/mscx_96x96.png +platform/file-icons/mscx_128x128.png +platform/file-icons/mscx_256x256.png +platform/file-icons/mscx_512x512.png +platform/file-icons/mscz.svg +platform/file-icons/mscz.ico +platform/file-icons/mscz.icns +platform/file-icons/mscz_16x16.png +platform/file-icons/mscz_22x22.png +platform/file-icons/mscz_24x24.png +platform/file-icons/mscz_32x32.png +platform/file-icons/mscz_48x48.png +platform/file-icons/mscz_64x64.png +platform/file-icons/mscz_96x96.png +platform/file-icons/mscz_128x128.png +platform/file-icons/mscz_256x256.png +platform/file-icons/mscz_512x512.png +platform/file-icons/xml.svg +platform/file-icons/xml.ico +platform/file-icons/xml.icns +platform/file-icons/xml_16x16.png +platform/file-icons/xml_22x22.png +platform/file-icons/xml_24x24.png +platform/file-icons/xml_32x32.png +platform/file-icons/xml_48x48.png +platform/file-icons/xml_64x64.png +platform/file-icons/xml_96x96.png +platform/file-icons/xml_128x128.png +platform/file-icons/xml_256x256.png +platform/file-icons/xml_512x512.png +platform/file-icons/mxl.svg +platform/file-icons/mxl.ico +platform/file-icons/mxl.icns +platform/file-icons/mxl_16x16.png +platform/file-icons/mxl_22x22.png +platform/file-icons/mxl_24x24.png +platform/file-icons/mxl_32x32.png +platform/file-icons/mxl_48x48.png +platform/file-icons/mxl_64x64.png +platform/file-icons/mxl_96x96.png +platform/file-icons/mxl_128x128.png +platform/file-icons/mxl_256x256.png +platform/file-icons/mxl_512x512.png +splash/splash-stable.svg +splash/splash-nightly.svg +splash/splash-development.svg diff --git a/assets/basic-functions.cmake b/assets/basic-functions.cmake new file mode 100644 index 0000000000000..d3bc92225439a --- /dev/null +++ b/assets/basic-functions.cmake @@ -0,0 +1,106 @@ +function(required_program # ensure that a build dependency is installed + PATHV # location of the program returned in this variable + DESCRIPTION # build fails with this error message if program is missing + COMMAND # the name of the program on the command line + # ARGN any alternative names for the command + ) + set(CMAKE_FIND_APPBUNDLE "NEVER") # macOS: don't search for .app bundles + find_program(${PATHV} NAMES ${COMMAND} ${ARGN} DOC "${DESCRIPTION}") + if(NOT ${PATHV} OR NOT EXISTS "${${PATHV}}") + # Fail the build, but use SEND_ERROR instead of FATAL_ERROR to allow other + # checks to complete (show all missing dependencies, not just the first) + message(SEND_ERROR "Program not found: ${COMMAND} - ${DESCRIPTION}") + endif(NOT ${PATHV} OR NOT EXISTS "${${PATHV}}") +endfunction(required_program) + +function(required_variable # ensure that a required variable has been set + NAMEV # the name of the variable + DEFAULT_VALUE # a value to store in the variable if it was not already set + ) + if(NOT DEFINED "${NAMEV}") + if(STRICT_VARIABLES) + # Fail the build, but use SEND_ERROR instead of FATAL_ERROR to allow other + # checks to complete (show all missing dependencies, not just the first) + message(SEND_ERROR "Variable not defined: ${NAMEV}") + else(STRICT_VARIABLES) + message(STATUS "Using default value for ${NAMEV}: \"${DEFAULT_VALUE}\"") + set("${NAMEV}" "${DEFAULT_VALUE}" PARENT_SCOPE) + endif(STRICT_VARIABLES) + endif(NOT DEFINED "${NAMEV}") +endfunction(required_variable) + +function(assert # ensure a condition is met (CI Test) + STATEMENT # the first part of the condition statement + # ARGN any more parts of the condition statement + ) + if(NOT (${STATEMENT} ${ARGN})) + set(ASSERTION "") # empty string ("unset()" exposes cached values) + string(REPLACE ";" " " ASSERTION "${STATEMENT} ${ARGN}") + message(FATAL_ERROR "Assertion failed: ${ASSERTION}\n" + "please fix the code responsible to allow the build to proceed") + endif(NOT (${STATEMENT} ${ARGN})) +endfunction(assert) + +function(min_index # find the smallest value in a list of numbers + MINV # minimum value returned in this variable + IDXV # index of its first occurance returned in this variable + # ARGN remaining arguments are items in the list + ) + set(MIN_IDX 0) # start by assuming first item in list is the smallest + list(GET ARGN ${MIN_IDX} MIN_VAL) # store its value for comparison + set(IDX 0) # keep track of where we are in the list + foreach(VAL ${ARGN}) + if(VAL LESS MIN_VAL) + set(MIN_VAL ${VAL}) + set(MIN_IDX ${IDX}) + endif(VAL LESS MIN_VAL) + math(EXPR IDX "${IDX}+1") # increment IDX + endforeach(VAL) + set("${MINV}" "${MIN_VAL}" PARENT_SCOPE) + set("${IDXV}" "${MIN_IDX}" PARENT_SCOPE) +endfunction(min_index) + +set(TEST_LIST 7 -2 20 -5 0 3 8) +min_index(TEST_MIN TEST_IDX ${TEST_LIST}) +assert(TEST_MIN EQUAL -5 AND TEST_IDX EQUAL 3) + +function(sort_integer_list # sort list of integers into ascending order + LISTV # list variable to be sorted + ) + set(LIST "${${LISTV}}") + list(LENGTH LIST LEN) + if(LEN GREATER 1) + min_index(MIN IDX ${LIST}) # find smallest value + list(REMOVE_AT LIST ${IDX}) # remove smallest value + sort_integer_list(LIST) # sort the list that remains (recursion) + set(${LISTV} ${MIN} ${LIST} PARENT_SCOPE) + endif(LEN GREATER 1) +endfunction(sort_integer_list) + +sort_integer_list(TEST_LIST) +set(TEST_SORT -5 -2 0 3 7 8 20) +assert(TEST_LIST STREQUAL TEST_SORT) + +function(assert_ascending # ensure a list of integers is in ascending order + LISTV # list variable to be checked + ) + set(LIST "${${LISTV}}") + set(SORTED "${LIST}") + sort_integer_list(SORTED) + if(NOT LIST STREQUAL SORTED) + message(FATAL_ERROR "Assertion failed: ${LISTV} in ascending order.\n" + "Please sort the list into ascending order to allow build to proceed.") + endif(NOT LIST STREQUAL SORTED) +endfunction(assert_ascending) + +function(assert_alphabetical # ensure list of strings is in alphabetical order + LISTV # list variable to be checked + ) + set(LIST "${${LISTV}}") + set(SORTED "${LIST}") + list(SORT SORTED) + if(NOT LIST STREQUAL SORTED) + message(FATAL_ERROR "Assertion failed: ${LISTV} in alphabetical order.\n" + "Please sort the list into alphabetical order to allow build to proceed.") + endif(NOT LIST STREQUAL SORTED) +endfunction(assert_alphabetical) diff --git a/assets/brand/CMakeLists.txt b/assets/brand/CMakeLists.txt new file mode 100644 index 0000000000000..b4535f669924e --- /dev/null +++ b/assets/brand/CMakeLists.txt @@ -0,0 +1,22 @@ +set(SOURCE_FILES + mscore-logo.svg.xml + ) + +assert_alphabetical(SOURCE_FILES) # keep list ordered for easier maintenance + +set(GENERATED_FILES "") # create empty list + +foreach(FILE ${SOURCE_FILES}) + get_filename_component(FILEBASE "${FILE}" NAME_WE) # strip file extensions + standalone_svg("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" "${FILEBASE}-standalone.svg" "../resources/mscore.svg") + optimize_svg("${FILEBASE}-standalone.svg" "${FILEBASE}.svg") + list(APPEND GENERATED_FILES "${FILEBASE}.svg") +endforeach(FILE) + +# custom build commands above will only run if a target depends on their output +add_custom_target("assets_brand" DEPENDS ${GENERATED_FILES}) +# must make sure the commands don't run until after the resources are built +add_dependencies("assets_brand" "assets_resources") +# ensure that this target gets built when the main assets target is built +add_dependencies("assets" "assets_brand") +add_to_manifest(${GENERATED_FILES}) diff --git a/assets/brand/mscore-logo.svg.xml b/assets/brand/mscore-logo.svg.xml new file mode 100644 index 0000000000000..d59345d0f2eb0 --- /dev/null +++ b/assets/brand/mscore-logo.svg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/font-dependencies.cmake b/assets/font-dependencies.cmake new file mode 100644 index 0000000000000..e2fd081aee9cc --- /dev/null +++ b/assets/font-dependencies.cmake @@ -0,0 +1,57 @@ +set(BUILT_IN_MSG "This tool should be built-in. Check your PATH environment variable.") +if(WIN32) + required_program(REG "Access Windows Registry - ${BUILT_IN_MSG}" "reg") + required_program(FINDSTR "Search for matching strings - ${BUILT_IN_MSG}" "findstr") +elseif(APPLE) + required_program(SYSTEM_PROFILER "Report system configuration - ${BUILT_IN_MSG}" "system_profiler") + required_program(GREP "Search for matching strings - ${BUILT_IN_MSG}" "grep") +elseif(UNIX) # Linux and friends + required_program(FC_LIST "List available fonts - https://www.freedesktop.org/wiki/Software/fontconfig/" "fc-list") + required_program(GREP "Search for matching strings - ${BUILT_IN_MSG}" "grep") +endif(WIN32) + +function(required_font # ensure that a font dependency is installed + CACHEV # cache this variable if font is found to avoid checking in future + DESCRIPTION # build fails with this error message if font is missing + FONT_NAME # the name of the font (e.g. "Roboto") + ) + unset(${CACHEV}) # expose cached value (if any) + if(NOT DEFINED ${CACHEV}) + message(STATUS "Checking font '${FONT_NAME}' is installed.") + if(WIN32) + execute_process( + COMMAND "${REG}" query "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" + COMMAND "${FINDSTR}" /r "/c:^ *${FONT_NAME} (OpenType)" "/c:^ *${FONT_NAME} (TrueType)" + RESULT_VARIABLE RET_VAL + OUTPUT_QUIET + ) + elseif(APPLE) + execute_process( + COMMAND "${SYSTEM_PROFILER}" "SPFontsDataType" + COMMAND "${GREP}" -B9 -A13 "^ *Family: ${FONT_NAME}$" + RESULT_VARIABLE RET_VAL + OUTPUT_QUIET + ) + elseif(UNIX) # Linux and friends + execute_process( + COMMAND "${FC_LIST}" + COMMAND "${GREP}" -E "^[^:]+\\.(ttf|otf): ${FONT_NAME}:style=" + RESULT_VARIABLE RET_VAL + OUTPUT_QUIET + ) + endif(WIN32) + if(RET_VAL STREQUAL "0") # string compare as RET_VAL not always a number + # Font is installed so no need to check again on future CMake runs + set(${CACHEV} "FOUND" CACHE INTERNAL "${FONT_NAME} - ${DESCRIPTION}") + else(RET_VAL STREQUAL "0") + # Fail the build, but use SEND_ERROR instead of FATAL_ERROR to allow other + # checks to complete (show all missing dependencies, not just the first) + message(SEND_ERROR "Font not found: ${FONT_NAME} - ${DESCRIPTION}") + endif(RET_VAL STREQUAL "0") + endif(NOT DEFINED ${CACHEV}) +endfunction(required_font) + +# Keep this list up-to-date. Run "grep -r font-family ." from the assets +# source directory to list fonts used in SVGs anywhere in the project. +required_font(ROBOTO_FONT "https://fonts.google.com/specimen/Roboto" "Roboto") +required_font(RALEWAY_FONT "https://fonts.google.com/specimen/Raleway" "Raleway") diff --git a/assets/image-functions.cmake b/assets/image-functions.cmake new file mode 100644 index 0000000000000..7329735870fb0 --- /dev/null +++ b/assets/image-functions.cmake @@ -0,0 +1,121 @@ +required_program(INKSCAPE "SVG vector graphics editing program - https://inkscape.org/" "inkscape") +required_program(XMLLINT "Tool for parsing XML files - http://xmlsoft.org/xmllint.html" "xmllint") + +if(OPTIMIZE_SVGS) + required_program(SVGO "Tool for optimizing SVG vector graphics files - https://github.com/svg/svgo" "svgo") +endif(OPTIMIZE_SVGS) + +if(OPTIMIZE_PNGS) + required_program(PNGCRUSH "Tool for optimizing PNG image files losslessly - https://pmt.sourceforge.io/pngcrush/" "pngcrush") +endif(OPTIMIZE_PNGS) + +# Need a function to convert relative paths to absolute paths: +# +# 1. CMake's add_custom_command() gives inconsistent results if relative +# paths are used for its DEPENDS argument (see below). +# 2. Inkscape must be called with absolute paths on macOS. See +# https://bugs.launchpad.net/inkscape/+bug/181639. +# +# All path arguments to add_custom_command() are relative to the current build +# directory (CMAKE_CURRENT_BINARY_DIR), except for some reason DEPENDS is +# relative to the source directory (CMAKE_CURRENT_SOURCE_DIR). However, if the +# named dependency was generated as OUTPUT to a previous add_custom_command() +# then DEPENDS becomes relative to build directory again! +function(absolute_path # prepend CMAKE_CURRENT_BINARY_DIR to relative paths + ABS_PATHV # absolute path is returned through this variable + PATH # input path - can be relative or absolute + ) + if(IS_ABSOLUTE "${PATH}") + set("${ABS_PATHV}" "${PATH}" PARENT_SCOPE) + else(IS_ABSOLUTE "${PATH}") + set("${ABS_PATHV}" "${CMAKE_CURRENT_BINARY_DIR}/${PATH}" PARENT_SCOPE) + endif(IS_ABSOLUTE "${PATH}") +endfunction(absolute_path) + +function(copy_during_build # copy a file at build time + SOURCE_FILE # path to file being copied + DEST_FILE # path to new location + ) + absolute_path(SOURCE_FILE_ABS "${SOURCE_FILE}") # needed for DEPENDS + add_custom_command( + OUTPUT "${DEST_FILE}" # relative path required + DEPENDS "${SOURCE_FILE_ABS}" # absolute path required + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SOURCE_FILE}" "${DEST_FILE}" + VERBATIM + ) +endfunction(copy_during_build) + +function(standalone_svg # resolve and embed an SVG's external dependencies + SVG_FILE_IN # path to the input SVG + SVG_FILE_OUT # path where the output SVG will be written + # ARGN remaining arguments are additional dependencies + ) + absolute_path(SVG_FILE_IN_ABS "${SVG_FILE_IN}") # needed for DEPENDS + absolute_path(SVG_FILE_OUT_ABS "${SVG_FILE_OUT}") # needed for Inkscape on macOS + set(DEPENDENCIES "") # empty list + foreach(DEPENDENCY ${ARGN}) + absolute_path(DEPENDENCY_ABS "${DEPENDENCY}") # needed for DEPENDS + list(APPEND DEPENDENCIES "${DEPENDENCY_ABS}") + endforeach(DEPENDENCY) + add_custom_command( + OUTPUT "${SVG_FILE_OUT}" # relative path required + DEPENDS "${SVG_FILE_IN_ABS}" ${DEPENDENCIES} # absolute paths required + COMMAND "${XMLLINT}" "${SVG_FILE_IN}" --xinclude --pretty 1 --output "${SVG_FILE_OUT}" + COMMAND "${INKSCAPE}" "${SVG_FILE_OUT_ABS}" --verb=EditSelectAll --verb=org.ekips.filter.embedselectedimages --verb=FileSave --verb=FileQuit + COMMAND "${INKSCAPE}" -z "${SVG_FILE_OUT_ABS}" --export-text-to-path --vacuum-defs --export-plain-svg "${SVG_FILE_OUT_ABS}" + VERBATIM + ) +endfunction(standalone_svg) + +function(optimize_svg # reduce size of an SVG without changing its appearance + SVG_FILE_IN # path to the input SVG + SVG_FILE_OUT # path where the output SVG will be written + ) + if(OPTIMIZE_SVGS) + absolute_path(SVG_FILE_IN_ABS "${SVG_FILE_IN}") # needed for DEPENDS + add_custom_command( + OUTPUT "${SVG_FILE_OUT}" # relative path required + DEPENDS "${SVG_FILE_IN_ABS}" # absolute path required + COMMAND "${SVGO}" "${SVG_FILE_IN}" -o "${SVG_FILE_OUT}" + VERBATIM + ) + else(OPTIMIZE_SVGS) + copy_during_build("${SVG_FILE_IN}" "${SVG_FILE_OUT}") + endif(OPTIMIZE_SVGS) +endfunction(optimize_svg) + +function(rasterize_svg # convert SVG to PNG + SVG_FILE_IN # path to the input SVG + PNG_FILE_OUT # path where the output PNG will be written + # ARGN any additional arguments will be passed to inkscape + ) + absolute_path(SVG_FILE_IN_ABS "${SVG_FILE_IN}") # needed for DEPENDS + absolute_path(PNG_FILE_OUT_ABS "${PNG_FILE_OUT}") # needed for Inkscape on macOS + add_custom_command( + OUTPUT "${PNG_FILE_OUT}" # relative path required + DEPENDS "${SVG_FILE_IN_ABS}" # absolute path required + COMMAND "${INKSCAPE}" -z "${SVG_FILE_IN_ABS}" ${ARGN} --export-png "${PNG_FILE_OUT_ABS}" + VERBATIM + ) +endfunction(rasterize_svg) + +function(optimize_png # reduce size of a PNG without changing its appearance + PNG_FILE_IN # path to the input PNG + PNG_FILE_OUT # path where the output PNG will be written + ) + if(OPTIMIZE_PNGS) + set(OPTS -rem allb) + if (OPTIMIZE_PNGS_BRUTE) + list(APPEND OPTS -brute) + endif(OPTIMIZE_PNGS_BRUTE) + absolute_path(PNG_FILE_IN_ABS "${PNG_FILE_IN}") # needed for DEPENDS + add_custom_command( + OUTPUT "${PNG_FILE_OUT}" # relative path required + DEPENDS "${PNG_FILE_IN_ABS}" # absolute path required + COMMAND "${PNGCRUSH}" ${OPTS} "${PNG_FILE_IN}" "${PNG_FILE_OUT}" + VERBATIM + ) + else(OPTIMIZE_PNGS) + copy_during_build("${PNG_FILE_IN}" "${PNG_FILE_OUT}") + endif(OPTIMIZE_PNGS) +endfunction(optimize_png) diff --git a/assets/msc-icon-master.svg b/assets/msc-icon-master.svg deleted file mode 100644 index d7789507067ab..0000000000000 --- a/assets/msc-icon-master.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - msc-icon-master - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSCZ - - - \ No newline at end of file diff --git a/assets/mscx-icon-48.png b/assets/mscx-icon-48.png deleted file mode 100644 index f6055a2965df6..0000000000000 Binary files a/assets/mscx-icon-48.png and /dev/null differ diff --git a/assets/mscx-icon.svg b/assets/mscx-icon.svg deleted file mode 100644 index 9ce104d8860e7..0000000000000 --- a/assets/mscx-icon.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - mscx-icon - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSCX - - - \ No newline at end of file diff --git a/assets/mscz-icon-48.png b/assets/mscz-icon-48.png deleted file mode 100644 index 6e81684f6635d..0000000000000 Binary files a/assets/mscz-icon-48.png and /dev/null differ diff --git a/assets/mscz-icon.svg b/assets/mscz-icon.svg deleted file mode 100644 index 3e2ee9039a83d..0000000000000 --- a/assets/mscz-icon.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - mscz-icon - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSCZ - - - \ No newline at end of file diff --git a/assets/musescore-icon-round-1024.png b/assets/musescore-icon-round-1024.png deleted file mode 100755 index 0ee0ed3e8761b..0000000000000 Binary files a/assets/musescore-icon-round-1024.png and /dev/null differ diff --git a/assets/musescore-icon-round-128.png b/assets/musescore-icon-round-128.png deleted file mode 100755 index d2fcf5df1cbdc..0000000000000 Binary files a/assets/musescore-icon-round-128.png and /dev/null differ diff --git a/assets/musescore-icon-round-16.png b/assets/musescore-icon-round-16.png deleted file mode 100755 index 717b366550bce..0000000000000 Binary files a/assets/musescore-icon-round-16.png and /dev/null differ diff --git a/assets/musescore-icon-round-2048.png b/assets/musescore-icon-round-2048.png deleted file mode 100755 index a73dd0899220a..0000000000000 Binary files a/assets/musescore-icon-round-2048.png and /dev/null differ diff --git a/assets/musescore-icon-round-24.png b/assets/musescore-icon-round-24.png deleted file mode 100755 index 8a97aeb7a835a..0000000000000 Binary files a/assets/musescore-icon-round-24.png and /dev/null differ diff --git a/assets/musescore-icon-round-32.png b/assets/musescore-icon-round-32.png deleted file mode 100755 index ebed21120d8e4..0000000000000 Binary files a/assets/musescore-icon-round-32.png and /dev/null differ diff --git a/assets/musescore-icon-round-48.png b/assets/musescore-icon-round-48.png deleted file mode 100755 index d7797f69104c0..0000000000000 Binary files a/assets/musescore-icon-round-48.png and /dev/null differ diff --git a/assets/musescore-icon-round-512.png b/assets/musescore-icon-round-512.png deleted file mode 100755 index 52f25ef5a5dfb..0000000000000 Binary files a/assets/musescore-icon-round-512.png and /dev/null differ diff --git a/assets/musescore-icon-round-64.png b/assets/musescore-icon-round-64.png deleted file mode 100755 index 616cfbe5a7e87..0000000000000 Binary files a/assets/musescore-icon-round-64.png and /dev/null differ diff --git a/assets/musescore-icon-round-96.png b/assets/musescore-icon-round-96.png deleted file mode 100644 index 7587546c34d48..0000000000000 Binary files a/assets/musescore-icon-round-96.png and /dev/null differ diff --git a/assets/musescore-icon-round.svg b/assets/musescore-icon-round.svg deleted file mode 100644 index 0e67e3b8ed8d6..0000000000000 --- a/assets/musescore-icon-round.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - musescore-icon-round - Created with Sketch. - - - - - - - - - - - \ No newline at end of file diff --git a/assets/musicxml-icon-master.svg b/assets/musicxml-icon-master.svg deleted file mode 100644 index c20ddf4fde7c5..0000000000000 --- a/assets/musicxml-icon-master.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - musicxml-icon-master - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MXL - - - - - - - \ No newline at end of file diff --git a/assets/mxl-icon-48.png b/assets/mxl-icon-48.png deleted file mode 100644 index c9e8f09dece6f..0000000000000 Binary files a/assets/mxl-icon-48.png and /dev/null differ diff --git a/assets/mxl-icon.svg b/assets/mxl-icon.svg deleted file mode 100644 index ccb240c90af69..0000000000000 --- a/assets/mxl-icon.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - mxl-icon - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MXL - - - - - - - \ No newline at end of file diff --git a/assets/platform/CMakeLists.txt b/assets/platform/CMakeLists.txt new file mode 100644 index 0000000000000..ce8d877bfa6ef --- /dev/null +++ b/assets/platform/CMakeLists.txt @@ -0,0 +1,33 @@ +include("icon-functions.cmake") + +if(BUILD_WINDOWS_ICONS) + # https://docs.microsoft.com/en-gb/windows/desktop/uxguide/vis-icons + set(WINDOWS_ICO_SIZES 16 24 32 48 64 96 128 256) + assert_ascending(WINDOWS_ICO_SIZES) # keep ordered for easy maintainability +else(BUILD_WINDOWS_ICONS) + set(WINDOWS_ICO_SIZES "") # empty list ("unset" exposes cached values) +endif(BUILD_WINDOWS_ICONS) + +if(BUILD_MACOS_ICONS) + # https://stackoverflow.com/a/11788723 + set(MACOS_ICNS_SIZES 16 32 128 256 512) # sizes in "points" not pixels + assert_ascending(MACOS_ICNS_SIZES) +else(BUILD_MACOS_ICONS) + set(MACOS_ICNS_SIZES "") +endif(BUILD_MACOS_ICONS) + +if(BUILD_FREEDESKTOP_ICONS) + # Look in /usr/share/icons/hicolor and find subdirectories with most files + set(FREEDESKTOP_COMMON_SIZES 16 22 24 32 48 64 96 128 256 512) + assert_ascending(FREEDESKTOP_COMMON_SIZES) +else(BUILD_FREEDESKTOP_ICONS) + set(FREEDESKTOP_COMMON_SIZES "") +endif(BUILD_FREEDESKTOP_ICONS) + +set(ALL_ICON_SIZES ${WINDOWS_ICO_SIZES} ${MACOS_ICNS_SIZES} ${FREEDESKTOP_COMMON_SIZES}) + +list(REMOVE_DUPLICATES ALL_ICON_SIZES) +sort_integer_list(ALL_ICON_SIZES) + +add_subdirectory(app-icons) +add_subdirectory(file-icons) diff --git a/assets/platform/README.md b/assets/platform/README.md new file mode 100644 index 0000000000000..b5980467976b2 --- /dev/null +++ b/assets/platform/README.md @@ -0,0 +1,121 @@ +MuseScore Assets - Platform +=========================== + +Assets produced in these directories integrate into the user's home screen or +desktop environment. This includes: + +- __[app-icons]:__ Application icons displayed in app stores, launchers and + system menus. +- __[file-icons]:__ Document mime/filetype icons displayed in file managers. + +These assets are usually displayed by the operating system rather than by +MuseScore. + +[app-icons]: app-icons "Application icons displayed in system menus" +[file-icons]: file-icons "Document icons displayed in file managers" + +## Platform Requirements + +Platforms often have [technical requirements] and [style guidelines] for +assets that integrate with their systems. These requirements change frequently +to follow (or set) the latest fashions in UX design so they are not documented +here in any detail. Check the comments in the code for specific details in +places where platform requirements have affected the design and build process, +as well as links to the sources of those requirements. + +[technical requirements]: #technical-requirements +[style guidelines]: #style-guidelines + +### Technical requirements + +These include requirements to do with the file format used for icons as well +as the dimensions of the images they contain. Assets must meet at least the +most basic of these requirements otherwise they will not be displayed +correctly or at all. However, it may be safe to ignore some of the more +specialist requirements if they are not relevant to MuseScore. + +Some requirements are not dealt with as part of the assets build and are +instead handled as part of MuseScore's build or installation process. This +includes any requirements to do with final names asset files must be given and +the locations they must be placed in for the operating system to be able to +find them. The assets build is purely concerned with generating the files. + +Technical requirements mainly affect the build rules in the CMake files, so +relevant details should be mentioned in those files where they have influenced +the build process. + +### Style guidelines + +These relate to the artistic design of assets. Many platforms recommend that +designs are restricted to a particular set of shapes or colors to achieve a +consistent look and feel for all applications on that platform. While we don't +want MuseScore to look out of place on any platform, we must balance this +desire with our own requirement that MuseScore should look and feel the same +on all platforms. + +- Where platforms have guidelines that are harmonious, or at least compatible, + then we clearly should do our best to follow them. + +- Where a particular recommendation from one platform is neither encouraged or + discouraged on another platform it may nevertheless be safe to follow the + guideline on both platforms. + +- Where platforms have conflicting guidelines it may be better to adopt a + neutral style rather than favoring one set of guidelines over the other. + +Style Guidelines mainly affect the content of the SVGs, so relevant details +should be mentioned as comments in those files where they have influenced the +design. + +## Icon Formats + +The two most common icons formats are ICO (Windows) and ICNS (macOS). Linux +and BSD used to use the XPM format for icons but this has been almost +universally replaced with ordinary PNG and SVG images on those systems (more +on this below). + +The ICO and ICNS formats are containers for holding multiple images, or more +commonly, multiple versions of the same image. Each version can have different +image properties, such as different sizes, enabling the system to pick the +best version of the image to use depending on: + +- The monitor's size and resolution +- The average viewing distance +- The user's display settings +- Where the icon is to be used, such as: + - Item views (tree views use smaller icons than list views) + - File Open and File Save dialogs + - File managers + - Launcher menus + +Icons usually provide a range of image sizes from 16x16 pixels up to 256x256 +or higher. The smaller sizes are still regularly used even on modern devices. + +Image size is not the only property that can differ between images in the same +icon file. Other properties include bit depth (number of colors), encoding +(type of image compression), alpha transparency, or pretty much any other +property, though size is the most common one to change. + +#### HDPI / Retina displays + +Modern devices pack more pixels into the same area of screen than older +displays, so icons need to have more pixels to compensate otherwise they will +appear too small on the screen. Most platforms simply use one of the larger +image sizes when they detect that the user has a High DPI display, but Apple's +ICNS format allows special images to be embedded specifically for use with +HDPI displays (Apple calls them "Retina" displays). This means that a single +icon file might contain some sizes twice, one for use on normal displays and +one for Retina displays. The non-Retina version of a 256 x 256 pixel icon is +labelled "256x256", while the Retina version is labelled "128x128@2x". Most of +Apple's Retina displays have double the DPI of the standard DPI displays they +replaced, so 256 pixels on a Retina "@2x" display is the same physical length +(in inches) as 128 pixels on a non-Retina display. + +Of course, the ability to use different images for Retina displays is only +beneficial if you do in fact use different images. Since our images are all +generated from the same SVGs there is literally no difference between the +256x256 image and the 128x128@2x image - and there doesn't really need to be. +Apple argue that it can be beneficial to increase the stroke width in Retina +icons compared to non-Retina icons, but our icons don't make use of strokes, +and there is certainly no benefit to be had from specialization in regions of +solid color or simple gradients. diff --git a/assets/platform/app-icons/CMakeLists.txt b/assets/platform/app-icons/CMakeLists.txt new file mode 100644 index 0000000000000..8bfa9fccfd4da --- /dev/null +++ b/assets/platform/app-icons/CMakeLists.txt @@ -0,0 +1,34 @@ +set(SOURCE_FILES + musescore-icon-round.svg.xml + musescore-icon-square.svg.xml + ) + +assert_alphabetical(SOURCE_FILES) # keep list ordered for easier maintenance + +set(GENERATED_FILES "") # create empty list + +foreach(FILE ${SOURCE_FILES}) + get_filename_component(FILEBASE "${FILE}" NAME_WE) # strip file extensions + standalone_svg("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" "${FILEBASE}-standalone.svg" "../../resources/mscore.svg") + optimize_svg("${FILEBASE}-standalone.svg" "${FILEBASE}.svg") + # newer Freedesktop systems can use the SVG directly + list(APPEND GENERATED_FILES "${FILEBASE}.svg") # archive the SVG + # Need many sizes of PNG - some to archive and some to embed in icon files. + # Different platforms need different sizes, but there is some overlap. We + # create all required sizes upfront to avoid building some twice. + png_sizes(CREATE "${FILEBASE}" 1 ALL_PNGS ${ALL_ICON_SIZES}) # standard displays + png_sizes(CREATE "${FILEBASE}" 2 ALL_PNGS_2X ${MACOS_ICNS_SIZES}) # retina displays + # Windows & macOS have special icon formats that are built from a subset of + # the PNGs just created. The actual PNGs aren't needed by those platforms. + create_icon_ico("${FILEBASE}" GENERATED_ICO ${WINDOWS_ICO_SIZES}) + create_icon_icns("${FILEBASE}" GENERATED_ICNS ${MACOS_ICNS_SIZES}) + # some Freedesktop systems use PNGs as icons so we list them for archiving + png_sizes(LIST "${FILEBASE}" 1 GENERATED_PNGS ${FREEDESKTOP_COMMON_SIZES}) + # only archive files we actually need, not any used only to build other icons + list(APPEND GENERATED_FILES ${GENERATED_ICO} ${GENERATED_ICNS} ${GENERATED_PNGS}) +endforeach(FILE) + +add_custom_target("assets_platform_appicons" DEPENDS ${GENERATED_FILES}) +add_dependencies("assets_platform_appicons" "assets_resources") +add_dependencies("assets" "assets_platform_appicons") +add_to_manifest(${GENERATED_FILES}) diff --git a/assets/platform/app-icons/musescore-icon-round.svg.xml b/assets/platform/app-icons/musescore-icon-round.svg.xml new file mode 100644 index 0000000000000..8ba0ee407fdcf --- /dev/null +++ b/assets/platform/app-icons/musescore-icon-round.svg.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/platform/app-icons/musescore-icon-square.svg.xml b/assets/platform/app-icons/musescore-icon-square.svg.xml new file mode 100644 index 0000000000000..886b0376768fc --- /dev/null +++ b/assets/platform/app-icons/musescore-icon-square.svg.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/platform/file-icons/CMakeLists.txt b/assets/platform/file-icons/CMakeLists.txt new file mode 100644 index 0000000000000..6980f0bd11f46 --- /dev/null +++ b/assets/platform/file-icons/CMakeLists.txt @@ -0,0 +1,48 @@ +set(GENERATED_FILES "") # empty list + +function(filetype_icon # create filetype/mimetype icons from a source SVG + SOURCE_FILE # source SVG/XML file that may contain @TYPE@ placeholder + TYPE # file type text to substitute @TYPE@ placeholder with in source + # ARGN remaining arguments are dependencies (resources or generated files) + ) + get_filename_component(FILEBASE "${SOURCE_FILE}" NAME_WE) # strip file extensions + string(TOLOWER "${TYPE}" TYPE_LOWER) + configure_file("${SOURCE_FILE}" "${FILEBASE}_${TYPE_LOWER}.svg.xml") # substitute @TYPE@ in file + file(READ "${CMAKE_CURRENT_BINARY_DIR}/${FILEBASE}_${TYPE_LOWER}.svg.xml" YOUR_CONTENT_HERE) + string(REGEX REPLACE "^[^>]+>(.*)\n${YOUR_CONTENT_HERE}\n + + + + @TYPE@ + diff --git a/assets/platform/icon-functions.cmake b/assets/platform/icon-functions.cmake new file mode 100644 index 0000000000000..ef26eb6573ccf --- /dev/null +++ b/assets/platform/icon-functions.cmake @@ -0,0 +1,123 @@ +if(BUILD_WINDOWS_ICONS) + set(CONVERT "convert") # old name of ImageMagick's command line tool + if(WIN32) + # ImageMagick's convert conflicts with a Windows system tool of the same + # name. A common solution is to rename ImageMagick's convert binary: + set(CONVERT "imconvert") # name commonly used for "convert" on Windows + endif(WIN32) + required_program(IMAGEMAGICK "ImageMagick image tool - https://www.imagemagick.org" "magick" "${CONVERT}") +endif(BUILD_WINDOWS_ICONS) + +if(BUILD_MACOS_ICONS) + if(APPLE) + set(BUILT_IN_MSG "This tool should be built-in. Check your PATH environment variable.") + required_program(ICONUTIL "Tool to create macOS icons (libicns) - ${BUILT_IN_MSG}" "iconutil") + else(APPLE) + # NOTE: PNG2ICNS doesn't support icons for HDPI / "retina" displays. See + # https://sourceforge.net/p/icns/bugs/12/. This probably doesn't matter if + # using the same source SVG for retina and non-rentina icons anyway. + required_program(PNG2ICNS "Tool to create macOS icons (libicns) - https://icns.sourceforge.io/" "png2icns") + # There's more than one program called "png2icns". Do we have the right one? + required_program(ICNS2PNG "You have the wrong png2icns. You need libicns from https://icns.sourceforge.io/" "icns2png") + endif(APPLE) +endif(BUILD_MACOS_ICONS) + +function(size_suffix # string appended to raster names to indicate pixel size + SUFFIXV # return suffix in this variable + SIZE # integer size in "points" (device-independent pixels) + SCALE # integer device pixel ratio (number of pixels per "point") + # NOTE: PIXEL_SIZE = SIZE * SCALE (so PIXEL_SIZE = SIZE when SCALE = 1) + ) + # Follow Apple's naming scheme: https://stackoverflow.com/a/11788723 + set(SUFFIX "_${SIZE}x${SIZE}") + if(SCALE GREATER 1) + # images with SCALE > 1 are intended for use on "retina" (HDPI) displays + set(SUFFIX "${SUFFIX}@${SCALE}x") + endif(SCALE GREATER 1) + set("${SUFFIXV}" "${SUFFIX}" PARENT_SCOPE) +endfunction(size_suffix) + +function(png_sizes # perform operations on an image at different pixel sizes + VERB # must be one of: LIST, CREATE or ICONSET + FILE_BASE_PATH # path to PNGs minus any size suffix, or SVG minus extension + SCALE # integer device pixel ratio (number of pixels per "point") + PNG_PATHS_LISTV # list variable to store paths to output PNGs + # ARGN remaining arguments are integer sizes (see function "size_suffix") + ) + set(PNG_LIST "") # create empty list + foreach(SIZE ${ARGN}) + size_suffix(SIZE_SUFFIX "${SIZE}" "${SCALE}") + set(PNG_BASE_PATH "${FILE_BASE_PATH}${SIZE_SUFFIX}") # no extenion yet + if(VERB STREQUAL "CREATE") + # actually create the PNG + math(EXPR PIXELS "${SIZE} * ${SCALE}") + rasterize_svg("${FILE_BASE_PATH}.svg" "${PNG_BASE_PATH}-bloated.png" "--export-width=${PIXELS}" "--export-height=${PIXELS}") + optimize_png("${PNG_BASE_PATH}-bloated.png" "${PNG_BASE_PATH}.png") + elseif(VERB STREQUAL "ICONSET") + # copy PNGs into iconset folder: https://stackoverflow.com/a/11788723 + set(ICONSET_PNG_BASE "${FILE_BASE_PATH}.iconset/icon${SIZE_SUFFIX}") + copy_during_build("${PNG_BASE_PATH}.png" "${ICONSET_PNG_BASE}.png") + set(PNG_BASE_PATH "${ICONSET_PNG_BASE}") # returned list will be iconset PNGs + elseif(NOT (VERB STREQUAL "LIST")) + message(FATAL_ERROR "VERB has unrecognised value '${VERB}'") + endif(VERB STREQUAL "CREATE") + list(APPEND PNG_LIST "${PNG_BASE_PATH}.png") # do this regardless of VERB + endforeach(SIZE) + set("${PNG_PATHS_LISTV}" "${PNG_LIST}" PARENT_SCOPE) # return the list +endfunction(png_sizes) + +function(create_icon_ico # convert various sized PNGs into a single ICO icon + FILE_BASE_PATH # path to input PNGs minus size suffix and extension + ICO_FILE_OUTV # variable to store path to output ICO file if it is created + # ARGN remaining arguments are integer sizes of input PNGs + ) + if(BUILD_WINDOWS_ICONS) + set(ICO_FILE_OUT "${FILE_BASE_PATH}.ico") + png_sizes(LIST "${FILE_BASE_PATH}" 1 INPUT_PNGS ${ARGN}) + add_custom_command( + OUTPUT "${ICO_FILE_OUT}" + DEPENDS ${INPUT_PNGS} # paths can be relative since all PNGs are generated + COMMAND "${IMAGEMAGICK}" ${INPUT_PNGS} "${ICO_FILE_OUT}" + VERBATIM + ) + set("${ICO_FILE_OUTV}" "${ICO_FILE_OUT}" PARENT_SCOPE) # return ICO path + else(BUILD_WINDOWS_ICONS) + set("${ICO_FILE_OUTV}" "" PARENT_SCOPE) # return nothing + endif(BUILD_WINDOWS_ICONS) +endfunction(create_icon_ico) + +function(create_icon_icns # convert various sized PNGs into a single ICNS icon + FILE_BASE_PATH # path to input PNGs minus size suffix and extension + ICNS_FILE_OUTV # variable to store path to output ICNS file if it is created + # ARGN remaining arguments are integer sizes of input PNGs + ) + if(BUILD_MACOS_ICONS) + set(ICNS_FILE_OUT "${FILE_BASE_PATH}.icns") + if(APPLE) + # Apple's iconutil takes an "iconset" as input (directory of PNGs) + set(INPUT_PNGS "") # empty list + foreach(SCALE 1 2) + png_sizes(ICONSET "${FILE_BASE_PATH}" "${SCALE}" ICONSET_PNGS ${ARGN}) + list(APPEND INPUT_PNGS "${ICONSET_PNGS}") + endforeach(SCALE 1 2) + add_custom_command( + OUTPUT "${ICNS_FILE_OUT}" + DEPENDS ${INPUT_PNGS} + COMMAND "${ICONUTIL}" -c icns -o "${ICNS_FILE_OUT}" "${FILE_BASE_PATH}.iconset" + VERBATIM + ) + else(APPLE) + # no retina support in png2icns https://sourceforge.net/p/icns/bugs/12/ + png_sizes(ICONSET "${FILE_BASE_PATH}" 1 ICONSET_PNGS ${ARGN}) # SCALE = 1 only + add_custom_command( + OUTPUT "${ICNS_FILE_OUT}" + DEPENDS ${ICONSET_PNGS} + COMMAND "${PNG2ICNS}" "${ICNS_FILE_OUT}" ${ICONSET_PNGS} + VERBATIM + ) + endif(APPLE) + set("${ICNS_FILE_OUTV}" "${ICNS_FILE_OUT}" PARENT_SCOPE) # return path + else(BUILD_MACOS_ICONS) + set("${ICNS_FILE_OUTV}" "" PARENT_SCOPE) # return nothing + endif(BUILD_MACOS_ICONS) +endfunction(create_icon_icns) diff --git a/assets/resources/CMakeLists.txt b/assets/resources/CMakeLists.txt new file mode 100644 index 0000000000000..0e71c7a8fbe79 --- /dev/null +++ b/assets/resources/CMakeLists.txt @@ -0,0 +1,17 @@ +# list of resource files (in alphabetical order) +set(RESOURCES + cymbals.svg + folded-page.svg + mscore.svg + musicxml-logo-unofficial.svg + splash-background.jpg + ) + +assert_alphabetical(RESOURCES) # easier to maintain if we keep lists ordered + +# copy into build directory so that links can be resolved at build time +foreach(FILE ${RESOURCES}) + copy_during_build("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" "${FILE}") +endforeach(FILE) + +add_custom_target("assets_resources" ALL DEPENDS ${RESOURCES}) diff --git a/assets/resources/cymbals.svg b/assets/resources/cymbals.svg new file mode 100644 index 0000000000000..0fd75d96d6ec4 --- /dev/null +++ b/assets/resources/cymbals.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/resources/folded-page.svg b/assets/resources/folded-page.svg new file mode 100644 index 0000000000000..022941f4b1a20 --- /dev/null +++ b/assets/resources/folded-page.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/resources/mscore.svg b/assets/resources/mscore.svg new file mode 100644 index 0000000000000..7bd72ae724f40 --- /dev/null +++ b/assets/resources/mscore.svg @@ -0,0 +1,33 @@ + + + + diff --git a/assets/resources/musicxml-logo-unofficial.svg b/assets/resources/musicxml-logo-unofficial.svg new file mode 100644 index 0000000000000..630bac1bc558d --- /dev/null +++ b/assets/resources/musicxml-logo-unofficial.svg @@ -0,0 +1,14 @@ + + + + diff --git a/assets/resources/splash-background.jpg b/assets/resources/splash-background.jpg new file mode 100644 index 0000000000000..634fd9ada5557 Binary files /dev/null and b/assets/resources/splash-background.jpg differ diff --git a/assets/splash/CMakeLists.txt b/assets/splash/CMakeLists.txt new file mode 100644 index 0000000000000..352e2bcb852c9 --- /dev/null +++ b/assets/splash/CMakeLists.txt @@ -0,0 +1,34 @@ +set(GENERATED_FILES "") # empty list + +function(splash # create splash screen image from a source SVG + SVG_FILE_IN # source SVG that may contain @BUILD@ placeholder text + BUILD # build type (text to set in place of @BUILD@ in the SVG) + # ARGN remaining arguments are dependencies (resources or generated files) + ) + string(TOLOWER "${BUILD}" BUILD_LOWER) + set(FILE_OUT "splash-${BUILD_LOWER}") + configure_file("${SVG_FILE_IN}" "${FILE_OUT}-raw.svg") # substitute @BUILD@ + standalone_svg("${FILE_OUT}-raw.svg" "${FILE_OUT}-standalone.svg") + optimize_svg("${FILE_OUT}-standalone.svg" "${FILE_OUT}.svg") + list(APPEND GENERATED_FILES "${FILE_OUT}.svg") + set(GENERATED_FILES "${GENERATED_FILES}" PARENT_SCOPE) +endfunction(splash) + +# splash screen for stable releases +set(DEPENDENCIES + "../resources/splash-background.jpg" + "../platform/app-icons/musescore-icon-round.svg" + ) +splash(splash-stable.svg.xml.in "STABLE" ${DEPENDENCIES}) + +# splash screen for unstable builds +list(APPEND DEPENDENCIES "../resources/cymbals.svg") +foreach(BUILD "NIGHTLY" "DEVELOPMENT") + splash(splash-unstable.svg.xml.in "${BUILD}" ${DEPENDENCIES}) +endforeach(BUILD) + +add_custom_target("assets_splash" DEPENDS ${GENERATED_FILES}) +add_dependencies("assets_splash" "assets_resources") +add_dependencies("assets_splash" "assets_platform_appicons") +add_dependencies("assets" "assets_splash") +add_to_manifest(${GENERATED_FILES}) diff --git a/assets/splash/splash-stable.svg.xml.in b/assets/splash/splash-stable.svg.xml.in new file mode 100644 index 0000000000000..988d44849c77b --- /dev/null +++ b/assets/splash/splash-stable.svg.xml.in @@ -0,0 +1,25 @@ + + + @MUSESCORE_NAME@ + @MUSESCORE_VERSION_FULL@ + + + + + + + + + + + diff --git a/assets/splash/splash-unstable.svg.xml.in b/assets/splash/splash-unstable.svg.xml.in new file mode 100644 index 0000000000000..fc065efa485f6 --- /dev/null +++ b/assets/splash/splash-unstable.svg.xml.in @@ -0,0 +1,28 @@ + + + @MUSESCORE_NAME@ + + + + + + + + + + + + + @MUSESCORE_VERSION_FULL@ + @BUILD@ BUILD - FOR TESTING ONLY + diff --git a/assets/xml-icon-48.png b/assets/xml-icon-48.png deleted file mode 100644 index e56e957c2cf22..0000000000000 Binary files a/assets/xml-icon-48.png and /dev/null differ diff --git a/assets/xml-icon.svg b/assets/xml-icon.svg deleted file mode 100644 index 37906e60d443a..0000000000000 --- a/assets/xml-icon.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/Linux+BSD/musescore.xml.in b/build/Linux+BSD/musescore.xml.in index 9de194104fe19..d3920e5717891 100644 --- a/build/Linux+BSD/musescore.xml.in +++ b/build/Linux+BSD/musescore.xml.in @@ -6,25 +6,20 @@ - uncompressed MuseScore file + Uncompressed MuseScore file - <_comment>compressed MusicXML file + Compressed MusicXML file - - - - <_comment>uncompressed MusicXML file + Uncompressed MusicXML file - - @@ -35,24 +30,7 @@ - - - - - <_comment>uncompressed MusicXML file - - - - - - - - - - - - - - + + diff --git a/build/MacOSXBundleInfo.plist.in b/build/MacOSXBundleInfo.plist.in index 26ee6c5cbb55c..2afc6c2f0c540 100644 --- a/build/MacOSXBundleInfo.plist.in +++ b/build/MacOSXBundleInfo.plist.in @@ -65,7 +65,7 @@ mscx CFBundleTypeIconFile - musescoreDocument.icns + mscx.icns CFBundleTypeMIMETypes application/x-musescore+xml @@ -87,7 +87,7 @@ mscz CFBundleTypeIconFile - musescoreDocument.icns + mscz.icns CFBundleTypeMIMETypes application/x-musescore @@ -101,31 +101,16 @@ LSHandlerRank Owner - - CFBundleTypeName - Uncompressed MusicXML File - CFBundleTypeExtensions - - xml - - CFBundleTypeMIMETypes - - application/vnd.recordare.musicxml+xml - - CFBundleTypeRole - Editor - LSTypeIsPackage - - NSPersistentStoreTypeKey - XML - CFBundleTypeName Uncompressed MusicXML File CFBundleTypeExtensions musicxml + xml + CFBundleTypeIconFile + xml.icns CFBundleTypeMIMETypes application/vnd.recordare.musicxml+xml @@ -144,6 +129,8 @@ mxl + CFBundleTypeIconFile + mxl.icns CFBundleTypeMIMETypes application/vnd.recordare.musicxml diff --git a/build/packaging/WIX.template.in b/build/packaging/WIX.template.in index b7118acb5d014..5102ddf678826 100644 --- a/build/packaging/WIX.template.in +++ b/build/packaging/WIX.template.in @@ -44,7 +44,7 @@ - + http://musescore.org http://musescore.org http://musescore.org @@ -53,8 +53,8 @@ WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed @@ -71,14 +71,18 @@ - - + - + + + + - - + + + + @@ -87,10 +91,10 @@ - - + + @@ -109,25 +113,64 @@ - + + + + + + + + + - + - - - + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/build/travis/job1_Tests/environment.sh b/build/travis/job1_Tests/environment.sh index 53f52761618d3..970a8f351fa0a 100644 --- a/build/travis/job1_Tests/environment.sh +++ b/build/travis/job1_Tests/environment.sh @@ -41,6 +41,19 @@ export ARTIFACTS_KEY=$ARTIFACTS_AWS_ACCESS_KEY_ID export ARTIFACTS_SECRET=$ARTIFACTS_AWS_SECRET_ACCESS_KEY artifacts -v || curl -sL https://raw.githubusercontent.com/travis-ci/artifacts/master/install | bash +# Install dependencies for assets build +sudo add-apt-repository -y ppa:inkscape.dev/stable +curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - # node.js +sudo apt-get install -y inkscape nodejs +sudo npm install -g svgo eclint google-font-installer +for font in Raleway Roboto; do + sudo gfi install "${font}" # can't install more than one at a time +done + +export DISPLAY=:99.0 +sh -e /etc/init.d/xvfb start # fake display for GUI programs (inkscape) +sleep 3 # give xvfb some time to start + # IMPORTANT: Must now return shell to it's initial state: set +x set +e diff --git a/build/travis/job1_Tests/install.sh b/build/travis/job1_Tests/install.sh index b51801c5a934a..a467952f8d506 100755 --- a/build/travis/job1_Tests/install.sh +++ b/build/travis/job1_Tests/install.sh @@ -5,5 +5,17 @@ set -e # exit on error set -x # echo commands make revision -make debug CPUS=2 PREFIX="$HOME/software" COVERAGE=ON +make debug CPUS=2 PREFIX="$HOME/software" COVERAGE=ON DOWNLOAD_ASSETS=OFF make installdebug CPUS=2 PREFIX="$HOME/software" + +cd build.debug/assets +make assets_archive +file="$(ls MuseScore-assets-*.zip)" +ls "${file}" # make sure file exists +url="$(curl --upload-file "${file}" "https://transfer.sh/${file}")" # TODO: upload to MuseScore server +if [[ "${url}" ]]; then + echo "Assets uploaded to: ${url}" +else + echo "Assets upload failed!" + exit 1 +fi diff --git a/build/travis/job_macos_lupdate/build-assets.sh b/build/travis/job_macos_lupdate/build-assets.sh new file mode 100755 index 0000000000000..54e0f90de0ada --- /dev/null +++ b/build/travis/job_macos_lupdate/build-assets.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +set -e # exit on error +set -x # echo commands + +# DEPENDENCIES + +# upgrade older packages already installed on Travis CI +HOMEBREW_UPGRADES=( + # cmake # can't upgrade without updating homebrew itself + # node # npm - Travis version seems recent enough + ) + +# new packages not already installed on Travis CI +HOMEBREW_FORMULAE=( + imagemagick + pngcrush + ) + +# GUI applications +HOMEBREW_CASKS=( + inkscape + ) + +# Node.js +NPM_PACKAGES=( + eclint + google-font-installer + svgo + ) + +GOOGLE_FONTS=( + Raleway + Roboto + ) + +export HOMEBREW_NO_AUTO_UPDATE="1" # brew takes ages to update + +# brew upgrade "${HOMEBREW_UPGRADES[@]}" +brew install "${HOMEBREW_FORMULAE[@]}" +brew cask install "${HOMEBREW_CASKS[@]}" + +npm config set color false # npm's colors don't behave with Travis +npm install -g "${NPM_PACKAGES[@]}" + +for font in "${GOOGLE_FONTS[@]}"; do + gfi install "${font}" # can't install more than one at a time +done + +# TEST - code sanity check +if ! (cd assets && eclint check); then + echo "$0: Code doesn't match formatting rules in 'assets/.editorconfig'." + exit 1 +fi + +# CONFIGURE +# We only want to build the assets, but we still have to configure MuseScore +# so that we get access to the variables set in MuseScore's CMakeLists.txt. + +mkdir build.assets +cd build.assets +cmake .. -DDOWNLOAD_ASSETS=FALSE -DONLY_BUILD_ASSETS=TRUE + +# BUILD + +cpus="$(getconf _NPROCESSORS_ONLN)" # get number of logical CPU cores +make -j ${cpus} assets_archive # make is faster than Xcode for assets + +cd assets # because we configured MuseScore, not just the assets + +assets_archive="$(ls MuseScore-assets-*.zip)" + +if [[ ! -f "${assets_archive}" ]]; then + echo "$0: Assets archive not found where it was supposed to be." >&2 + pwd # where are we? + find . # what's here? + exit 1 +fi + +# UPLOAD + +if [[ "${UPLOAD_ASSETS}" ]]; then + if [[ "${TRAVIS_REPO_SLUG}" == "musescore/MuseScore" ]] && [[ "${TRAVIS_PULL_REQUEST}" == "false" ]]; then + # Upload assets to MuseScore server so everyone can download them + ( + # enter subshell to set shell options locally + set +x # protect secrets inside subshell + echo "TODO: write command to upload ${assets_archive} to MuseScore server" + exit 1 # remove when implemented + ) + else + # Upload assets to transfer.sh so developers can download and test them + url="$(curl --upload-file "${assets_archive}" "https://transfer.sh/${file}")" + if [[ "${url}" ]]; then + echo "Assets uploaded to: ${url}" + else + echo "Assets upload failed!" + exit 1 + fi + fi +fi diff --git a/manual/genManual.cpp b/manual/genManual.cpp index 35ec7ffd1012b..d27f1913fa9fd 100644 --- a/manual/genManual.cpp +++ b/manual/genManual.cpp @@ -367,7 +367,7 @@ static void copyAssets(QString& lSrcPath, QString& lDstPath) QString assetDstPath = lDstPath + "/plugins/"; QString assetSrcPath = lSrcPath + "/manual/"; // QStringList files = {"manual.css", "manual-dark.css", "mscore.png" }; - QStringList files = {"mscore.png" }; + QStringList files = {}; // copy files from source to destination path for (QString f : files) { diff --git a/manual/mscore.png b/manual/mscore.png deleted file mode 100644 index 2f10d209864ed..0000000000000 Binary files a/manual/mscore.png and /dev/null differ diff --git a/mscore/CMakeLists.txt b/mscore/CMakeLists.txt index fcf933289ade0..65fb0047053dd 100644 --- a/mscore/CMakeLists.txt +++ b/mscore/CMakeLists.txt @@ -178,28 +178,83 @@ QT5_WRAP_UI (ui_headers ${SCRIPT_UI} ) +# process files generated during the assets build (icons and images, etc) +# use an appropriate file for the app icon (file extension depends on platform) +if (MSCORE_UNSTABLE) + # square icon on development builds + set(MSCORE_ICON_BASE "${ASSETS_BINARY_DIR}/platform/app-icons/musescore-icon-square") +else (MSCORE_UNSTABLE) + # round icon on stable releases + set(MSCORE_ICON_BASE "${ASSETS_BINARY_DIR}/platform/app-icons/musescore-icon-round") +endif (MSCORE_UNSTABLE) + +# Add the appropriate splash screen for the build +if(MSCORE_UNSTABLE) + # use a special splash screen on unstable builds + if(ENV{MSCORE_UNSTABLE_BUILDS_USE_NIGHTLY_SPLASH} STREQUAL TRUE) + set(SPLASH_IMAGE "${ASSETS_BINARY_DIR}/splash/splash-nightly.svg") + else(ENV{MSCORE_UNSTABLE_BUILDS_USE_NIGHTLY_SPLASH} STREQUAL TRUE) + set(SPLASH_IMAGE "${ASSETS_BINARY_DIR}/splash/splash-development.svg") + endif(ENV{MSCORE_UNSTABLE_BUILDS_USE_NIGHTLY_SPLASH} STREQUAL TRUE) +else(MSCORE_UNSTABLE) + # use the normal splash image on stable releases + set(SPLASH_IMAGE "${ASSETS_BINARY_DIR}/splash/splash-stable.svg") +endif(MSCORE_UNSTABLE) + +# Use Qt's Resource System to embed files into the mscore executable at +# compile time so that they are guaranteed to be available at runtime. +# See https://doc.qt.io/qt-5/resources.html. +configure_file(musescoreassets.qrc.in musescoreassets.qrc) # substitute some variables +set(qt_resources_files + musescore.qrc + ${CMAKE_CURRENT_BINARY_DIR}/musescoreassets.qrc + ) if (APPLE) - QT5_ADD_RESOURCES (qrc_files musescore.qrc musescorefonts-Mac.qrc shortcut-Mac.qrc) + list(APPEND qt_resources_files + musescorefonts-Mac.qrc + shortcut-Mac.qrc + ) else (APPLE) - QT5_ADD_RESOURCES (qrc_files musescore.qrc - musescorefonts-MScore.qrc - musescorefonts-Gootville.qrc - musescorefonts-Bravura.qrc - musescorefonts-MuseJazz.qrc - musescorefonts-FreeSerif.qrc - musescorefonts-Free.qrc - shortcut.qrc) + list(APPEND qt_resources_files + musescorefonts-MScore.qrc + musescorefonts-Gootville.qrc + musescorefonts-Bravura.qrc + musescorefonts-MuseJazz.qrc + musescorefonts-FreeSerif.qrc + musescorefonts-Free.qrc + shortcut.qrc + ) endif (APPLE) - +QT5_ADD_RESOURCES (qrc_files ${qt_resources_files}) + +# Windows has its own resources system which is used to embed resources that +# need to be accessed by the operating system rather than by MuseScore or Qt. +set(windows_resource_file "") # empty unless on Windows +if (WIN32) + set(windows_resource_file "${CMAKE_CURRENT_BINARY_DIR}/musescoreassets-windows.rc") + configure_file(musescoreassets-windows.rc.in "${windows_resource_file}") # substitute some variables + # MSVC: job done! MSVC recognizes a *.rc file and will compile and link it automatically + if (MINGW) + # Must manually compile resource file into an object file in order to link it + set(intermediate_resource_file "${CMAKE_CURRENT_BINARY_DIR}/musescoreassets-windows.res") + set(compiled_resource_file "${CMAKE_CURRENT_BINARY_DIR}/musescoreassets-windows.o") + set(QT_WRC_EXECUTABLE "${PROJECT_SOURCE_DIR}/build/wrc.bat") + set(QT_WINE_EXECUTABLE "${PROJECT_SOURCE_DIR}/build/wine.bat") + add_custom_command( + OUTPUT "${compiled_resource_file}" + COMMAND "${QT_WRC_EXECUTABLE}" -i "${windows_resource_file}" -o "${intermediate_resource_file}" + COMMAND "${QT_WINE_EXECUTABLE}" "/home/ws/.wine/drive_c/MingW/bin/windres.exe" "${intermediate_resource_file}" -o "${compiled_resource_file}" + DEPENDS "${windows_resource_file}" + ) + set_source_files_properties( + "${compiled_resource_file}" + PROPERTIES generated true + ) + set (windows_resource_file "${compiled_resource_file}") + endif (MINGW) +endif (WIN32) set (AUDIO "") -if (MINGW) - set (resource_file ${PROJECT_BINARY_DIR}/resfile.o) -endif (MINGW) -if (MSVC) - # MSVC recognizes a *.rc file and will invoke the resource compiler to link it - set (resource_file ${PROJECT_SOURCE_DIR}/mscore/data/mscore.rc) -endif ( MSVC ) if ( NOT MINGW AND NOT MSVC ) if (USE_ALSA) set (AUDIO ${AUDIO} alsa.cpp) @@ -288,7 +343,7 @@ add_executable ( ${ExecutableName} ${ui_headers} ${_all_h_file} ${PCH} - ${resource_file} + ${windows_resource_file} ${INCS} abstractdialog.h accessibletoolbutton.h albummanager.h @@ -316,7 +371,7 @@ add_executable ( ${ExecutableName} scoreBrowser.h scoreInfo.h scorePreview.h scoretab.h scoreview.h searchComboBox.h sectionbreakprop.h selectdialog.h selectionwindow.h selectnotedialog.h selinstrument.h seq.h shortcut.h shortcutcapturedialog.h simplebutton.h splitstaff.h stafftextproperties.h - startcenter.h startupWizard.h stringutils.h svggenerator.h symboldialog.h synthcontrol.h + startcenter.h startupWizard.h stringutils.h svggenerator.h svgrenderer.h symboldialog.h synthcontrol.h templateBrowser.h textcursor.h textpalette.h texttools.h timedialog.h timeline.h timesigproperties.h toolbarEditor.h toolbuttonmenu.h transposedialog.h tremolobarcanvas.h tremolobarprop.h tupletdialog.h updatechecker.h uploadscoredialog.h waveview.h webpage.h workspace.h @@ -364,6 +419,7 @@ add_executable ( ${ExecutableName} layer.cpp selectdialog.cpp selectnotedialog.cpp propertymenu.cpp shortcut.cpp bb.cpp dragelement.cpp startupWizard.cpp svggenerator.cpp + svgrenderer.cpp masterpalette.cpp dragdrop.cpp waveview.cpp helpBrowser.cpp @@ -545,19 +601,6 @@ if (OSC) endif (OSC) if (MINGW) - set (QT_WRC_EXECUTABLE ${PROJECT_SOURCE_DIR}/build/wrc.bat) - set (QT_WINE_EXECUTABLE ${PROJECT_SOURCE_DIR}/build/wine.bat) - add_custom_command( - OUTPUT ${PROJECT_BINARY_DIR}/resfile.o - COMMAND ${QT_WRC_EXECUTABLE} -i mscore.rc -o ${PROJECT_BINARY_DIR}/mscore.res - COMMAND ${QT_WINE_EXECUTABLE} /home/ws/.wine/drive_c/MingW/bin/windres.exe ${PROJECT_BINARY_DIR}/mscore.res -o ${PROJECT_BINARY_DIR}/resfile.o - DEPENDS ${PROJECT_SOURCE_DIR}/mscore/data/mscore.rc - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/mscore/data - ) - set_source_files_properties( - ${PROJECT_BINARY_DIR}/resfile.o - PROPERTIES generated true - ) string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) # Windows: Add -mconsole to LINK_FLAGS to get a console window for debug output if(CMAKE_BUILD_TYPE MATCHES "DEBUG") @@ -758,8 +801,10 @@ else (MINGW) ) xcode_pch(mscore all) install (TARGETS mscore BUNDLE DESTINATION ${CMAKE_INSTALL_PREFIX}) - install (FILES data/mscore.icns DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}) - install (FILES data/musescoreDocument.icns DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}) + install (FILES "${MSCORE_ICON_BASE}.icns" RENAME mscore.icns DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}) + foreach(FILETYPE mscx mscz xml mxl) + install (FILES "${ASSETS_BINARY_DIR}/platform/file-icons/${FILETYPE}.icns" DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}) + endforeach(FILETYPE) else (APPLE) #### PACKAGING for Linux and BSD based systems (more in top-level CMakeLists.txt) #### # Install mscore executable (package maintainers may add "MuseScore" and/or "musescore" aliases that symlink to mscore) @@ -778,34 +823,18 @@ else (MINGW) ) endif (LN_EXECUTABLE) # Install MuseScore icons (use SVGs where possible, but install PNGs as backup for systems that don't support SVG) - set(MSCORE_ICON_BASE ../assets/musescore-icon-round) - install(FILES ${MSCORE_ICON_BASE}.svg RENAME mscore${MSCORE_INSTALL_SUFFIX}.svg DESTINATION share/icons/hicolor/scalable/apps) - install(FILES ${MSCORE_ICON_BASE}-16.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/16x16/apps) - install(FILES ${MSCORE_ICON_BASE}-24.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/24x24/apps) - install(FILES ${MSCORE_ICON_BASE}-32.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/32x32/apps) - install(FILES ${MSCORE_ICON_BASE}-48.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/48x48/apps) - install(FILES ${MSCORE_ICON_BASE}-64.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/64x64/apps) - install(FILES ${MSCORE_ICON_BASE}-96.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/96x96/apps) - install(FILES ${MSCORE_ICON_BASE}-128.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/128x128/apps) - install(FILES ${MSCORE_ICON_BASE}-512.png RENAME mscore${MSCORE_INSTALL_SUFFIX}.png DESTINATION share/icons/hicolor/512x512/apps) - # Install MIME (filetype) icons for each mimetype on Linux - install( FILES ../assets/mscz-icon.svg RENAME application-x-musescore${MSCORE_INSTALL_SUFFIX}.svg - DESTINATION share/icons/hicolor/scalable/mimetypes) # SVG icon for .MSCZ files - install( FILES ../assets/mscz-icon-48.png RENAME application-x-musescore${MSCORE_INSTALL_SUFFIX}.png - DESTINATION share/icons/hicolor/48x48/mimetypes) # PNG icon for .MSCZ files - install( FILES ../assets/mscx-icon.svg RENAME application-x-musescore${MSCORE_INSTALL_SUFFIX}+xml.svg - DESTINATION share/icons/hicolor/scalable/mimetypes) # SVG icon for .MSCX files - install( FILES ../assets/mscx-icon-48.png RENAME application-x-musescore${MSCORE_INSTALL_SUFFIX}+xml.png - DESTINATION share/icons/hicolor/48x48/mimetypes) # PNG icon for .MSCX files + function(install_icon_freedesktop BASEPATH_IN NAME_OUT DIR_OUT) + install(FILES "${BASEPATH_IN}.svg" RENAME "${NAME_OUT}.svg" DESTINATION "share/icons/hicolor/scalable/${DIR_OUT}") + foreach(SIZE 16 22 24 32 48 64 96 128 256 512) + install(FILES "${BASEPATH_IN}_${SIZE}x${SIZE}.png" RENAME "${NAME_OUT}.png" DESTINATION "share/icons/hicolor/${SIZE}x${SIZE}/${DIR_OUT}") + endforeach(SIZE) + endfunction(install_icon_freedesktop) + install_icon_freedesktop("${MSCORE_ICON_BASE}" "mscore${MSCORE_INSTALL_SUFFIX}" "apps") + install_icon_freedesktop("${ASSETS_BINARY_DIR}/platform/file-icons/mscx" "application-x-musescore${MSCORE_INSTALL_SUFFIX}+xml" "mimetypes") + install_icon_freedesktop("${ASSETS_BINARY_DIR}/platform/file-icons/mscz" "application-x-musescore${MSCORE_INSTALL_SUFFIX}" "mimetypes") # use a custom icon for MusicXML files (there isn't a standard icon for MusicXML files) - install( FILES ../assets/mxl-icon.svg RENAME application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}.svg - DESTINATION share/icons/hicolor/scalable/mimetypes) # SVG icon for .MXL (compressed MusicXML) files - install( FILES ../assets/mxl-icon-48.png RENAME application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}.png - DESTINATION share/icons/hicolor/48x48/mimetypes) # PNG icon for .MXL (compressed MusicXML) files - install( FILES ../assets/xml-icon.svg RENAME application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}+xml.svg - DESTINATION share/icons/hicolor/scalable/mimetypes) # SVG icon for .XML (MusicXML) files - install( FILES ../assets/xml-icon-48.png RENAME application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}+xml.png - DESTINATION share/icons/hicolor/48x48/mimetypes) # PNG icon for .XML (MusicXML) files + install_icon_freedesktop("${ASSETS_BINARY_DIR}/platform/file-icons/xml" "application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}+xml" "mimetypes") + install_icon_freedesktop("${ASSETS_BINARY_DIR}/platform/file-icons/mxl" "application-vnd.recordare.musicxml${MSCORE_INSTALL_SUFFIX}" "mimetypes") # Note: Must now run "gtk-update-icon-cache" to set the new icons. This is done in the Makefile. endif (APPLE) else ( NOT MSVC ) diff --git a/mscore/data/icons/mscore.png b/mscore/data/icons/mscore.png deleted file mode 100755 index d7797f69104c0..0000000000000 Binary files a/mscore/data/icons/mscore.png and /dev/null differ diff --git a/mscore/data/mscore.icns b/mscore/data/mscore.icns deleted file mode 100644 index ff2cf6a3e2c3c..0000000000000 Binary files a/mscore/data/mscore.icns and /dev/null differ diff --git a/mscore/data/mscore.ico b/mscore/data/mscore.ico deleted file mode 100644 index 338a68dfc27dc..0000000000000 Binary files a/mscore/data/mscore.ico and /dev/null differ diff --git a/mscore/data/mscore.png b/mscore/data/mscore.png deleted file mode 100644 index 856a052259bb5..0000000000000 Binary files a/mscore/data/mscore.png and /dev/null differ diff --git a/mscore/data/mscore.rc b/mscore/data/mscore.rc deleted file mode 100644 index 196d912512960..0000000000000 --- a/mscore/data/mscore.rc +++ /dev/null @@ -1,5 +0,0 @@ - -/* -*/ -IDI_ICON1 ICON DISCARDABLE "mscore.ico" -IDI_ICON2 ICON DISCARDABLE "mscorefile.ico" diff --git a/mscore/data/mscorefile.ico b/mscore/data/mscorefile.ico deleted file mode 100644 index 96ebaae7f4a29..0000000000000 Binary files a/mscore/data/mscorefile.ico and /dev/null differ diff --git a/mscore/data/musescoreDocument.icns b/mscore/data/musescoreDocument.icns deleted file mode 100644 index e80d63adc1d5a..0000000000000 Binary files a/mscore/data/musescoreDocument.icns and /dev/null differ diff --git a/mscore/data/splash.png b/mscore/data/splash.png deleted file mode 100644 index 580f3a1a03a93..0000000000000 Binary files a/mscore/data/splash.png and /dev/null differ diff --git a/mscore/icons.cpp b/mscore/icons.cpp index 4a048e2438462..38b900254530b 100644 --- a/mscore/icons.cpp +++ b/mscore/icons.cpp @@ -85,7 +85,6 @@ static const char* iconNames[] = { "document-new.svg", "document-save.svg", "document-save-as.svg", - "mscore.png", "acciaccatura.svg", "appoggiatura.svg", "grace4.svg", @@ -160,21 +159,31 @@ static const char* iconNames[] = { "note_timewise.svg" }; +//--------------------------------------------------------- +// iconFromFile +//--------------------------------------------------------- +QIcon* iconFromFile(QString iconFilePath) + { + QIcon* icon = new QIcon(new MIconEngine); + icon->addFile(iconFilePath); + if (icon->isNull() || icon->pixmap(12).isNull()) { + qDebug("cannot load Icon <%s>", qPrintable(iconFilePath)); + } + return icon; + } + //--------------------------------------------------------- // genIcons //--------------------------------------------------------- void genIcons() { - for (int i = 0; i < int(Icons::voice1_ICON); ++i) { - QIcon* icon = new QIcon(new MIconEngine); - icon->addFile(iconPath + iconNames[i]); - icons[i] = icon; - if (icon->isNull() || icon->pixmap(12).isNull()) { - qDebug("cannot load Icon <%s>", qPrintable(iconPath + iconNames[i])); - } + for (int i = 0; i < int(Icons::window_ICON); ++i) { + icons[i] = iconFromFile(iconPath + iconNames[i]); } + icons[int(Icons::window_ICON)] = iconFromFile(":/assets/mscore-icon.svg"); + static const char* vtext[VOICES] = { "1","2","3","4" }; int iw = preferences.getInt(PREF_UI_THEME_ICONHEIGHT) * 2 / 3; // 16; int ih = preferences.getInt(PREF_UI_THEME_ICONHEIGHT); // 24; diff --git a/mscore/icons.h b/mscore/icons.h index ea785559130fb..dc6b092871dcf 100644 --- a/mscore/icons.h +++ b/mscore/icons.h @@ -24,41 +24,133 @@ namespace Ms { extern void genIcons(); -enum class Icons : signed char { Invalid_ICON = -1, - longaUp_ICON, brevis_ICON, note_ICON, note2_ICON, note4_ICON, note8_ICON, note16_ICON, - note32_ICON, note64_ICON, note128_ICON, - natural_ICON, sharp_ICON, sharpsharp_ICON, flat_ICON, flatflat_ICON, - quartrest_ICON, dot_ICON, dotdot_ICON, dot3_ICON, dot4_ICON, +enum class Icons : signed char { + Invalid_ICON = -1, + longaUp_ICON, + brevis_ICON, + note_ICON, + note2_ICON, + note4_ICON, + note8_ICON, + note16_ICON, + note32_ICON, + note64_ICON, + note128_ICON, + natural_ICON, + sharp_ICON, + sharpsharp_ICON, + flat_ICON, + flatflat_ICON, + quartrest_ICON, + dot_ICON, + dotdot_ICON, + dot3_ICON, + dot4_ICON, flip_ICON, - undo_ICON, redo_ICON, cut_ICON, copy_ICON, paste_ICON, swap_ICON, print_ICON, clef_ICON, - midiin_ICON, speaker_ICON, start_ICON, play_ICON, repeat_ICON, pan_ICON, - sbeam_ICON, mbeam_ICON, nbeam_ICON, beam32_ICON, beam64_ICON, abeam_ICON, fbeam1_ICON, fbeam2_ICON, - file_ICON, fileOpen_ICON, fileNew_ICON, fileSave_ICON, fileSaveAs_ICON, - window_ICON, acciaccatura_ICON, appoggiatura_ICON, - grace4_ICON, grace16_ICON, grace32_ICON, - grace8after_ICON, grace16after_ICON, grace32after_ICON, - noteEntry_ICON, // noteEntrySteptime_ICON, (using normal icon for the time being.) - noteEntryRepitch_ICON, noteEntryRhythm_ICON, noteEntryRealtimeAuto_ICON, noteEntryRealtimeManual_ICON, - keys_ICON, tie_ICON, - textBold_ICON, textItalic_ICON, textUnderline_ICON, - textLeft_ICON, textCenter_ICON, textRight_ICON, textTop_ICON, textBottom_ICON, textVCenter_ICON, textBaseline_ICON, - textSuper_ICON, textSub_ICON, + undo_ICON, + redo_ICON, + cut_ICON, + copy_ICON, + paste_ICON, + swap_ICON, + print_ICON, + clef_ICON, + midiin_ICON, + speaker_ICON, + start_ICON, + play_ICON, + repeat_ICON, + pan_ICON, + sbeam_ICON, + mbeam_ICON, + nbeam_ICON, + beam32_ICON, + beam64_ICON, + abeam_ICON, + fbeam1_ICON, + fbeam2_ICON, + file_ICON, + fileOpen_ICON, + fileNew_ICON, + fileSave_ICON, + fileSaveAs_ICON, + acciaccatura_ICON, + appoggiatura_ICON, + grace4_ICON, + grace16_ICON, + grace32_ICON, + grace8after_ICON, + grace16after_ICON, + grace32after_ICON, + noteEntry_ICON, + // noteEntrySteptime_ICON, (using noteEntry_ICON for Steptime for the time being.) + noteEntryRepitch_ICON, + noteEntryRhythm_ICON, + noteEntryRealtimeAuto_ICON, + noteEntryRealtimeManual_ICON, + keys_ICON, + tie_ICON, + textBold_ICON, + textItalic_ICON, + textUnderline_ICON, + textLeft_ICON, + textCenter_ICON, + textRight_ICON, + textTop_ICON, + textBottom_ICON, + textVCenter_ICON, + textBaseline_ICON, + textSuper_ICON, + textSub_ICON, fotomode_ICON, - hraster_ICON, vraster_ICON, - formatListUnordered_ICON, formatListOrdered_ICON, - formatIndentMore_ICON, formatIndentLess_ICON, - loop_ICON, loopIn_ICON, loopOut_ICON, metronome_ICON, countin_ICON, - vframe_ICON, hframe_ICON, tframe_ICON, fframe_ICON, measure_ICON, checkmark_ICON, - helpContents_ICON, goHome_ICON, goPrevious_ICON, goNext_ICON, viewRefresh_ICON, + hraster_ICON, + vraster_ICON, + formatListUnordered_ICON, + formatListOrdered_ICON, + formatIndentMore_ICON, + formatIndentLess_ICON, + loop_ICON, + loopIn_ICON, + loopOut_ICON, + metronome_ICON, + countin_ICON, + vframe_ICON, + hframe_ICON, + tframe_ICON, + fframe_ICON, + measure_ICON, + checkmark_ICON, + helpContents_ICON, + goHome_ICON, + goPrevious_ICON, + goNext_ICON, + viewRefresh_ICON, parentheses_ICON, brackets_ICON, - timesig_allabreve_ICON, timesig_common_ICON, timesig_prolatio01_ICON, timesig_prolatio02_ICON, - timesig_prolatio03_ICON, timesig_prolatio04_ICON, timesig_prolatio05_ICON, timesig_prolatio07_ICON, - timesig_prolatio08_ICON, timesig_prolatio10_ICON, timesig_prolatio11_ICON, edit_ICON, reset_ICON, close_ICON, - arrowUp_ICON, arrowDown_ICON, - mail_ICON, bug_ICON, + timesig_allabreve_ICON, + timesig_common_ICON, + timesig_prolatio01_ICON, + timesig_prolatio02_ICON, + timesig_prolatio03_ICON, + timesig_prolatio04_ICON, + timesig_prolatio05_ICON, + timesig_prolatio07_ICON, + timesig_prolatio08_ICON, + timesig_prolatio10_ICON, + timesig_prolatio11_ICON, + edit_ICON, + reset_ICON, + close_ICON, + arrowUp_ICON, + arrowDown_ICON, + mail_ICON, + bug_ICON, noteTimewise_ICON, - voice1_ICON, voice2_ICON, voice3_ICON, voice4_ICON, + window_ICON, + voice1_ICON, + voice2_ICON, + voice3_ICON, + voice4_ICON, ICONS }; diff --git a/mscore/logindialog.ui b/mscore/logindialog.ui index 30dff51fe9210..7af5f8f26506e 100644 --- a/mscore/logindialog.ui +++ b/mscore/logindialog.ui @@ -37,7 +37,7 @@ - :/data/mscore.png + :/assets/mscore-logo.svg Qt::AlignCenter @@ -190,8 +190,6 @@ - - - + diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 64b9463f2d4d7..222cc8b74e010 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -116,6 +116,7 @@ #include "searchComboBox.h" #include "startcenter.h" #include "help.h" +#include "svgrenderer.h" #include "awl/aslider.h" #include "extension.h" #include "thirdparty/qzip/qzipreader_p.h" @@ -167,6 +168,7 @@ bool processJob = false; bool externalIcons = false; bool pluginMode = false; static bool startWithNewScore = false; +double _physicalDotsPerInch = 0.0; double guiScaling = 0.0; static double userDPI = 0.0; int trimMargin = -1; @@ -261,6 +263,12 @@ static constexpr double SCALE_MIN = 0.05; static constexpr double SCALE_STEP = 1.7; static const char* saveOnlineMenuItem = "file-save-online"; + +qreal MuseScore::physicalDotsPerInch() const + { + return _physicalDotsPerInch; + } + //--------------------------------------------------------- // cmdInsertMeasure //--------------------------------------------------------- @@ -978,31 +986,6 @@ MuseScore::MuseScore() qApp->installEventFilter(_tourHandler); _tourHandler->loadTours(); - QScreen* screen = QGuiApplication::primaryScreen(); - if (userDPI == 0.0) { -#if defined(Q_OS_WIN) - if (QSysInfo::WindowsVersion <= QSysInfo::WV_WINDOWS7) - _physicalDotsPerInch = screen->logicalDotsPerInch() * screen->devicePixelRatio(); - else - _physicalDotsPerInch = screen->physicalDotsPerInch(); // physical resolution -#else - _physicalDotsPerInch = screen->physicalDotsPerInch(); // physical resolution -#endif - } - else { - _physicalDotsPerInch = userDPI; - } - if (guiScaling == 0.0) { - // set scale for icons, palette elements, window sizes, etc - // the default values are hard coded in pixel sizes and assume ~96 DPI - if (qAbs(_physicalDotsPerInch - DPI_DISPLAY) > 6.0) - guiScaling = _physicalDotsPerInch / DPI_DISPLAY; - else - guiScaling = 1.0; - } - - MScore::pixelRatio = DPI / screen->logicalDotsPerInch(); - setObjectName("MuseScore"); _sstate = STATE_INIT; setWindowTitle(QString(MUSESCORE_NAME_VERSION)); @@ -1879,10 +1862,8 @@ MuseScore::MuseScore() #endif if (enableExperimental) { - cornerLabel = new QLabel(this); - cornerLabel->setScaledContents(true); - cornerLabel->setPixmap(QPixmap(":/data/mscore.png")); - cornerLabel->setGeometry(width() - 48, 0, 48, 48); + cornerGraphic = new QSvgWidget(":/assets/mscore-logo.svg", this); + cornerGraphic->setGeometry(width() - 48, 0, 48, 48); } #if defined(WIN_SPARKLE_ENABLED) autoUpdater.reset(new WinSparkleAutoUpdater); @@ -1985,7 +1966,7 @@ void MuseScore::retranslate() void MuseScore::resizeEvent(QResizeEvent*) { if (enableExperimental) { - cornerLabel->setGeometry(width() - 48, 0, 48, 48); + cornerGraphic->setGeometry(width() - 48, 0, 48, 48); } } @@ -7249,16 +7230,63 @@ int main(int argc, char* av[]) if (!MScore::testMode) MScore::readDefaultStyle(preferences.getString(PREF_SCORE_STYLE_DEFAULTSTYLEFILE)); - QSplashScreen* sc = 0; + if (!MScore::noGui) { + QScreen* screen = QGuiApplication::primaryScreen(); + if (userDPI == 0.0) { +#if defined(Q_OS_WIN) + if (QSysInfo::WindowsVersion <= QSysInfo::WV_WINDOWS7) + _physicalDotsPerInch = screen->logicalDotsPerInch() * screen->devicePixelRatio(); + else + _physicalDotsPerInch = screen->physicalDotsPerInch(); // physical resolution +#else + _physicalDotsPerInch = screen->physicalDotsPerInch(); // physical resolution +#endif + } + else { + _physicalDotsPerInch = userDPI; + } + if (guiScaling == 0.0) { + // set scale for icons, palette elements, window sizes, etc + // the default values are hard coded in pixel sizes and assume ~96 DPI + if (qAbs(_physicalDotsPerInch - DPI_DISPLAY) > 6.0) + guiScaling = _physicalDotsPerInch / DPI_DISPLAY; + else + guiScaling = 1.0; + } + + MScore::pixelRatio = DPI / screen->logicalDotsPerInch(); + } + + QSplashScreen* sc = nullptr; if (!MScore::noGui && preferences.getBool(PREF_UI_APP_STARTUP_SHOWSPLASHSCREEN)) { - QString pictureScaling; - if (QGuiApplication::primaryScreen()->devicePixelRatio() >= 2) - pictureScaling = "@2x"; - QPixmap pm(":/data/splash" + pictureScaling + ".png"); + QPixmap pm = SvgRenderer(":/assets/splash.svg").hdpiPixmap(QSize(), true); sc = new QSplashScreen(pm); sc->setWindowTitle(QString("MuseScore Startup")); #ifdef Q_OS_MAC // to have session dialog on top of splashscreen on mac - sc->setWindowFlags(Qt::FramelessWindowHint); + sc->setWindowFlag(Qt::FramelessWindowHint); +#endif +#ifdef QT_DEBUG + QString mscore_msg = QString( +"MuseScore: GUI Scaling: %1, devicePixelRatio: %2" + ) + .arg(guiScaling) + .arg(qApp->devicePixelRatio()); // reports largest from all monitors, not necessarily primary monitor; + const qreal MM_PER_INCH = 25.4; + auto wxh = [](QSizeF s) { return QString("%1x%2").arg(s.width()).arg(s.height()); }; + QScreen* screen = qApp->primaryScreen(); + QString screen_msg = QString( +"Primary Display:\n" +" size (mm): %1, size (inches): %2\n" +" size (pixels) %3, devicePixelRatio: %4\n" +" logical DPI: %5, phyical DPI: %6" + ) + .arg(wxh(screen->physicalSize())) + .arg(wxh(screen->physicalSize()/MM_PER_INCH)) + .arg(wxh(screen->size())) // multiply this by monitor's devicePixelRatio to get actual number of pixels + .arg(screen->devicePixelRatio()) // =1 for standard displays, >1 for HDPI / retina displays + .arg(screen->logicalDotsPerInch()) // many monitors pretend to be (a multiple of) 96 DPI for historical reasons + .arg(screen->physicalDotsPerInch()); // multiply this by devicePixelRatio to get the monitor's actual DPI + sc->showMessage(QString("%1\n\n%2").arg(mscore_msg, screen_msg), Qt::AlignLeft, Qt::white); #endif sc->show(); qApp->processEvents(); diff --git a/mscore/musescore.h b/mscore/musescore.h index 344690a2fb6cf..7572b49866bc7 100644 --- a/mscore/musescore.h +++ b/mscore/musescore.h @@ -415,12 +415,10 @@ class MuseScore : public QMainWindow, public MuseScoreCore { QAction* loopOutAction; QAction* panAction; - QLabel* cornerLabel; + QSvgWidget* cornerGraphic; QStringList _recentScores; QToolButton* _playButton; - qreal _physicalDotsPerInch; - QMessageBox* infoMsgBox; TourHandler* _tourHandler { 0 }; @@ -824,7 +822,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore { void showSynthControl(bool); void showMixer(bool); - qreal physicalDotsPerInch() const { return _physicalDotsPerInch; } + qreal physicalDotsPerInch() const; static const std::list& allNoteInputMenuEntries() { return _allNoteInputMenuEntries; } std::list* noteInputMenuEntries() { return &_noteInputMenuEntries; } void setNoteInputMenuEntries(std::list l) { _noteInputMenuEntries = l; } diff --git a/mscore/musescore.qrc b/mscore/musescore.qrc index 9c0184086636a..2d03ad99f4fdb 100644 --- a/mscore/musescore.qrc +++ b/mscore/musescore.qrc @@ -15,15 +15,12 @@ ../share/themes/style_dark_fusion.css ../share/themes/palette_light_fusion.json ../share/themes/palette_dark_fusion.json - data/splash.png - data/splash@2x.png ../share/templates/My_First_Score.mscz ../share/templates/Create_New_Score.mscz ../share/templates/01-General/00-Blank.mscx data/tab_sample.mscx data/std_sample.mscx data/style.qss - data/mscore.png data/icons/window-close.svg data/icons/png/window-close.png data/icons/png/window-close@2x.png @@ -56,7 +53,6 @@ data/icons/grace16after.svg data/icons/grace32after.svg data/icons/clef.svg - data/icons/mscore.png data/icons/raster-horizontal.svg data/icons/raster-vertical.svg data/icons/edit-reset.svg diff --git a/mscore/musescoreassets-windows.rc.in b/mscore/musescoreassets-windows.rc.in new file mode 100644 index 0000000000000..00f82406c9725 --- /dev/null +++ b/mscore/musescoreassets-windows.rc.in @@ -0,0 +1,34 @@ +/* Windows Resources File - embed files into the MuseScore.exe executable + +Use this file to embed resouces that must be accessed by the Windows operating +system, such as the application icon and filetype icons. + +Helpful links: +- https://en.wikipedia.org/wiki/Resource_(Windows) +- https://docs.microsoft.com/en-us/windows/desktop/menurc/about-resource-files +- https://doc.qt.io/qt-5/appicon.html#setting-the-application-icon-on-windows + +Do not use this file to embed resources that must be accessible within +MuseScore itself; use the Qt Resources System instead. +*/ + +//------------------------- +// ICON RESOURCES +// +// Tip: to see the icons embedded in an executable (.exe) file: +// 1. Right-click on the EXE and choose "Create Shortcut". +// 2. Right-click on the newly created shortcut and choose "Properties". +// 3. Click the button labelled "Change Icon". +// This will display the icons embedded inside the EXE ordered by icon index. +//------------------------- + +// The first icon mentioned in this file has index 0 and is used as the application icon +IDI_ICON1 ICON DISCARDABLE "@MSCORE_ICON_BASE@.ico" // icon index 0 + +// The index increases by 1 for each icon subsequently mentioned in this file. +// These can be used as filetype icons by setting the appropriate keys in the +// Windows Registry. This is usually done by the application's installer. +IDI_ICON2 ICON DISCARDABLE "@ASSETS_BINARY_DIR@/platform/file-icons/mscx.ico" // icon index 1 +IDI_ICON3 ICON DISCARDABLE "@ASSETS_BINARY_DIR@/platform/file-icons/mscz.ico" // icon index 2 +IDI_ICON4 ICON DISCARDABLE "@ASSETS_BINARY_DIR@/platform/file-icons/xml.ico" // etc. +IDI_ICON5 ICON DISCARDABLE "@ASSETS_BINARY_DIR@/platform/file-icons/mxl.ico" diff --git a/mscore/musescoreassets.qrc.in b/mscore/musescoreassets.qrc.in new file mode 100644 index 0000000000000..f1d26b96ff8b4 --- /dev/null +++ b/mscore/musescoreassets.qrc.in @@ -0,0 +1,7 @@ + + + @ASSETS_BINARY_DIR@/brand/mscore-logo.svg + @MSCORE_ICON_BASE@.svg + @SPLASH_IMAGE@ + + diff --git a/mscore/newwizard.cpp b/mscore/newwizard.cpp index 9ef2a18983d7f..8e29fbb1777be 100644 --- a/mscore/newwizard.cpp +++ b/mscore/newwizard.cpp @@ -24,6 +24,7 @@ #include "palette.h" #include "instrdialog.h" #include "templateBrowser.h" +#include "svgrenderer.h" #include "extension.h" #include "libmscore/instrtemplate.h" @@ -447,8 +448,9 @@ NewWizard::NewWizard(QWidget* parent) setOption(QWizard::CancelButtonOnLeft, true); #endif setWizardStyle(wizardStyleValue); - - setPixmap(QWizard::LogoPixmap, QPixmap(":/data/mscore.png")); + + QPixmap pm = SvgRenderer(":/assets/mscore-logo.svg").hdpiPixmap(QSize(64,64)); + setPixmap(QWizard::LogoPixmap, pm); setPixmap(QWizard::WatermarkPixmap, QPixmap()); setWindowTitle(tr("New Score Wizard")); @@ -545,4 +547,3 @@ void NewWizard::hideEvent(QHideEvent* event) } } - diff --git a/mscore/startcenter.cpp b/mscore/startcenter.cpp index df13c02f70032..07e38623cb6e2 100644 --- a/mscore/startcenter.cpp +++ b/mscore/startcenter.cpp @@ -61,7 +61,7 @@ Startcenter::Startcenter(QWidget* parent) #ifdef USE_WEBENGINE if (!noWebView) { _webView = new MyWebView(this); - _webView->setMaximumWidth(200); + _webView->setMaximumWidth(200); MyWebEnginePage* page = new MyWebEnginePage(this); MyWebUrlRequestInterceptor* wuri = new MyWebUrlRequestInterceptor(page); @@ -198,7 +198,7 @@ void Startcenter::keyReleaseEvent(QKeyEvent *event) } #ifdef USE_WEBENGINE - + //--------------------------------------------------------- // MyWebView //--------------------------------------------------------- @@ -255,4 +255,3 @@ bool MyWebEnginePage::acceptNavigationRequest(const QUrl & url, QWebEnginePage:: #endif //USE_WEBENGINE } - diff --git a/mscore/svgrenderer.cpp b/mscore/svgrenderer.cpp new file mode 100644 index 0000000000000..89a3f6dc78912 --- /dev/null +++ b/mscore/svgrenderer.cpp @@ -0,0 +1,40 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2002-2016 Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "svgrenderer.h" +#include "globals.h" + +namespace Ms { + +QPixmap SvgRenderer::hdpiPixmap(QSize size, bool scaleWithGui, const QColor &background) + { + if (!size.isValid()) + size = defaultSize(); + if (scaleWithGui) + size *= (guiScaling * qApp->devicePixelRatio()); + else + size *= qApp->devicePixelRatio(); + QPixmap pm(size); + pm.fill(background); + QPainter painter(&pm); + render(&painter); + pm.setDevicePixelRatio(qApp->devicePixelRatio()); + return pm; + } +} diff --git a/mscore/svgrenderer.h b/mscore/svgrenderer.h new file mode 100644 index 0000000000000..83d1cab65812c --- /dev/null +++ b/mscore/svgrenderer.h @@ -0,0 +1,47 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2002-2016 Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __SVGRENDERER_H__ +#define __SVGRENDERER_H__ + +namespace Ms { + +//--------------------------------------------------------------------------- +// SvgRenderer - Create QPixmaps from SVGs. +// +// Unlike simply calling QPixmap("/path/to/image.svg"), this class creates +// pixmaps that are appropriately scaled for HDPI/retina displays. +// +// Note: Do you really need a pixmap? Instead of adding a pixmap to a QLabel, +// consider replacing the QLabel with a QSvgWidget instead as this avoids +// rasterising the vector image unnecessarily. Pixmaps are only useful for +// legacy Qt classes that require pixmaps, such as QSplashScreen & QWizard. +//--------------------------------------------------------------------------- + +class SvgRenderer : public QSvgRenderer + { + Q_OBJECT + + public: + SvgRenderer(const QString &filename, QObject *parent = nullptr) : QSvgRenderer(filename, parent) {} + QPixmap hdpiPixmap(QSize size = QSize(), bool scaleWithGui = false, const QColor &background = Qt::transparent); + }; + +} +#endif // __SVGRENDERER_H__ diff --git a/mtest/mtest.qrc b/mtest/mtest.qrc index 9f26fc4b31856..db4cc9d4a150f 100644 --- a/mtest/mtest.qrc +++ b/mtest/mtest.qrc @@ -11,7 +11,7 @@ ../share/instruments/instruments.xml - ../mscore/data/mscore.png + ../mscore/data/mscore.svg ../mscore/revision.h ../mscore/data/musescore_logo_full.png