From 15ec1496c5afd0c34ef9b340cd5daaa51ad51ec1 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sun, 19 Sep 2021 14:09:20 +0200 Subject: [PATCH] Update and reorganise themes (#893) * Drop the subfolders for GUI themes * Remove bundled font support * Add safe file read function * Allow loading themes from multiple locations * Clean up unused variables * Clean up icons class * Merge icon theme icons * Update icon theme class * Remove guiDark config setting * Fix tests * Fix handling of default theme * Update icon readmes * Add test for getGuiItem common function --- CREDITS.md | 1 - novelWriter.pro | 1 - .../assets/fonts/Cantarell/Cantarell-Bold.ttf | Bin 46572 -> 0 bytes .../fonts/Cantarell/Cantarell-BoldItalic.ttf | Bin 49488 -> 0 bytes .../fonts/Cantarell/Cantarell-Italic.ttf | Bin 47368 -> 0 bytes .../fonts/Cantarell/Cantarell-Regular.ttf | Bin 44792 -> 0 bytes novelwriter/assets/fonts/Cantarell/OFL.txt | 93 ---- novelwriter/assets/icons/fallback/README.md | 6 - .../assets/icons/fallback/add-dark.svg | 31 -- novelwriter/assets/icons/fallback/add.svg | 31 -- .../assets/icons/fallback/backward-dark.svg | 31 -- .../assets/icons/fallback/backward.svg | 31 -- .../assets/icons/fallback/bullet-off-dark.svg | 31 -- .../assets/icons/fallback/bullet-off.svg | 31 -- .../assets/icons/fallback/bullet-on-dark.svg | 31 -- .../assets/icons/fallback/bullet-on.svg | 31 -- .../assets/icons/fallback/check-dark.svg | 31 -- novelwriter/assets/icons/fallback/check.svg | 31 -- .../assets/icons/fallback/cross-dark.svg | 31 -- novelwriter/assets/icons/fallback/cross.svg | 31 -- .../assets/icons/fallback/edit-dark.svg | 31 -- novelwriter/assets/icons/fallback/edit.svg | 31 -- .../assets/icons/fallback/forward-dark.svg | 31 -- novelwriter/assets/icons/fallback/forward.svg | 31 -- .../assets/icons/fallback/hash-dark.svg | 31 -- novelwriter/assets/icons/fallback/hash.svg | 31 -- .../assets/icons/fallback/maximise-dark.svg | 56 -- .../assets/icons/fallback/maximise.svg | 56 -- .../assets/icons/fallback/minimise-dark.svg | 55 -- .../assets/icons/fallback/minimise.svg | 55 -- .../assets/icons/fallback/proj_nwx.svg | 207 ------- .../assets/icons/fallback/reference-dark.svg | 31 -- .../assets/icons/fallback/reference.svg | 31 -- .../assets/icons/fallback/refresh-dark.svg | 56 -- novelwriter/assets/icons/fallback/refresh.svg | 56 -- .../assets/icons/fallback/remove-dark.svg | 31 -- novelwriter/assets/icons/fallback/remove.svg | 31 -- .../assets/icons/fallback/search-dark.svg | 31 -- .../assets/icons/fallback/search-replace.svg | 34 -- novelwriter/assets/icons/fallback/search.svg | 31 -- .../assets/icons/fallback/sticky-off-dark.svg | 31 -- .../assets/icons/fallback/sticky-off.svg | 31 -- .../assets/icons/fallback/sticky-on-dark.svg | 31 -- .../assets/icons/fallback/sticky-on.svg | 31 -- novelwriter/assets/icons/system/icons.conf | 8 - .../assets/icons/typicons_dark/README.md | 26 +- .../assets/icons/typicons_dark/icons.conf | 117 ++-- ...chapter.svg => mixed_document-chapter.svg} | 0 ...ument-note.svg => mixed_document-note.svg} | 0 ...ent-scene.svg => mixed_document-scene.svg} | 0 ...ent-title.svg => mixed_document-title.svg} | 0 .../{heading0.svg => mixed_heading0.svg} | 0 .../{heading1.svg => mixed_heading1.svg} | 0 .../{heading2.svg => mixed_heading2.svg} | 0 .../{heading3.svg => mixed_heading3.svg} | 0 .../{heading4.svg => mixed_heading4.svg} | 0 .../mixed_search-replace.svg} | 0 .../nw_search-case.svg} | 0 .../nw_search-preserve.svg} | 0 .../nw_search-regex.svg} | 0 .../nw_search-word.svg} | 0 .../typ_arrow-down-thick-grey.svg} | 0 ...ow-maximise.svg => typ_arrow-maximise.svg} | 0 ...ow-minimise.svg => typ_arrow-minimise.svg} | 0 .../typ_arrow-repeat-grey.svg} | 0 .../typicons_dark/{at.svg => typ_at.svg} | 0 .../{backspace.svg => typ_backspace.svg} | 0 .../typicons_dark/{book.svg => typ_book.svg} | 0 .../{bookmark.svg => typ_bookmark.svg} | 0 .../{calendar.svg => typ_calendar.svg} | 0 .../typ_cancel-grey.svg} | 0 .../{cancel.svg => typ_cancel.svg} | 0 .../typ_chart-bar-grey.svg} | 0 ...{chevron-left.svg => typ_chevron-left.svg} | 0 ...hevron-right.svg => typ_chevron-right.svg} | 0 .../typ_cog.svg} | 0 .../{delete.svg => typ_delete.svg} | 0 ...ocument-text.svg => typ_document-text.svg} | 0 .../{download.svg => typ_download.svg} | 0 .../typicons_dark/{flag.svg => typ_flag.svg} | 0 .../{folder.svg => typ_folder.svg} | 0 .../typ_globe-grey.svg} | 0 .../{globe.svg => typ_globe.svg} | 0 .../typicons_dark/{hash.svg => typ_hash.svg} | 0 ...nput-checked.svg => typ_input-checked.svg} | 0 .../typicons_dark/{key.svg => typ_key.svg} | 0 .../{location.svg => typ_location.svg} | 0 .../typ_media-pause-grey.svg} | 0 ...tline.svg => typ_media-record-outline.svg} | 0 ...{media-record.svg => typ_media-record.svg} | 0 .../{minus.svg => typ_minus.svg} | 0 ...replace.svg => typ_mod_search-replace.svg} | 0 .../{pencil.svg => typ_pencil.svg} | 0 .../{pin-outline.svg => typ_pin-outline.svg} | 0 .../typicons_dark/{pin.svg => typ_pin.svg} | 0 .../typicons_dark/{plus.svg => typ_plus.svg} | 0 .../{puzzle.svg => typ_puzzle.svg} | 0 .../{refresh.svg => typ_refresh.svg} | 0 .../{search.svg => typ_search.svg} | 0 .../typicons_dark/{star.svg => typ_star.svg} | 0 .../typ_stopwatch-grey.svg} | 0 .../{stopwatch.svg => typ_stopwatch.svg} | 0 .../typ_th-list-grey.svg} | 0 .../typicons_dark/{tick.svg => typ_tick.svg} | 0 .../{times.svg => typ_times.svg} | 0 .../{trash.svg => typ_trash.svg} | 0 .../typicons_dark/{user.svg => typ_user.svg} | 0 .../assets/icons/typicons_light/README.md | 26 +- .../assets/icons/typicons_light/icons.conf | 117 ++-- ...chapter.svg => mixed_document-chapter.svg} | 0 ...ument-note.svg => mixed_document-note.svg} | 0 ...ent-scene.svg => mixed_document-scene.svg} | 0 ...ent-title.svg => mixed_document-title.svg} | 0 .../{heading0.svg => mixed_heading0.svg} | 0 .../{heading1.svg => mixed_heading1.svg} | 0 .../{heading2.svg => mixed_heading2.svg} | 0 .../{heading3.svg => mixed_heading3.svg} | 0 .../{heading4.svg => mixed_heading4.svg} | 0 ...h-replace.svg => mixed_search-replace.svg} | 0 .../nw_search-case.svg} | 0 .../nw_search-preserve.svg} | 0 .../nw_search-regex.svg} | 0 .../nw_search-word.svg} | 0 .../typ_arrow-down-thick-grey.svg} | 0 ...ow-maximise.svg => typ_arrow-maximise.svg} | 0 ...ow-minimise.svg => typ_arrow-minimise.svg} | 0 .../typ_arrow-repeat-grey.svg} | 0 .../typicons_light/{at.svg => typ_at.svg} | 0 .../{backspace.svg => typ_backspace.svg} | 0 .../typicons_light/{book.svg => typ_book.svg} | 0 .../{bookmark.svg => typ_bookmark.svg} | 0 .../{calendar.svg => typ_calendar.svg} | 0 .../typ_cancel-grey.svg} | 0 .../{cancel.svg => typ_cancel.svg} | 0 .../typ_chart-bar-grey.svg} | 0 ...{chevron-left.svg => typ_chevron-left.svg} | 0 ...hevron-right.svg => typ_chevron-right.svg} | 0 .../typ_cog.svg} | 0 .../{delete.svg => typ_delete.svg} | 0 ...ocument-text.svg => typ_document-text.svg} | 0 .../{download.svg => typ_download.svg} | 0 .../typicons_light/{flag.svg => typ_flag.svg} | 0 .../{folder.svg => typ_folder.svg} | 0 .../typ_globe-grey.svg} | 0 .../{globe.svg => typ_globe.svg} | 0 .../typicons_light/{hash.svg => typ_hash.svg} | 0 ...nput-checked.svg => typ_input-checked.svg} | 0 .../typicons_light/{key.svg => typ_key.svg} | 0 .../{location.svg => typ_location.svg} | 0 .../typ_media-pause-grey.svg} | 0 ...tline.svg => typ_media-record-outline.svg} | 0 ...{media-record.svg => typ_media-record.svg} | 0 .../{minus.svg => typ_minus.svg} | 0 .../{pencil.svg => typ_pencil.svg} | 0 .../{pin-outline.svg => typ_pin-outline.svg} | 0 .../typicons_light/{pin.svg => typ_pin.svg} | 0 .../typicons_light/{plus.svg => typ_plus.svg} | 0 .../{puzzle.svg => typ_puzzle.svg} | 0 .../{refresh.svg => typ_refresh.svg} | 0 .../{search.svg => typ_search.svg} | 0 .../typicons_light/{star.svg => typ_star.svg} | 0 .../typ_stopwatch-grey.svg} | 0 .../{stopwatch.svg => typ_stopwatch.svg} | 0 .../typ_th-list-grey.svg} | 0 .../typicons_light/{tick.svg => typ_tick.svg} | 0 .../{times.svg => typ_times.svg} | 0 .../{trash.svg => typ_trash.svg} | 0 .../typicons_light/{user.svg => typ_user.svg} | 0 .../{themes => }/syntax/default_dark.conf | 0 .../{themes => }/syntax/default_light.conf | 0 .../assets/{themes => }/syntax/grey_dark.conf | 0 .../{themes => }/syntax/grey_light.conf | 0 .../assets/{themes => }/syntax/light_owl.conf | 0 .../assets/{themes => }/syntax/night_owl.conf | 0 .../{themes => }/syntax/solarized_dark.conf | 0 .../{themes => }/syntax/solarized_light.conf | 0 .../assets/{themes => }/syntax/tomorrow.conf | 0 .../{themes => }/syntax/tomorrow_night.conf | 0 .../syntax/tomorrow_night_blue.conf | 0 .../syntax/tomorrow_night_bright.conf | 0 .../syntax/tomorrow_night_eighties.conf | 0 .../{gui/default/theme.conf => default.conf} | 0 .../theme.conf => default_dark.conf} | 0 .../styles.qss => default_dark.qss} | 0 .../theme.conf => solarized_dark.conf} | 0 .../theme.conf => solarized_light.conf} | 0 novelwriter/common.py | 19 + novelwriter/config.py | 34 +- novelwriter/dialogs/about.py | 16 +- novelwriter/dialogs/preferences.py | 12 - novelwriter/gui/doceditor.py | 2 +- novelwriter/gui/theme.py | 505 +++++++----------- novelwriter/guimain.py | 2 +- setup/debian/copyright | 6 - tests/reference/baseConfig_novelwriter.conf | 3 +- .../reference/guiPreferences_novelwriter.conf | 3 +- tests/test_base/test_base_common.py | 33 +- tests/test_base/test_base_config.py | 6 +- tests/test_dialogs/test_dlg_preferences.py | 13 +- tests/test_gui/test_gui_theme.py | 26 +- tests/tools.py | 7 +- 201 files changed, 482 insertions(+), 2043 deletions(-) delete mode 100644 novelwriter/assets/fonts/Cantarell/Cantarell-Bold.ttf delete mode 100644 novelwriter/assets/fonts/Cantarell/Cantarell-BoldItalic.ttf delete mode 100644 novelwriter/assets/fonts/Cantarell/Cantarell-Italic.ttf delete mode 100644 novelwriter/assets/fonts/Cantarell/Cantarell-Regular.ttf delete mode 100644 novelwriter/assets/fonts/Cantarell/OFL.txt delete mode 100644 novelwriter/assets/icons/fallback/README.md delete mode 100644 novelwriter/assets/icons/fallback/add-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/add.svg delete mode 100644 novelwriter/assets/icons/fallback/backward-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/backward.svg delete mode 100644 novelwriter/assets/icons/fallback/bullet-off-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/bullet-off.svg delete mode 100644 novelwriter/assets/icons/fallback/bullet-on-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/bullet-on.svg delete mode 100644 novelwriter/assets/icons/fallback/check-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/check.svg delete mode 100644 novelwriter/assets/icons/fallback/cross-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/cross.svg delete mode 100644 novelwriter/assets/icons/fallback/edit-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/edit.svg delete mode 100644 novelwriter/assets/icons/fallback/forward-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/forward.svg delete mode 100644 novelwriter/assets/icons/fallback/hash-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/hash.svg delete mode 100644 novelwriter/assets/icons/fallback/maximise-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/maximise.svg delete mode 100644 novelwriter/assets/icons/fallback/minimise-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/minimise.svg delete mode 100644 novelwriter/assets/icons/fallback/proj_nwx.svg delete mode 100644 novelwriter/assets/icons/fallback/reference-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/reference.svg delete mode 100644 novelwriter/assets/icons/fallback/refresh-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/refresh.svg delete mode 100644 novelwriter/assets/icons/fallback/remove-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/remove.svg delete mode 100644 novelwriter/assets/icons/fallback/search-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/search-replace.svg delete mode 100644 novelwriter/assets/icons/fallback/search.svg delete mode 100644 novelwriter/assets/icons/fallback/sticky-off-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/sticky-off.svg delete mode 100644 novelwriter/assets/icons/fallback/sticky-on-dark.svg delete mode 100644 novelwriter/assets/icons/fallback/sticky-on.svg delete mode 100644 novelwriter/assets/icons/system/icons.conf rename novelwriter/assets/icons/typicons_dark/{document-chapter.svg => mixed_document-chapter.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{document-note.svg => mixed_document-note.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{document-scene.svg => mixed_document-scene.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{document-title.svg => mixed_document-title.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{heading0.svg => mixed_heading0.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{heading1.svg => mixed_heading1.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{heading2.svg => mixed_heading2.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{heading3.svg => mixed_heading3.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{heading4.svg => mixed_heading4.svg} (100%) rename novelwriter/assets/icons/{fallback/search-replace-dark.svg => typicons_dark/mixed_search-replace.svg} (100%) rename novelwriter/assets/icons/{fallback/search_case-dark.svg => typicons_dark/nw_search-case.svg} (100%) rename novelwriter/assets/icons/{fallback/search_preserve-dark.svg => typicons_dark/nw_search-preserve.svg} (100%) rename novelwriter/assets/icons/{fallback/search_regex-dark.svg => typicons_dark/nw_search-regex.svg} (100%) rename novelwriter/assets/icons/{fallback/search_word-dark.svg => typicons_dark/nw_search-word.svg} (100%) rename novelwriter/assets/icons/{fallback/search_project-dark.svg => typicons_dark/typ_arrow-down-thick-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{arrow-maximise.svg => typ_arrow-maximise.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{arrow-minimise.svg => typ_arrow-minimise.svg} (100%) rename novelwriter/assets/icons/{fallback/search_loop-dark.svg => typicons_dark/typ_arrow-repeat-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{at.svg => typ_at.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{backspace.svg => typ_backspace.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{book.svg => typ_book.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{bookmark.svg => typ_bookmark.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{calendar.svg => typ_calendar.svg} (100%) rename novelwriter/assets/icons/{fallback/search_cancel-dark.svg => typicons_dark/typ_cancel-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{cancel.svg => typ_cancel.svg} (100%) rename novelwriter/assets/icons/{fallback/status_stats-dark.svg => typicons_dark/typ_chart-bar-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{chevron-left.svg => typ_chevron-left.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{chevron-right.svg => typ_chevron-right.svg} (100%) rename novelwriter/assets/icons/{fallback/settings-dark.svg => typicons_dark/typ_cog.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{delete.svg => typ_delete.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{document-text.svg => typ_document-text.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{download.svg => typ_download.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{flag.svg => typ_flag.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{folder.svg => typ_folder.svg} (100%) rename novelwriter/assets/icons/{fallback/status_lang-dark.svg => typicons_dark/typ_globe-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{globe.svg => typ_globe.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{hash.svg => typ_hash.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{input-checked.svg => typ_input-checked.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{key.svg => typ_key.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{location.svg => typ_location.svg} (100%) rename novelwriter/assets/icons/{fallback/status_idle-dark.svg => typicons_dark/typ_media-pause-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{media-record-outline.svg => typ_media-record-outline.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{media-record.svg => typ_media-record.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{minus.svg => typ_minus.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{search-replace.svg => typ_mod_search-replace.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{pencil.svg => typ_pencil.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{pin-outline.svg => typ_pin-outline.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{pin.svg => typ_pin.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{plus.svg => typ_plus.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{puzzle.svg => typ_puzzle.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{refresh.svg => typ_refresh.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{search.svg => typ_search.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{star.svg => typ_star.svg} (100%) rename novelwriter/assets/icons/{fallback/status_time-dark.svg => typicons_dark/typ_stopwatch-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{stopwatch.svg => typ_stopwatch.svg} (100%) rename novelwriter/assets/icons/{fallback/status_lines-dark.svg => typicons_dark/typ_th-list-grey.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{tick.svg => typ_tick.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{times.svg => typ_times.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{trash.svg => typ_trash.svg} (100%) rename novelwriter/assets/icons/typicons_dark/{user.svg => typ_user.svg} (100%) rename novelwriter/assets/icons/typicons_light/{document-chapter.svg => mixed_document-chapter.svg} (100%) rename novelwriter/assets/icons/typicons_light/{document-note.svg => mixed_document-note.svg} (100%) rename novelwriter/assets/icons/typicons_light/{document-scene.svg => mixed_document-scene.svg} (100%) rename novelwriter/assets/icons/typicons_light/{document-title.svg => mixed_document-title.svg} (100%) rename novelwriter/assets/icons/typicons_light/{heading0.svg => mixed_heading0.svg} (100%) rename novelwriter/assets/icons/typicons_light/{heading1.svg => mixed_heading1.svg} (100%) rename novelwriter/assets/icons/typicons_light/{heading2.svg => mixed_heading2.svg} (100%) rename novelwriter/assets/icons/typicons_light/{heading3.svg => mixed_heading3.svg} (100%) rename novelwriter/assets/icons/typicons_light/{heading4.svg => mixed_heading4.svg} (100%) rename novelwriter/assets/icons/typicons_light/{search-replace.svg => mixed_search-replace.svg} (100%) rename novelwriter/assets/icons/{fallback/search_case.svg => typicons_light/nw_search-case.svg} (100%) rename novelwriter/assets/icons/{fallback/search_preserve.svg => typicons_light/nw_search-preserve.svg} (100%) rename novelwriter/assets/icons/{fallback/search_regex.svg => typicons_light/nw_search-regex.svg} (100%) rename novelwriter/assets/icons/{fallback/search_word.svg => typicons_light/nw_search-word.svg} (100%) rename novelwriter/assets/icons/{fallback/search_project.svg => typicons_light/typ_arrow-down-thick-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{arrow-maximise.svg => typ_arrow-maximise.svg} (100%) rename novelwriter/assets/icons/typicons_light/{arrow-minimise.svg => typ_arrow-minimise.svg} (100%) rename novelwriter/assets/icons/{fallback/search_loop.svg => typicons_light/typ_arrow-repeat-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{at.svg => typ_at.svg} (100%) rename novelwriter/assets/icons/typicons_light/{backspace.svg => typ_backspace.svg} (100%) rename novelwriter/assets/icons/typicons_light/{book.svg => typ_book.svg} (100%) rename novelwriter/assets/icons/typicons_light/{bookmark.svg => typ_bookmark.svg} (100%) rename novelwriter/assets/icons/typicons_light/{calendar.svg => typ_calendar.svg} (100%) rename novelwriter/assets/icons/{fallback/search_cancel.svg => typicons_light/typ_cancel-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{cancel.svg => typ_cancel.svg} (100%) rename novelwriter/assets/icons/{fallback/status_stats.svg => typicons_light/typ_chart-bar-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{chevron-left.svg => typ_chevron-left.svg} (100%) rename novelwriter/assets/icons/typicons_light/{chevron-right.svg => typ_chevron-right.svg} (100%) rename novelwriter/assets/icons/{fallback/settings.svg => typicons_light/typ_cog.svg} (100%) rename novelwriter/assets/icons/typicons_light/{delete.svg => typ_delete.svg} (100%) rename novelwriter/assets/icons/typicons_light/{document-text.svg => typ_document-text.svg} (100%) rename novelwriter/assets/icons/typicons_light/{download.svg => typ_download.svg} (100%) rename novelwriter/assets/icons/typicons_light/{flag.svg => typ_flag.svg} (100%) rename novelwriter/assets/icons/typicons_light/{folder.svg => typ_folder.svg} (100%) rename novelwriter/assets/icons/{fallback/status_lang.svg => typicons_light/typ_globe-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{globe.svg => typ_globe.svg} (100%) rename novelwriter/assets/icons/typicons_light/{hash.svg => typ_hash.svg} (100%) rename novelwriter/assets/icons/typicons_light/{input-checked.svg => typ_input-checked.svg} (100%) rename novelwriter/assets/icons/typicons_light/{key.svg => typ_key.svg} (100%) rename novelwriter/assets/icons/typicons_light/{location.svg => typ_location.svg} (100%) rename novelwriter/assets/icons/{fallback/status_idle.svg => typicons_light/typ_media-pause-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{media-record-outline.svg => typ_media-record-outline.svg} (100%) rename novelwriter/assets/icons/typicons_light/{media-record.svg => typ_media-record.svg} (100%) rename novelwriter/assets/icons/typicons_light/{minus.svg => typ_minus.svg} (100%) rename novelwriter/assets/icons/typicons_light/{pencil.svg => typ_pencil.svg} (100%) rename novelwriter/assets/icons/typicons_light/{pin-outline.svg => typ_pin-outline.svg} (100%) rename novelwriter/assets/icons/typicons_light/{pin.svg => typ_pin.svg} (100%) rename novelwriter/assets/icons/typicons_light/{plus.svg => typ_plus.svg} (100%) rename novelwriter/assets/icons/typicons_light/{puzzle.svg => typ_puzzle.svg} (100%) rename novelwriter/assets/icons/typicons_light/{refresh.svg => typ_refresh.svg} (100%) rename novelwriter/assets/icons/typicons_light/{search.svg => typ_search.svg} (100%) rename novelwriter/assets/icons/typicons_light/{star.svg => typ_star.svg} (100%) rename novelwriter/assets/icons/{fallback/status_time.svg => typicons_light/typ_stopwatch-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{stopwatch.svg => typ_stopwatch.svg} (100%) rename novelwriter/assets/icons/{fallback/status_lines.svg => typicons_light/typ_th-list-grey.svg} (100%) rename novelwriter/assets/icons/typicons_light/{tick.svg => typ_tick.svg} (100%) rename novelwriter/assets/icons/typicons_light/{times.svg => typ_times.svg} (100%) rename novelwriter/assets/icons/typicons_light/{trash.svg => typ_trash.svg} (100%) rename novelwriter/assets/icons/typicons_light/{user.svg => typ_user.svg} (100%) rename novelwriter/assets/{themes => }/syntax/default_dark.conf (100%) rename novelwriter/assets/{themes => }/syntax/default_light.conf (100%) rename novelwriter/assets/{themes => }/syntax/grey_dark.conf (100%) rename novelwriter/assets/{themes => }/syntax/grey_light.conf (100%) rename novelwriter/assets/{themes => }/syntax/light_owl.conf (100%) rename novelwriter/assets/{themes => }/syntax/night_owl.conf (100%) rename novelwriter/assets/{themes => }/syntax/solarized_dark.conf (100%) rename novelwriter/assets/{themes => }/syntax/solarized_light.conf (100%) rename novelwriter/assets/{themes => }/syntax/tomorrow.conf (100%) rename novelwriter/assets/{themes => }/syntax/tomorrow_night.conf (100%) rename novelwriter/assets/{themes => }/syntax/tomorrow_night_blue.conf (100%) rename novelwriter/assets/{themes => }/syntax/tomorrow_night_bright.conf (100%) rename novelwriter/assets/{themes => }/syntax/tomorrow_night_eighties.conf (100%) rename novelwriter/assets/themes/{gui/default/theme.conf => default.conf} (100%) rename novelwriter/assets/themes/{gui/default_dark/theme.conf => default_dark.conf} (100%) rename novelwriter/assets/themes/{gui/default_dark/styles.qss => default_dark.qss} (100%) rename novelwriter/assets/themes/{gui/solarized_dark/theme.conf => solarized_dark.conf} (100%) rename novelwriter/assets/themes/{gui/solarized_light/theme.conf => solarized_light.conf} (100%) diff --git a/CREDITS.md b/CREDITS.md index dc6b4c53..66d2f64b 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -31,7 +31,6 @@ The following libraries are dependencies of novelWriter: Some of the assets bundled with novelWriter were adapted from the following sources: * Typicons icons by Stephen Hutchings (CC BY-SA 4.0) -* Cantarell font by Dave Crossland (OPEN FONT LICENSE Version 1.1) * Tomorrow syntax themes by Chris Kempson (MIT License) * Owl syntax themes by Sarah Drasner (MIT License) * Solarized themes by Ethan Schoonover, added by @nullbasis (MIT License) diff --git a/novelWriter.pro b/novelWriter.pro index d1bc3e7b..2d948874 100644 --- a/novelWriter.pro +++ b/novelWriter.pro @@ -22,7 +22,6 @@ SOURCES += \ novelwriter/gui/projdetails.py \ novelwriter/gui/projtree.py \ novelwriter/gui/statusbar.py \ - novelwriter/gui/theme.py \ novelwriter/tools/build.py \ novelwriter/tools/projwizard.py \ novelwriter/tools/writingstats.py \ diff --git a/novelwriter/assets/fonts/Cantarell/Cantarell-Bold.ttf b/novelwriter/assets/fonts/Cantarell/Cantarell-Bold.ttf deleted file mode 100644 index ca364663a8cc2b37bd5e56cfa68bca1f223a35aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46572 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 z 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 diff --git a/novelwriter/assets/fonts/Cantarell/Cantarell-BoldItalic.ttf b/novelwriter/assets/fonts/Cantarell/Cantarell-BoldItalic.ttf deleted file mode 100644 index a54eab4c17a078a42413e212075423ae58a4b975..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49488 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 diff --git a/novelwriter/assets/fonts/Cantarell/Cantarell-Italic.ttf b/novelwriter/assets/fonts/Cantarell/Cantarell-Italic.ttf deleted file mode 100644 index 725b19863efe63b76cce9bb6254b93a031eb9b88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47368 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 X11k0bm6`yRdI0fI0ah2d18e*X^Z|wj diff --git a/novelwriter/assets/fonts/Cantarell/OFL.txt b/novelwriter/assets/fonts/Cantarell/OFL.txt deleted file mode 100644 index 4e495019..00000000 --- a/novelwriter/assets/fonts/Cantarell/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2009-2010, Understanding Limited (dave@understandinglimited.com) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/novelwriter/assets/icons/fallback/README.md b/novelwriter/assets/icons/fallback/README.md deleted file mode 100644 index 45a06454..00000000 --- a/novelwriter/assets/icons/fallback/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## License - -All icons in the fallback folder are modified from the Typicons theme by -Stephen Hutchings, released under CC BY-SA 4.0. - -See: https://github.com/stephenhutchings/typicons.font diff --git a/novelwriter/assets/icons/fallback/add-dark.svg b/novelwriter/assets/icons/fallback/add-dark.svg deleted file mode 100644 index 0846263d..00000000 --- a/novelwriter/assets/icons/fallback/add-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/add.svg b/novelwriter/assets/icons/fallback/add.svg deleted file mode 100644 index e7399157..00000000 --- a/novelwriter/assets/icons/fallback/add.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/backward-dark.svg b/novelwriter/assets/icons/fallback/backward-dark.svg deleted file mode 100644 index bc1c987f..00000000 --- a/novelwriter/assets/icons/fallback/backward-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/backward.svg b/novelwriter/assets/icons/fallback/backward.svg deleted file mode 100644 index 2e7af570..00000000 --- a/novelwriter/assets/icons/fallback/backward.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/bullet-off-dark.svg b/novelwriter/assets/icons/fallback/bullet-off-dark.svg deleted file mode 100644 index 46e56070..00000000 --- a/novelwriter/assets/icons/fallback/bullet-off-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/bullet-off.svg b/novelwriter/assets/icons/fallback/bullet-off.svg deleted file mode 100644 index 2e2712be..00000000 --- a/novelwriter/assets/icons/fallback/bullet-off.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/bullet-on-dark.svg b/novelwriter/assets/icons/fallback/bullet-on-dark.svg deleted file mode 100644 index ba3d9739..00000000 --- a/novelwriter/assets/icons/fallback/bullet-on-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/bullet-on.svg b/novelwriter/assets/icons/fallback/bullet-on.svg deleted file mode 100644 index 7a077ddd..00000000 --- a/novelwriter/assets/icons/fallback/bullet-on.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/check-dark.svg b/novelwriter/assets/icons/fallback/check-dark.svg deleted file mode 100644 index 0c1bea67..00000000 --- a/novelwriter/assets/icons/fallback/check-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/check.svg b/novelwriter/assets/icons/fallback/check.svg deleted file mode 100644 index 894c6186..00000000 --- a/novelwriter/assets/icons/fallback/check.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/cross-dark.svg b/novelwriter/assets/icons/fallback/cross-dark.svg deleted file mode 100644 index f863c42b..00000000 --- a/novelwriter/assets/icons/fallback/cross-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/cross.svg b/novelwriter/assets/icons/fallback/cross.svg deleted file mode 100644 index bc451278..00000000 --- a/novelwriter/assets/icons/fallback/cross.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/edit-dark.svg b/novelwriter/assets/icons/fallback/edit-dark.svg deleted file mode 100644 index f7665c6b..00000000 --- a/novelwriter/assets/icons/fallback/edit-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/edit.svg b/novelwriter/assets/icons/fallback/edit.svg deleted file mode 100644 index ddd96f64..00000000 --- a/novelwriter/assets/icons/fallback/edit.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/forward-dark.svg b/novelwriter/assets/icons/fallback/forward-dark.svg deleted file mode 100644 index 18eafe98..00000000 --- a/novelwriter/assets/icons/fallback/forward-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/forward.svg b/novelwriter/assets/icons/fallback/forward.svg deleted file mode 100644 index 8da983ca..00000000 --- a/novelwriter/assets/icons/fallback/forward.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/hash-dark.svg b/novelwriter/assets/icons/fallback/hash-dark.svg deleted file mode 100644 index 9f3db253..00000000 --- a/novelwriter/assets/icons/fallback/hash-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/hash.svg b/novelwriter/assets/icons/fallback/hash.svg deleted file mode 100644 index 99fddb80..00000000 --- a/novelwriter/assets/icons/fallback/hash.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/maximise-dark.svg b/novelwriter/assets/icons/fallback/maximise-dark.svg deleted file mode 100644 index 1ce767a3..00000000 --- a/novelwriter/assets/icons/fallback/maximise-dark.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/maximise.svg b/novelwriter/assets/icons/fallback/maximise.svg deleted file mode 100644 index 0e1d4a86..00000000 --- a/novelwriter/assets/icons/fallback/maximise.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/minimise-dark.svg b/novelwriter/assets/icons/fallback/minimise-dark.svg deleted file mode 100644 index 4bc48ce2..00000000 --- a/novelwriter/assets/icons/fallback/minimise-dark.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/minimise.svg b/novelwriter/assets/icons/fallback/minimise.svg deleted file mode 100644 index b0a1972f..00000000 --- a/novelwriter/assets/icons/fallback/minimise.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/proj_nwx.svg b/novelwriter/assets/icons/fallback/proj_nwx.svg deleted file mode 100644 index 08546d15..00000000 --- a/novelwriter/assets/icons/fallback/proj_nwx.svg +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/reference-dark.svg b/novelwriter/assets/icons/fallback/reference-dark.svg deleted file mode 100644 index 4d98eb91..00000000 --- a/novelwriter/assets/icons/fallback/reference-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/reference.svg b/novelwriter/assets/icons/fallback/reference.svg deleted file mode 100644 index b39357c9..00000000 --- a/novelwriter/assets/icons/fallback/reference.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/refresh-dark.svg b/novelwriter/assets/icons/fallback/refresh-dark.svg deleted file mode 100644 index 31367a18..00000000 --- a/novelwriter/assets/icons/fallback/refresh-dark.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/refresh.svg b/novelwriter/assets/icons/fallback/refresh.svg deleted file mode 100644 index c87d3257..00000000 --- a/novelwriter/assets/icons/fallback/refresh.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/remove-dark.svg b/novelwriter/assets/icons/fallback/remove-dark.svg deleted file mode 100644 index 799e4ff3..00000000 --- a/novelwriter/assets/icons/fallback/remove-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/remove.svg b/novelwriter/assets/icons/fallback/remove.svg deleted file mode 100644 index eb40a0e2..00000000 --- a/novelwriter/assets/icons/fallback/remove.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/search-dark.svg b/novelwriter/assets/icons/fallback/search-dark.svg deleted file mode 100644 index ecf47350..00000000 --- a/novelwriter/assets/icons/fallback/search-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/search-replace.svg b/novelwriter/assets/icons/fallback/search-replace.svg deleted file mode 100644 index cbf10912..00000000 --- a/novelwriter/assets/icons/fallback/search-replace.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/search.svg b/novelwriter/assets/icons/fallback/search.svg deleted file mode 100644 index d541d53b..00000000 --- a/novelwriter/assets/icons/fallback/search.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/sticky-off-dark.svg b/novelwriter/assets/icons/fallback/sticky-off-dark.svg deleted file mode 100644 index f571d5c9..00000000 --- a/novelwriter/assets/icons/fallback/sticky-off-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/sticky-off.svg b/novelwriter/assets/icons/fallback/sticky-off.svg deleted file mode 100644 index 57b2b498..00000000 --- a/novelwriter/assets/icons/fallback/sticky-off.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/sticky-on-dark.svg b/novelwriter/assets/icons/fallback/sticky-on-dark.svg deleted file mode 100644 index 62c6a66b..00000000 --- a/novelwriter/assets/icons/fallback/sticky-on-dark.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/fallback/sticky-on.svg b/novelwriter/assets/icons/fallback/sticky-on.svg deleted file mode 100644 index 3473b82f..00000000 --- a/novelwriter/assets/icons/fallback/sticky-on.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/novelwriter/assets/icons/system/icons.conf b/novelwriter/assets/icons/system/icons.conf deleted file mode 100644 index 9f94d37b..00000000 --- a/novelwriter/assets/icons/system/icons.conf +++ /dev/null @@ -1,8 +0,0 @@ -## -# System Theme -# Dummy theme that relies on Qt and novelWriter fallback icons -## - -[Main] -name = System Theme -description = Dummy theme that relies on Qt and novelWriter fallback icons diff --git a/novelwriter/assets/icons/typicons_dark/README.md b/novelwriter/assets/icons/typicons_dark/README.md index cfa5ea08..48c3f4ef 100644 --- a/novelwriter/assets/icons/typicons_dark/README.md +++ b/novelwriter/assets/icons/typicons_dark/README.md @@ -1,5 +1,29 @@ -## Typicons +# Typicons for Dark Backgrounds + +This theme is based on Typicons. All files are prefixed, depending on whether they are based +directly on original Typicons, redesigned, or designed from scratch. + +## Typicons Icons + +The files have a `typ_` prefix. These are colourised and rescaled Typicons, but with no other +modifications. Copyright: Stephen Hutchings Source: https://github.com/stephenhutchings/typicons.font License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +## Original Icons + +The files have a `nw_` prefix. These are made completely from scratch for novelWriter and are not +using any design elements from Typicons. + +Copyright: Veronica Berglyd Olsen +License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +## Mixed Icons + +The files have a `mixed_` prefix. These are redesigned from Typicons components, modified from +Typicons, or consist of a mix of Typicons and new elements. + +Copyright: Stephen Hutchings, Veronica Berglyd Olsen +License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf index 99bee3fe..e06aba68 100644 --- a/novelwriter/assets/icons/typicons_dark/icons.conf +++ b/novelwriter/assets/icons/typicons_dark/icons.conf @@ -7,57 +7,70 @@ ## [Main] -name = Typicons Dark -description = Colourised icons for dark GUI theme based on Typicons. -author = Veronica Berglyd Olsen (adaptation) -credit = Stephen Hutchings (icon design) -url = https://github.com/stephenhutchings/typicons.font -license = CC BY-SA 4.0 -licenseurl = https://creativecommons.org/licenses/by-sa/4.0/ +name = Typicons Dark +description = Colourised icons for dark GUI theme based on Typicons. +author = Veronica Berglyd Olsen (adaptation) +credit = Stephen Hutchings (icon design) +url = https://github.com/stephenhutchings/typicons.font +license = CC BY-SA 4.0 +licenseurl = https://creativecommons.org/licenses/by-sa/4.0/ [Map] -cls_none = cancel.svg -cls_novel = book.svg -cls_plot = puzzle.svg -cls_character = user.svg -cls_world = location.svg -cls_timeline = calendar.svg -cls_object = key.svg -cls_entity = flag.svg -cls_custom = star.svg -cls_archive = delete.svg -cls_trash = trash.svg -proj_document = document-text.svg -proj_title = document-title.svg -proj_chapter = document-chapter.svg -proj_scene = document-scene.svg -proj_note = document-note.svg -proj_folder = folder.svg -doc_h0 = heading0.svg -doc_h1 = heading1.svg -doc_h2 = heading2.svg -doc_h3 = heading3.svg -doc_h4 = heading4.svg -delete = delete.svg -add = plus.svg -remove = minus.svg -close = times.svg -refresh = refresh.svg -maximise = arrow-maximise.svg -minimise = arrow-minimise.svg -done = input-checked.svg -search = search.svg -search-replace = search-replace.svg -clear = backspace.svg -save = download.svg -edit = pencil.svg -check = tick.svg -cross = times.svg -hash = hash.svg -reference = at.svg -backward = chevron-left.svg -forward = chevron-right.svg -sticky-on = pin.svg -sticky-off = pin-outline.svg -bullet-on = media-record.svg -bullet-off = media-record-outline.svg +add = typ_plus.svg +backward = typ_chevron-left.svg +bullet-off = typ_media-record-outline.svg +bullet-on = typ_media-record.svg +check = typ_tick.svg +clear = typ_backspace.svg +close = typ_times.svg +cls_archive = typ_delete.svg +cls_character = typ_user.svg +cls_custom = typ_star.svg +cls_entity = typ_flag.svg +cls_none = typ_cancel.svg +cls_novel = typ_book.svg +cls_object = typ_key.svg +cls_plot = typ_puzzle.svg +cls_timeline = typ_calendar.svg +cls_trash = typ_trash.svg +cls_world = typ_location.svg +cross = typ_times.svg +delete = typ_delete.svg +doc_h0 = mixed_heading0.svg +doc_h1 = mixed_heading1.svg +doc_h2 = mixed_heading2.svg +doc_h3 = mixed_heading3.svg +doc_h4 = mixed_heading4.svg +done = typ_input-checked.svg +edit = typ_pencil.svg +forward = typ_chevron-right.svg +hash = typ_hash.svg +maximise = typ_arrow-maximise.svg +minimise = typ_arrow-minimise.svg +proj_chapter = mixed_document-chapter.svg +proj_document = typ_document-text.svg +proj_folder = typ_folder.svg +proj_note = mixed_document-note.svg +proj_scene = mixed_document-scene.svg +proj_title = mixed_document-title.svg +reference = typ_at.svg +refresh = typ_refresh.svg +remove = typ_minus.svg +save = typ_download.svg +search = typ_search.svg +search_cancel = typ_cancel-grey.svg +search_case = nw_search-case.svg +search_loop = typ_arrow-repeat-grey.svg +search_preserve = nw_search-preserve.svg +search_project = typ_arrow-down-thick-grey.svg +search_regex = nw_search-regex.svg +search_replace = mixed_search-replace.svg +search_word = nw_search-word.svg +settings = typ_cog.svg +status_idle = typ_media-pause-grey.svg +status_lang = typ_globe-grey.svg +status_lines = typ_th-list-grey.svg +status_stats = typ_chart-bar-grey.svg +status_time = typ_stopwatch-grey.svg +sticky-off = typ_pin-outline.svg +sticky-on = typ_pin.svg diff --git a/novelwriter/assets/icons/typicons_dark/document-chapter.svg b/novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/document-chapter.svg rename to novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg diff --git a/novelwriter/assets/icons/typicons_dark/document-note.svg b/novelwriter/assets/icons/typicons_dark/mixed_document-note.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/document-note.svg rename to novelwriter/assets/icons/typicons_dark/mixed_document-note.svg diff --git a/novelwriter/assets/icons/typicons_dark/document-scene.svg b/novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/document-scene.svg rename to novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg diff --git a/novelwriter/assets/icons/typicons_dark/document-title.svg b/novelwriter/assets/icons/typicons_dark/mixed_document-title.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/document-title.svg rename to novelwriter/assets/icons/typicons_dark/mixed_document-title.svg diff --git a/novelwriter/assets/icons/typicons_dark/heading0.svg b/novelwriter/assets/icons/typicons_dark/mixed_heading0.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/heading0.svg rename to novelwriter/assets/icons/typicons_dark/mixed_heading0.svg diff --git a/novelwriter/assets/icons/typicons_dark/heading1.svg b/novelwriter/assets/icons/typicons_dark/mixed_heading1.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/heading1.svg rename to novelwriter/assets/icons/typicons_dark/mixed_heading1.svg diff --git a/novelwriter/assets/icons/typicons_dark/heading2.svg b/novelwriter/assets/icons/typicons_dark/mixed_heading2.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/heading2.svg rename to novelwriter/assets/icons/typicons_dark/mixed_heading2.svg diff --git a/novelwriter/assets/icons/typicons_dark/heading3.svg b/novelwriter/assets/icons/typicons_dark/mixed_heading3.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/heading3.svg rename to novelwriter/assets/icons/typicons_dark/mixed_heading3.svg diff --git a/novelwriter/assets/icons/typicons_dark/heading4.svg b/novelwriter/assets/icons/typicons_dark/mixed_heading4.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/heading4.svg rename to novelwriter/assets/icons/typicons_dark/mixed_heading4.svg diff --git a/novelwriter/assets/icons/fallback/search-replace-dark.svg b/novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search-replace-dark.svg rename to novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg diff --git a/novelwriter/assets/icons/fallback/search_case-dark.svg b/novelwriter/assets/icons/typicons_dark/nw_search-case.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_case-dark.svg rename to novelwriter/assets/icons/typicons_dark/nw_search-case.svg diff --git a/novelwriter/assets/icons/fallback/search_preserve-dark.svg b/novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_preserve-dark.svg rename to novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg diff --git a/novelwriter/assets/icons/fallback/search_regex-dark.svg b/novelwriter/assets/icons/typicons_dark/nw_search-regex.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_regex-dark.svg rename to novelwriter/assets/icons/typicons_dark/nw_search-regex.svg diff --git a/novelwriter/assets/icons/fallback/search_word-dark.svg b/novelwriter/assets/icons/typicons_dark/nw_search-word.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_word-dark.svg rename to novelwriter/assets/icons/typicons_dark/nw_search-word.svg diff --git a/novelwriter/assets/icons/fallback/search_project-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_project-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/arrow-maximise.svg b/novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/arrow-maximise.svg rename to novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg diff --git a/novelwriter/assets/icons/typicons_dark/arrow-minimise.svg b/novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/arrow-minimise.svg rename to novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg diff --git a/novelwriter/assets/icons/fallback/search_loop-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_loop-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/at.svg b/novelwriter/assets/icons/typicons_dark/typ_at.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/at.svg rename to novelwriter/assets/icons/typicons_dark/typ_at.svg diff --git a/novelwriter/assets/icons/typicons_dark/backspace.svg b/novelwriter/assets/icons/typicons_dark/typ_backspace.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/backspace.svg rename to novelwriter/assets/icons/typicons_dark/typ_backspace.svg diff --git a/novelwriter/assets/icons/typicons_dark/book.svg b/novelwriter/assets/icons/typicons_dark/typ_book.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/book.svg rename to novelwriter/assets/icons/typicons_dark/typ_book.svg diff --git a/novelwriter/assets/icons/typicons_dark/bookmark.svg b/novelwriter/assets/icons/typicons_dark/typ_bookmark.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/bookmark.svg rename to novelwriter/assets/icons/typicons_dark/typ_bookmark.svg diff --git a/novelwriter/assets/icons/typicons_dark/calendar.svg b/novelwriter/assets/icons/typicons_dark/typ_calendar.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/calendar.svg rename to novelwriter/assets/icons/typicons_dark/typ_calendar.svg diff --git a/novelwriter/assets/icons/fallback/search_cancel-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_cancel-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/cancel.svg b/novelwriter/assets/icons/typicons_dark/typ_cancel.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/cancel.svg rename to novelwriter/assets/icons/typicons_dark/typ_cancel.svg diff --git a/novelwriter/assets/icons/fallback/status_stats-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_stats-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/chevron-left.svg b/novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/chevron-left.svg rename to novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg diff --git a/novelwriter/assets/icons/typicons_dark/chevron-right.svg b/novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/chevron-right.svg rename to novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg diff --git a/novelwriter/assets/icons/fallback/settings-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_cog.svg similarity index 100% rename from novelwriter/assets/icons/fallback/settings-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_cog.svg diff --git a/novelwriter/assets/icons/typicons_dark/delete.svg b/novelwriter/assets/icons/typicons_dark/typ_delete.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/delete.svg rename to novelwriter/assets/icons/typicons_dark/typ_delete.svg diff --git a/novelwriter/assets/icons/typicons_dark/document-text.svg b/novelwriter/assets/icons/typicons_dark/typ_document-text.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/document-text.svg rename to novelwriter/assets/icons/typicons_dark/typ_document-text.svg diff --git a/novelwriter/assets/icons/typicons_dark/download.svg b/novelwriter/assets/icons/typicons_dark/typ_download.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/download.svg rename to novelwriter/assets/icons/typicons_dark/typ_download.svg diff --git a/novelwriter/assets/icons/typicons_dark/flag.svg b/novelwriter/assets/icons/typicons_dark/typ_flag.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/flag.svg rename to novelwriter/assets/icons/typicons_dark/typ_flag.svg diff --git a/novelwriter/assets/icons/typicons_dark/folder.svg b/novelwriter/assets/icons/typicons_dark/typ_folder.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/folder.svg rename to novelwriter/assets/icons/typicons_dark/typ_folder.svg diff --git a/novelwriter/assets/icons/fallback/status_lang-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_lang-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/globe.svg b/novelwriter/assets/icons/typicons_dark/typ_globe.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/globe.svg rename to novelwriter/assets/icons/typicons_dark/typ_globe.svg diff --git a/novelwriter/assets/icons/typicons_dark/hash.svg b/novelwriter/assets/icons/typicons_dark/typ_hash.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/hash.svg rename to novelwriter/assets/icons/typicons_dark/typ_hash.svg diff --git a/novelwriter/assets/icons/typicons_dark/input-checked.svg b/novelwriter/assets/icons/typicons_dark/typ_input-checked.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/input-checked.svg rename to novelwriter/assets/icons/typicons_dark/typ_input-checked.svg diff --git a/novelwriter/assets/icons/typicons_dark/key.svg b/novelwriter/assets/icons/typicons_dark/typ_key.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/key.svg rename to novelwriter/assets/icons/typicons_dark/typ_key.svg diff --git a/novelwriter/assets/icons/typicons_dark/location.svg b/novelwriter/assets/icons/typicons_dark/typ_location.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/location.svg rename to novelwriter/assets/icons/typicons_dark/typ_location.svg diff --git a/novelwriter/assets/icons/fallback/status_idle-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_idle-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/media-record-outline.svg b/novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/media-record-outline.svg rename to novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg diff --git a/novelwriter/assets/icons/typicons_dark/media-record.svg b/novelwriter/assets/icons/typicons_dark/typ_media-record.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/media-record.svg rename to novelwriter/assets/icons/typicons_dark/typ_media-record.svg diff --git a/novelwriter/assets/icons/typicons_dark/minus.svg b/novelwriter/assets/icons/typicons_dark/typ_minus.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/minus.svg rename to novelwriter/assets/icons/typicons_dark/typ_minus.svg diff --git a/novelwriter/assets/icons/typicons_dark/search-replace.svg b/novelwriter/assets/icons/typicons_dark/typ_mod_search-replace.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/search-replace.svg rename to novelwriter/assets/icons/typicons_dark/typ_mod_search-replace.svg diff --git a/novelwriter/assets/icons/typicons_dark/pencil.svg b/novelwriter/assets/icons/typicons_dark/typ_pencil.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/pencil.svg rename to novelwriter/assets/icons/typicons_dark/typ_pencil.svg diff --git a/novelwriter/assets/icons/typicons_dark/pin-outline.svg b/novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/pin-outline.svg rename to novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg diff --git a/novelwriter/assets/icons/typicons_dark/pin.svg b/novelwriter/assets/icons/typicons_dark/typ_pin.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/pin.svg rename to novelwriter/assets/icons/typicons_dark/typ_pin.svg diff --git a/novelwriter/assets/icons/typicons_dark/plus.svg b/novelwriter/assets/icons/typicons_dark/typ_plus.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/plus.svg rename to novelwriter/assets/icons/typicons_dark/typ_plus.svg diff --git a/novelwriter/assets/icons/typicons_dark/puzzle.svg b/novelwriter/assets/icons/typicons_dark/typ_puzzle.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/puzzle.svg rename to novelwriter/assets/icons/typicons_dark/typ_puzzle.svg diff --git a/novelwriter/assets/icons/typicons_dark/refresh.svg b/novelwriter/assets/icons/typicons_dark/typ_refresh.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/refresh.svg rename to novelwriter/assets/icons/typicons_dark/typ_refresh.svg diff --git a/novelwriter/assets/icons/typicons_dark/search.svg b/novelwriter/assets/icons/typicons_dark/typ_search.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/search.svg rename to novelwriter/assets/icons/typicons_dark/typ_search.svg diff --git a/novelwriter/assets/icons/typicons_dark/star.svg b/novelwriter/assets/icons/typicons_dark/typ_star.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/star.svg rename to novelwriter/assets/icons/typicons_dark/typ_star.svg diff --git a/novelwriter/assets/icons/fallback/status_time-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_time-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/stopwatch.svg b/novelwriter/assets/icons/typicons_dark/typ_stopwatch.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/stopwatch.svg rename to novelwriter/assets/icons/typicons_dark/typ_stopwatch.svg diff --git a/novelwriter/assets/icons/fallback/status_lines-dark.svg b/novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_lines-dark.svg rename to novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg diff --git a/novelwriter/assets/icons/typicons_dark/tick.svg b/novelwriter/assets/icons/typicons_dark/typ_tick.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/tick.svg rename to novelwriter/assets/icons/typicons_dark/typ_tick.svg diff --git a/novelwriter/assets/icons/typicons_dark/times.svg b/novelwriter/assets/icons/typicons_dark/typ_times.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/times.svg rename to novelwriter/assets/icons/typicons_dark/typ_times.svg diff --git a/novelwriter/assets/icons/typicons_dark/trash.svg b/novelwriter/assets/icons/typicons_dark/typ_trash.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/trash.svg rename to novelwriter/assets/icons/typicons_dark/typ_trash.svg diff --git a/novelwriter/assets/icons/typicons_dark/user.svg b/novelwriter/assets/icons/typicons_dark/typ_user.svg similarity index 100% rename from novelwriter/assets/icons/typicons_dark/user.svg rename to novelwriter/assets/icons/typicons_dark/typ_user.svg diff --git a/novelwriter/assets/icons/typicons_light/README.md b/novelwriter/assets/icons/typicons_light/README.md index cfa5ea08..eb6f78a5 100644 --- a/novelwriter/assets/icons/typicons_light/README.md +++ b/novelwriter/assets/icons/typicons_light/README.md @@ -1,5 +1,29 @@ -## Typicons +# Typicons for Light Backgrounds + +This theme is based on Typicons. All files are prefixed, depending on whether they are based +directly on original Typicons, redesigned, or designed from scratch. + +## Typicons Icons + +The files have a `typ_` prefix. These are colourised and rescaled Typicons, but with no other +modifications. Copyright: Stephen Hutchings Source: https://github.com/stephenhutchings/typicons.font License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +## Original Icons + +The files have a `nw_` prefix. These are made completely from scratch for novelWriter and are not +using any design elements from Typicons. + +Copyright: Veronica Berglyd Olsen +License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +## Mixed Icons + +The files have a `mixed_` prefix. These are redesigned from Typicons components, modified from +Typicons, or consist of a mix of Typicons and new elements. + +Copyright: Stephen Hutchings, Veronica Berglyd Olsen +License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf index 64d6ec29..56e18b2a 100644 --- a/novelwriter/assets/icons/typicons_light/icons.conf +++ b/novelwriter/assets/icons/typicons_light/icons.conf @@ -7,57 +7,70 @@ ## [Main] -name = Typicons Light -description = Colourised icons for light GUI theme based on Typicons. -author = Veronica Berglyd Olsen (adaptation) -credit = Stephen Hutchings (icon design) -url = https://github.com/stephenhutchings/typicons.font -license = CC BY-SA 4.0 -licenseurl = https://creativecommons.org/licenses/by-sa/4.0/ +name = Typicons Light +description = Colourised icons for light GUI theme based on Typicons. +author = Veronica Berglyd Olsen (adaptation) +credit = Stephen Hutchings (icon design) +url = https://github.com/stephenhutchings/typicons.font +license = CC BY-SA 4.0 +licenseurl = https://creativecommons.org/licenses/by-sa/4.0/ [Map] -cls_none = cancel.svg -cls_novel = book.svg -cls_plot = puzzle.svg -cls_character = user.svg -cls_world = location.svg -cls_timeline = calendar.svg -cls_object = key.svg -cls_entity = flag.svg -cls_custom = star.svg -cls_archive = delete.svg -cls_trash = trash.svg -proj_document = document-text.svg -proj_title = document-title.svg -proj_chapter = document-chapter.svg -proj_scene = document-scene.svg -proj_note = document-note.svg -proj_folder = folder.svg -doc_h0 = heading0.svg -doc_h1 = heading1.svg -doc_h2 = heading2.svg -doc_h3 = heading3.svg -doc_h4 = heading4.svg -delete = delete.svg -add = plus.svg -remove = minus.svg -close = times.svg -refresh = refresh.svg -maximise = arrow-maximise.svg -minimise = arrow-minimise.svg -done = input-checked.svg -search = search.svg -search-replace = search-replace.svg -clear = backspace.svg -save = download.svg -edit = pencil.svg -check = tick.svg -cross = times.svg -hash = hash.svg -reference = at.svg -backward = chevron-left.svg -forward = chevron-right.svg -sticky-on = pin.svg -sticky-off = pin-outline.svg -bullet-on = media-record.svg -bullet-off = media-record-outline.svg +add = typ_plus.svg +backward = typ_chevron-left.svg +bullet-off = typ_media-record-outline.svg +bullet-on = typ_media-record.svg +check = typ_tick.svg +clear = typ_backspace.svg +close = typ_times.svg +cls_archive = typ_delete.svg +cls_character = typ_user.svg +cls_custom = typ_star.svg +cls_entity = typ_flag.svg +cls_none = typ_cancel.svg +cls_novel = typ_book.svg +cls_object = typ_key.svg +cls_plot = typ_puzzle.svg +cls_timeline = typ_calendar.svg +cls_trash = typ_trash.svg +cls_world = typ_location.svg +cross = typ_times.svg +delete = typ_delete.svg +doc_h0 = mixed_heading0.svg +doc_h1 = mixed_heading1.svg +doc_h2 = mixed_heading2.svg +doc_h3 = mixed_heading3.svg +doc_h4 = mixed_heading4.svg +done = typ_input-checked.svg +edit = typ_pencil.svg +forward = typ_chevron-right.svg +hash = typ_hash.svg +maximise = typ_arrow-maximise.svg +minimise = typ_arrow-minimise.svg +proj_chapter = mixed_document-chapter.svg +proj_document = typ_document-text.svg +proj_folder = typ_folder.svg +proj_note = mixed_document-note.svg +proj_scene = mixed_document-scene.svg +proj_title = mixed_document-title.svg +reference = typ_at.svg +refresh = typ_refresh.svg +remove = typ_minus.svg +save = typ_download.svg +search = typ_search.svg +search_cancel = typ_cancel-grey.svg +search_case = nw_search-case.svg +search_loop = typ_arrow-repeat-grey.svg +search_preserve = nw_search-preserve.svg +search_project = typ_arrow-down-thick-grey.svg +search_regex = nw_search-regex.svg +search_replace = mixed_search-replace.svg +search_word = nw_search-word.svg +settings = typ_cog.svg +status_idle = typ_media-pause-grey.svg +status_lang = typ_globe-grey.svg +status_lines = typ_th-list-grey.svg +status_stats = typ_chart-bar-grey.svg +status_time = typ_stopwatch-grey.svg +sticky-off = typ_pin-outline.svg +sticky-on = typ_pin.svg diff --git a/novelwriter/assets/icons/typicons_light/document-chapter.svg b/novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/document-chapter.svg rename to novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg diff --git a/novelwriter/assets/icons/typicons_light/document-note.svg b/novelwriter/assets/icons/typicons_light/mixed_document-note.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/document-note.svg rename to novelwriter/assets/icons/typicons_light/mixed_document-note.svg diff --git a/novelwriter/assets/icons/typicons_light/document-scene.svg b/novelwriter/assets/icons/typicons_light/mixed_document-scene.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/document-scene.svg rename to novelwriter/assets/icons/typicons_light/mixed_document-scene.svg diff --git a/novelwriter/assets/icons/typicons_light/document-title.svg b/novelwriter/assets/icons/typicons_light/mixed_document-title.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/document-title.svg rename to novelwriter/assets/icons/typicons_light/mixed_document-title.svg diff --git a/novelwriter/assets/icons/typicons_light/heading0.svg b/novelwriter/assets/icons/typicons_light/mixed_heading0.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/heading0.svg rename to novelwriter/assets/icons/typicons_light/mixed_heading0.svg diff --git a/novelwriter/assets/icons/typicons_light/heading1.svg b/novelwriter/assets/icons/typicons_light/mixed_heading1.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/heading1.svg rename to novelwriter/assets/icons/typicons_light/mixed_heading1.svg diff --git a/novelwriter/assets/icons/typicons_light/heading2.svg b/novelwriter/assets/icons/typicons_light/mixed_heading2.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/heading2.svg rename to novelwriter/assets/icons/typicons_light/mixed_heading2.svg diff --git a/novelwriter/assets/icons/typicons_light/heading3.svg b/novelwriter/assets/icons/typicons_light/mixed_heading3.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/heading3.svg rename to novelwriter/assets/icons/typicons_light/mixed_heading3.svg diff --git a/novelwriter/assets/icons/typicons_light/heading4.svg b/novelwriter/assets/icons/typicons_light/mixed_heading4.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/heading4.svg rename to novelwriter/assets/icons/typicons_light/mixed_heading4.svg diff --git a/novelwriter/assets/icons/typicons_light/search-replace.svg b/novelwriter/assets/icons/typicons_light/mixed_search-replace.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/search-replace.svg rename to novelwriter/assets/icons/typicons_light/mixed_search-replace.svg diff --git a/novelwriter/assets/icons/fallback/search_case.svg b/novelwriter/assets/icons/typicons_light/nw_search-case.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_case.svg rename to novelwriter/assets/icons/typicons_light/nw_search-case.svg diff --git a/novelwriter/assets/icons/fallback/search_preserve.svg b/novelwriter/assets/icons/typicons_light/nw_search-preserve.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_preserve.svg rename to novelwriter/assets/icons/typicons_light/nw_search-preserve.svg diff --git a/novelwriter/assets/icons/fallback/search_regex.svg b/novelwriter/assets/icons/typicons_light/nw_search-regex.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_regex.svg rename to novelwriter/assets/icons/typicons_light/nw_search-regex.svg diff --git a/novelwriter/assets/icons/fallback/search_word.svg b/novelwriter/assets/icons/typicons_light/nw_search-word.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_word.svg rename to novelwriter/assets/icons/typicons_light/nw_search-word.svg diff --git a/novelwriter/assets/icons/fallback/search_project.svg b/novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_project.svg rename to novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/arrow-maximise.svg b/novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/arrow-maximise.svg rename to novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg diff --git a/novelwriter/assets/icons/typicons_light/arrow-minimise.svg b/novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/arrow-minimise.svg rename to novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg diff --git a/novelwriter/assets/icons/fallback/search_loop.svg b/novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_loop.svg rename to novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/at.svg b/novelwriter/assets/icons/typicons_light/typ_at.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/at.svg rename to novelwriter/assets/icons/typicons_light/typ_at.svg diff --git a/novelwriter/assets/icons/typicons_light/backspace.svg b/novelwriter/assets/icons/typicons_light/typ_backspace.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/backspace.svg rename to novelwriter/assets/icons/typicons_light/typ_backspace.svg diff --git a/novelwriter/assets/icons/typicons_light/book.svg b/novelwriter/assets/icons/typicons_light/typ_book.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/book.svg rename to novelwriter/assets/icons/typicons_light/typ_book.svg diff --git a/novelwriter/assets/icons/typicons_light/bookmark.svg b/novelwriter/assets/icons/typicons_light/typ_bookmark.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/bookmark.svg rename to novelwriter/assets/icons/typicons_light/typ_bookmark.svg diff --git a/novelwriter/assets/icons/typicons_light/calendar.svg b/novelwriter/assets/icons/typicons_light/typ_calendar.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/calendar.svg rename to novelwriter/assets/icons/typicons_light/typ_calendar.svg diff --git a/novelwriter/assets/icons/fallback/search_cancel.svg b/novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/search_cancel.svg rename to novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/cancel.svg b/novelwriter/assets/icons/typicons_light/typ_cancel.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/cancel.svg rename to novelwriter/assets/icons/typicons_light/typ_cancel.svg diff --git a/novelwriter/assets/icons/fallback/status_stats.svg b/novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_stats.svg rename to novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/chevron-left.svg b/novelwriter/assets/icons/typicons_light/typ_chevron-left.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/chevron-left.svg rename to novelwriter/assets/icons/typicons_light/typ_chevron-left.svg diff --git a/novelwriter/assets/icons/typicons_light/chevron-right.svg b/novelwriter/assets/icons/typicons_light/typ_chevron-right.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/chevron-right.svg rename to novelwriter/assets/icons/typicons_light/typ_chevron-right.svg diff --git a/novelwriter/assets/icons/fallback/settings.svg b/novelwriter/assets/icons/typicons_light/typ_cog.svg similarity index 100% rename from novelwriter/assets/icons/fallback/settings.svg rename to novelwriter/assets/icons/typicons_light/typ_cog.svg diff --git a/novelwriter/assets/icons/typicons_light/delete.svg b/novelwriter/assets/icons/typicons_light/typ_delete.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/delete.svg rename to novelwriter/assets/icons/typicons_light/typ_delete.svg diff --git a/novelwriter/assets/icons/typicons_light/document-text.svg b/novelwriter/assets/icons/typicons_light/typ_document-text.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/document-text.svg rename to novelwriter/assets/icons/typicons_light/typ_document-text.svg diff --git a/novelwriter/assets/icons/typicons_light/download.svg b/novelwriter/assets/icons/typicons_light/typ_download.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/download.svg rename to novelwriter/assets/icons/typicons_light/typ_download.svg diff --git a/novelwriter/assets/icons/typicons_light/flag.svg b/novelwriter/assets/icons/typicons_light/typ_flag.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/flag.svg rename to novelwriter/assets/icons/typicons_light/typ_flag.svg diff --git a/novelwriter/assets/icons/typicons_light/folder.svg b/novelwriter/assets/icons/typicons_light/typ_folder.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/folder.svg rename to novelwriter/assets/icons/typicons_light/typ_folder.svg diff --git a/novelwriter/assets/icons/fallback/status_lang.svg b/novelwriter/assets/icons/typicons_light/typ_globe-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_lang.svg rename to novelwriter/assets/icons/typicons_light/typ_globe-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/globe.svg b/novelwriter/assets/icons/typicons_light/typ_globe.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/globe.svg rename to novelwriter/assets/icons/typicons_light/typ_globe.svg diff --git a/novelwriter/assets/icons/typicons_light/hash.svg b/novelwriter/assets/icons/typicons_light/typ_hash.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/hash.svg rename to novelwriter/assets/icons/typicons_light/typ_hash.svg diff --git a/novelwriter/assets/icons/typicons_light/input-checked.svg b/novelwriter/assets/icons/typicons_light/typ_input-checked.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/input-checked.svg rename to novelwriter/assets/icons/typicons_light/typ_input-checked.svg diff --git a/novelwriter/assets/icons/typicons_light/key.svg b/novelwriter/assets/icons/typicons_light/typ_key.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/key.svg rename to novelwriter/assets/icons/typicons_light/typ_key.svg diff --git a/novelwriter/assets/icons/typicons_light/location.svg b/novelwriter/assets/icons/typicons_light/typ_location.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/location.svg rename to novelwriter/assets/icons/typicons_light/typ_location.svg diff --git a/novelwriter/assets/icons/fallback/status_idle.svg b/novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_idle.svg rename to novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/media-record-outline.svg b/novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/media-record-outline.svg rename to novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg diff --git a/novelwriter/assets/icons/typicons_light/media-record.svg b/novelwriter/assets/icons/typicons_light/typ_media-record.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/media-record.svg rename to novelwriter/assets/icons/typicons_light/typ_media-record.svg diff --git a/novelwriter/assets/icons/typicons_light/minus.svg b/novelwriter/assets/icons/typicons_light/typ_minus.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/minus.svg rename to novelwriter/assets/icons/typicons_light/typ_minus.svg diff --git a/novelwriter/assets/icons/typicons_light/pencil.svg b/novelwriter/assets/icons/typicons_light/typ_pencil.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/pencil.svg rename to novelwriter/assets/icons/typicons_light/typ_pencil.svg diff --git a/novelwriter/assets/icons/typicons_light/pin-outline.svg b/novelwriter/assets/icons/typicons_light/typ_pin-outline.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/pin-outline.svg rename to novelwriter/assets/icons/typicons_light/typ_pin-outline.svg diff --git a/novelwriter/assets/icons/typicons_light/pin.svg b/novelwriter/assets/icons/typicons_light/typ_pin.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/pin.svg rename to novelwriter/assets/icons/typicons_light/typ_pin.svg diff --git a/novelwriter/assets/icons/typicons_light/plus.svg b/novelwriter/assets/icons/typicons_light/typ_plus.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/plus.svg rename to novelwriter/assets/icons/typicons_light/typ_plus.svg diff --git a/novelwriter/assets/icons/typicons_light/puzzle.svg b/novelwriter/assets/icons/typicons_light/typ_puzzle.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/puzzle.svg rename to novelwriter/assets/icons/typicons_light/typ_puzzle.svg diff --git a/novelwriter/assets/icons/typicons_light/refresh.svg b/novelwriter/assets/icons/typicons_light/typ_refresh.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/refresh.svg rename to novelwriter/assets/icons/typicons_light/typ_refresh.svg diff --git a/novelwriter/assets/icons/typicons_light/search.svg b/novelwriter/assets/icons/typicons_light/typ_search.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/search.svg rename to novelwriter/assets/icons/typicons_light/typ_search.svg diff --git a/novelwriter/assets/icons/typicons_light/star.svg b/novelwriter/assets/icons/typicons_light/typ_star.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/star.svg rename to novelwriter/assets/icons/typicons_light/typ_star.svg diff --git a/novelwriter/assets/icons/fallback/status_time.svg b/novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_time.svg rename to novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/stopwatch.svg b/novelwriter/assets/icons/typicons_light/typ_stopwatch.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/stopwatch.svg rename to novelwriter/assets/icons/typicons_light/typ_stopwatch.svg diff --git a/novelwriter/assets/icons/fallback/status_lines.svg b/novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg similarity index 100% rename from novelwriter/assets/icons/fallback/status_lines.svg rename to novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg diff --git a/novelwriter/assets/icons/typicons_light/tick.svg b/novelwriter/assets/icons/typicons_light/typ_tick.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/tick.svg rename to novelwriter/assets/icons/typicons_light/typ_tick.svg diff --git a/novelwriter/assets/icons/typicons_light/times.svg b/novelwriter/assets/icons/typicons_light/typ_times.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/times.svg rename to novelwriter/assets/icons/typicons_light/typ_times.svg diff --git a/novelwriter/assets/icons/typicons_light/trash.svg b/novelwriter/assets/icons/typicons_light/typ_trash.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/trash.svg rename to novelwriter/assets/icons/typicons_light/typ_trash.svg diff --git a/novelwriter/assets/icons/typicons_light/user.svg b/novelwriter/assets/icons/typicons_light/typ_user.svg similarity index 100% rename from novelwriter/assets/icons/typicons_light/user.svg rename to novelwriter/assets/icons/typicons_light/typ_user.svg diff --git a/novelwriter/assets/themes/syntax/default_dark.conf b/novelwriter/assets/syntax/default_dark.conf similarity index 100% rename from novelwriter/assets/themes/syntax/default_dark.conf rename to novelwriter/assets/syntax/default_dark.conf diff --git a/novelwriter/assets/themes/syntax/default_light.conf b/novelwriter/assets/syntax/default_light.conf similarity index 100% rename from novelwriter/assets/themes/syntax/default_light.conf rename to novelwriter/assets/syntax/default_light.conf diff --git a/novelwriter/assets/themes/syntax/grey_dark.conf b/novelwriter/assets/syntax/grey_dark.conf similarity index 100% rename from novelwriter/assets/themes/syntax/grey_dark.conf rename to novelwriter/assets/syntax/grey_dark.conf diff --git a/novelwriter/assets/themes/syntax/grey_light.conf b/novelwriter/assets/syntax/grey_light.conf similarity index 100% rename from novelwriter/assets/themes/syntax/grey_light.conf rename to novelwriter/assets/syntax/grey_light.conf diff --git a/novelwriter/assets/themes/syntax/light_owl.conf b/novelwriter/assets/syntax/light_owl.conf similarity index 100% rename from novelwriter/assets/themes/syntax/light_owl.conf rename to novelwriter/assets/syntax/light_owl.conf diff --git a/novelwriter/assets/themes/syntax/night_owl.conf b/novelwriter/assets/syntax/night_owl.conf similarity index 100% rename from novelwriter/assets/themes/syntax/night_owl.conf rename to novelwriter/assets/syntax/night_owl.conf diff --git a/novelwriter/assets/themes/syntax/solarized_dark.conf b/novelwriter/assets/syntax/solarized_dark.conf similarity index 100% rename from novelwriter/assets/themes/syntax/solarized_dark.conf rename to novelwriter/assets/syntax/solarized_dark.conf diff --git a/novelwriter/assets/themes/syntax/solarized_light.conf b/novelwriter/assets/syntax/solarized_light.conf similarity index 100% rename from novelwriter/assets/themes/syntax/solarized_light.conf rename to novelwriter/assets/syntax/solarized_light.conf diff --git a/novelwriter/assets/themes/syntax/tomorrow.conf b/novelwriter/assets/syntax/tomorrow.conf similarity index 100% rename from novelwriter/assets/themes/syntax/tomorrow.conf rename to novelwriter/assets/syntax/tomorrow.conf diff --git a/novelwriter/assets/themes/syntax/tomorrow_night.conf b/novelwriter/assets/syntax/tomorrow_night.conf similarity index 100% rename from novelwriter/assets/themes/syntax/tomorrow_night.conf rename to novelwriter/assets/syntax/tomorrow_night.conf diff --git a/novelwriter/assets/themes/syntax/tomorrow_night_blue.conf b/novelwriter/assets/syntax/tomorrow_night_blue.conf similarity index 100% rename from novelwriter/assets/themes/syntax/tomorrow_night_blue.conf rename to novelwriter/assets/syntax/tomorrow_night_blue.conf diff --git a/novelwriter/assets/themes/syntax/tomorrow_night_bright.conf b/novelwriter/assets/syntax/tomorrow_night_bright.conf similarity index 100% rename from novelwriter/assets/themes/syntax/tomorrow_night_bright.conf rename to novelwriter/assets/syntax/tomorrow_night_bright.conf diff --git a/novelwriter/assets/themes/syntax/tomorrow_night_eighties.conf b/novelwriter/assets/syntax/tomorrow_night_eighties.conf similarity index 100% rename from novelwriter/assets/themes/syntax/tomorrow_night_eighties.conf rename to novelwriter/assets/syntax/tomorrow_night_eighties.conf diff --git a/novelwriter/assets/themes/gui/default/theme.conf b/novelwriter/assets/themes/default.conf similarity index 100% rename from novelwriter/assets/themes/gui/default/theme.conf rename to novelwriter/assets/themes/default.conf diff --git a/novelwriter/assets/themes/gui/default_dark/theme.conf b/novelwriter/assets/themes/default_dark.conf similarity index 100% rename from novelwriter/assets/themes/gui/default_dark/theme.conf rename to novelwriter/assets/themes/default_dark.conf diff --git a/novelwriter/assets/themes/gui/default_dark/styles.qss b/novelwriter/assets/themes/default_dark.qss similarity index 100% rename from novelwriter/assets/themes/gui/default_dark/styles.qss rename to novelwriter/assets/themes/default_dark.qss diff --git a/novelwriter/assets/themes/gui/solarized_dark/theme.conf b/novelwriter/assets/themes/solarized_dark.conf similarity index 100% rename from novelwriter/assets/themes/gui/solarized_dark/theme.conf rename to novelwriter/assets/themes/solarized_dark.conf diff --git a/novelwriter/assets/themes/gui/solarized_light/theme.conf b/novelwriter/assets/themes/solarized_light.conf similarity index 100% rename from novelwriter/assets/themes/gui/solarized_light/theme.conf rename to novelwriter/assets/themes/solarized_light.conf diff --git a/novelwriter/common.py b/novelwriter/common.py index d4eb5a83..7e699e97 100644 --- a/novelwriter/common.py +++ b/novelwriter/common.py @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +import os import json import hashlib import logging @@ -415,6 +416,24 @@ def jsonEncode(data, n=0, nmax=0): # File and File System Functions # =============================================================================================== # +def readTextFile(filePath): + """Read the content of a text file in a robust manner. + """ + if not os.path.isfile(filePath): + return "" + + fileText = "" + try: + with open(filePath, mode="r", encoding="utf-8") as inFile: + fileText = inFile.read() + except Exception: + logger.error("Could not read file: %s", filePath) + logException() + return "" + + return fileText + + def makeFileNameSafe(theText): """Returns a filename safe version of the text. """ diff --git a/novelwriter/config.py b/novelwriter/config.py index 16f8e27d..8a7231f8 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -68,24 +68,24 @@ class Config: self.appRoot = None # The full path to the novelwriter root folder self.appIcon = None # The full path to the novelwriter icon file self.assetPath = None # The full path to the novelwriter/assets folder - self.themeRoot = None # The full path to the novelwriter/assets/themes folder - self.dictPath = None # The full path to the novelwriter/assets/dict folder - self.iconPath = None # The full path to the novelwriter/assets/icons folder self.pdfDocs = None # The location of the PDF manual, if it exists # Runtime Settings and Variables self.confChanged = False # True whenever the config has chenged, false after save # General - self.guiTheme = "default" - self.guiSyntax = "default_light" - self.guiIcons = "typicons_light" - self.guiDark = False # Load icons for dark backgrounds, if available + self.guiTheme = "" # GUI theme + self.guiSyntax = "" # Syntax theme + self.guiIcons = "" # Icon theme self.guiFont = "" # Defaults to system default font self.guiFontSize = 11 # Is overridden if system default is loaded self.guiScale = 1.0 # Set automatically by Theme class self.lastNotes = "0x0" # The latest release notes that have been shown + self.setDefaultGuiTheme() + self.setDefaultSyntaxTheme() + self.setDefaultIconTheme() + # Localisation self.qLocal = QLocale.system() self.guiLang = self.qLocal.name() @@ -293,10 +293,7 @@ class Config: # Assets self.assetPath = os.path.join(self.appPath, "assets") - self.themeRoot = os.path.join(self.assetPath, "themes") - self.dictPath = os.path.join(self.assetPath, "dict") - self.iconPath = os.path.join(self.assetPath, "icons") - self.appIcon = os.path.join(self.iconPath, "novelwriter.svg") + self.appIcon = os.path.join(self.assetPath, "icons", "novelwriter.svg") # Internationalisation self.nwLangPath = os.path.join(self.assetPath, "i18n") @@ -441,7 +438,6 @@ class Config: self.guiTheme = theConf.rdStr(cnfSec, "theme", self.guiTheme) self.guiSyntax = theConf.rdStr(cnfSec, "syntax", self.guiSyntax) self.guiIcons = theConf.rdStr(cnfSec, "icons", self.guiIcons) - self.guiDark = theConf.rdBool(cnfSec, "guidark", self.guiDark) self.guiFont = theConf.rdStr(cnfSec, "guifont", self.guiFont) self.guiFontSize = theConf.rdInt(cnfSec, "guifontsize", self.guiFontSize) self.lastNotes = theConf.rdStr(cnfSec, "lastnotes", self.lastNotes) @@ -564,7 +560,6 @@ class Config: "theme": str(self.guiTheme), "syntax": str(self.guiSyntax), "icons": str(self.guiIcons), - "guidark": str(self.guiDark), "guifont": str(self.guiFont), "guifontsize": str(self.guiFontSize), "lastnotes": str(self.lastNotes), @@ -852,6 +847,19 @@ class Config: self.confChanged = True return self.viewSynopsis + ## + # Default Setters + ## + + def setDefaultGuiTheme(self): + self.guiTheme = "default" + + def setDefaultSyntaxTheme(self): + self.guiSyntax = "default_light" + + def setDefaultIconTheme(self): + self.guiIcons = "typicons_light" + ## # Getters ## diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py index 498a25df..2aefc3f6 100644 --- a/novelwriter/dialogs/about.py +++ b/novelwriter/dialogs/about.py @@ -36,6 +36,8 @@ from PyQt5.QtWidgets import ( QTextBrowser, QLabel ) +from novelwriter.common import readTextFile + logger = logging.getLogger(__name__) @@ -230,10 +232,9 @@ class GuiAbout(QDialog): """Load the content for the Release Notes page. """ docPath = os.path.join(self.mainConf.assetPath, "text", "release_notes.htm") - if os.path.isfile(docPath): - with open(docPath, mode="r", encoding="utf-8") as inFile: - helpText = inFile.read() - self.pageNotes.setHtml(helpText) + docText = readTextFile(docPath) + if docText: + self.pageNotes.setHtml(docText) else: self.pageNotes.setHtml("Error loading release notes text ...") return @@ -242,10 +243,9 @@ class GuiAbout(QDialog): """Load the content for the Licence page. """ docPath = os.path.join(self.mainConf.assetPath, "text", "gplv3_en.htm") - if os.path.isfile(docPath): - with open(docPath, mode="r", encoding="utf-8") as inFile: - helpText = inFile.read() - self.pageLicense.setHtml(helpText) + docText = readTextFile(docPath) + if docText: + self.pageLicense.setHtml(docText) else: self.pageLicense.setHtml("Error loading licence text ...") return diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index cd757f95..98f20993 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -203,15 +203,6 @@ class GuiPreferencesGeneral(QWidget): self.tr("Changing this requires restarting novelWriter.") ) - # Dark Icons - self.guiDark = QSwitch() - self.guiDark.setChecked(self.mainConf.guiDark) - self.mainForm.addRow( - self.tr("Prefer icons for dark backgrounds"), - self.guiDark, - self.tr("May improve the look of icons on dark themes.") - ) - # Font Family self.guiFont = QLineEdit() self.guiFont.setReadOnly(True) @@ -284,7 +275,6 @@ class GuiPreferencesGeneral(QWidget): guiLang = self.guiLang.currentData() guiTheme = self.guiTheme.currentData() guiIcons = self.guiIcons.currentData() - guiDark = self.guiDark.isChecked() guiFont = self.guiFont.text() guiFontSize = self.guiFontSize.value() emphLabels = self.emphLabels.isChecked() @@ -294,7 +284,6 @@ class GuiPreferencesGeneral(QWidget): needsRestart |= self.mainConf.guiLang != guiLang needsRestart |= self.mainConf.guiTheme != guiTheme needsRestart |= self.mainConf.guiIcons != guiIcons - needsRestart |= self.mainConf.guiDark != guiDark needsRestart |= self.mainConf.guiFont != guiFont needsRestart |= self.mainConf.guiFontSize != guiFontSize @@ -305,7 +294,6 @@ class GuiPreferencesGeneral(QWidget): self.mainConf.guiLang = guiLang self.mainConf.guiTheme = guiTheme self.mainConf.guiIcons = guiIcons - self.mainConf.guiDark = guiDark self.mainConf.guiFont = guiFont self.mainConf.guiFontSize = guiFontSize self.mainConf.emphLabels = emphLabels diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 941e83ee..b23a8aaf 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -2244,7 +2244,7 @@ class GuiDocEditSearch(QFrame): self.searchButton.setToolTip(self.tr("Find in current document")) self.searchButton.clicked.connect(self._doSearch) - self.replaceButton = QPushButton(self.theTheme.getIcon("search-replace"), "") + self.replaceButton = QPushButton(self.theTheme.getIcon("search_replace"), "") self.replaceButton.setFixedSize(QSize(bPx, bPx)) self.replaceButton.setToolTip(self.tr("Find and replace in current document")) self.replaceButton.clicked.connect(self._doReplace) diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index fa2237a5..be1f6754 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -29,16 +29,15 @@ import logging import novelwriter from math import ceil -from functools import partial -from PyQt5.QtCore import QCoreApplication, Qt -from PyQt5.QtWidgets import QStyle, qApp +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import qApp from PyQt5.QtGui import ( QPalette, QColor, QIcon, QFont, QFontMetrics, QFontDatabase, QPixmap ) -from novelwriter.enum import nwAlert, nwItemLayout, nwItemType -from novelwriter.common import NWConfigParser +from novelwriter.enum import nwItemLayout, nwItemType +from novelwriter.common import NWConfigParser, readTextFile from novelwriter.constants import nwLabels logger = logging.getLogger(__name__) @@ -51,19 +50,10 @@ logger = logging.getLogger(__name__) class GuiTheme: - def __init__(self, theParent): + def __init__(self): - self.mainConf = novelwriter.CONFIG - self.theParent = theParent - self.theIcons = GuiIcons(self.theParent) - self.guiPalette = QPalette() - self.guiPath = "gui" - self.fontPath = "fonts" - self.syntaxPath = "syntax" - self.cssName = "style.qss" - self.confName = "theme.conf" - self.themeList = [] - self.syntaxList = [] + self.mainConf = novelwriter.CONFIG + self.theIcons = GuiIcons(self) # Loaded Theme Settings # ===================== @@ -84,6 +74,7 @@ class GuiTheme: self.helpText = [0, 0, 0] # Loaded Syntax Settings + # ====================== # Main self.syntaxName = "" @@ -115,14 +106,24 @@ class GuiTheme: # Changeable Settings self.guiTheme = None self.guiSyntax = None - self.themeRoot = None - self.themePath = None self.syntaxFile = None - self.confFile = None self.cssFile = None self.guiFontDB = QFontDatabase() - self.loadFonts() + # Class Setup + # =========== + + self._guiPalette = QPalette() + self._themeList = [] + self._syntaxList = [] + self._availThemes = {} + self._availSyntax = {} + + self._listConf(self._availSyntax, os.path.join(self.mainConf.dataPath, "syntax")) + self._listConf(self._availSyntax, os.path.join(self.mainConf.assetPath, "syntax")) + self._listConf(self._availThemes, os.path.join(self.mainConf.dataPath, "themes")) + self._listConf(self._availThemes, os.path.join(self.mainConf.assetPath, "themes")) + self.updateFont() self.updateTheme() self.theIcons.updateTheme() @@ -162,9 +163,6 @@ class GuiTheme: logger.verbose("Text 'N' Height: %d", self.textNHeight) logger.verbose("Text 'N' Width: %d", self.textNWidth) - # Internal Mapping - self.tr = partial(QCoreApplication.translate, "GuiTheme") - return ## @@ -184,43 +182,14 @@ class GuiTheme: # Actions ## - def loadFonts(self): - """Add the fonts in the assets fonts folder to the app. - """ - logger.debug("Loading additional fonts") - - ttfList = [] - fontAssets = os.path.join(self.mainConf.assetPath, self.fontPath) - for fontFam in os.listdir(fontAssets): - fontDir = os.path.join(fontAssets, fontFam) - if os.path.isdir(fontDir): - logger.verbose("Found font: %s", fontFam) - if fontFam not in self.guiFontDB.families(): - for fontFile in os.listdir(fontDir): - ttfFile = os.path.join(fontDir, fontFile) - if os.path.isfile(ttfFile) and fontFile.endswith(".ttf"): - ttfList.append(ttfFile) - - for ttfFile in ttfList: - relPath = os.path.relpath(ttfFile, fontAssets) - logger.verbose("Adding font: %s", relPath) - fontID = self.guiFontDB.addApplicationFont(ttfFile) - if fontID < 0: - logger.error("Failed to add font: %s", relPath) - - return - def updateFont(self): """Update the GUI's font style from settings. """ theFont = QFont() if self.mainConf.guiFont not in self.guiFontDB.families(): - if self.mainConf.osWindows: - if "Arial" in self.guiFontDB.families(): - theFont.setFamily("Arial") - else: - # On Windows, fall back to Cantarell provided by novelWriter - theFont.setFamily("Cantarell") + if self.mainConf.osWindows and "Arial" in self.guiFontDB.families(): + # On Windows we default to Arial if possible + theFont.setFamily("Arial") theFont.setPointSize(10) else: theFont = self.guiFontDB.systemFont(QFontDatabase.GeneralFont) @@ -237,16 +206,21 @@ class GuiTheme: def updateTheme(self): """Update the GUI theme from theme files. """ - self.guiTheme = self.mainConf.guiTheme - self.guiSyntax = self.mainConf.guiSyntax - self.themeRoot = self.mainConf.themeRoot - self.themePath = os.path.join(self.mainConf.themeRoot, self.guiPath, self.guiTheme) - self.syntaxFile = os.path.join(self.themeRoot, self.syntaxPath, self.guiSyntax+".conf") - self.confFile = os.path.join(self.themePath, self.confName) - self.cssFile = os.path.join(self.themePath, self.cssName) + self.guiTheme = self.mainConf.guiTheme + self.guiSyntax = self.mainConf.guiSyntax - self.loadTheme() - self.loadSyntax() + self.themeFile = self._availThemes.get(self.guiTheme, None) + if self.themeFile is None: + logger.error("Could not find GUI theme '%s'", self.guiTheme) + else: + self.cssFile = self.themeFile[:-5]+".css" + self.loadTheme() + + self.syntaxFile = self._availSyntax.get(self.guiSyntax, None) + if self.syntaxFile is None: + logger.error("Could not find syntax theme '%s'", self.guiSyntax) + else: + self.loadSyntax() # Update dependant colours backCol = qApp.palette().window().color() @@ -267,27 +241,15 @@ class GuiTheme: def loadTheme(self): """Load the currently specified GUI theme. """ - logger.debug("Loading theme files") - logger.debug("System icon theme is '%s'", str(QIcon.themeName())) - - # CSS File - cssData = "" - try: - if os.path.isfile(self.cssFile): - with open(self.cssFile, mode="r", encoding="utf-8") as inFile: - cssData = inFile.read() - except Exception: - logger.error("Could not load theme css file") - novelwriter.logException() - return False + logger.info("Loading GUI theme '%s'", self.guiTheme) # Config File confParser = NWConfigParser() try: - with open(self.confFile, mode="r", encoding="utf-8") as inFile: + with open(self.themeFile, mode="r", encoding="utf-8") as inFile: confParser.read_file(inFile) except Exception: - logger.error("Could not load theme settings from: %s", self.confFile) + logger.error("Could not load theme settings from: %s", self.themeFile) novelwriter.logException() return False @@ -327,18 +289,20 @@ class GuiTheme: self.statUnsaved = self._loadColour(confParser, cnfSec, "statusunsaved") self.statSaved = self._loadColour(confParser, cnfSec, "statussaved") - # Apply Styles - qApp.setStyleSheet(cssData) - qApp.setPalette(self.guiPalette) + # CSS File + cssData = readTextFile(self.cssFile) + if cssData: + qApp.setStyleSheet(cssData) - logger.info("Loaded theme '%s'", self.guiTheme) + # Apply Styles + qApp.setPalette(self._guiPalette) return True def loadSyntax(self): """Load the currently specified syntax highlighter theme. """ - logger.debug("Loading syntax theme files") + logger.info("Loading syntax theme '%s'", self.guiSyntax) confParser = NWConfigParser() try: @@ -380,79 +344,59 @@ class GuiTheme: self.colRepTag = self._loadColour(confParser, cnfSec, "replacetag") self.colMod = self._loadColour(confParser, cnfSec, "modifier") - logger.info("Loaded syntax theme '%s'", self.guiSyntax) - return True def listThemes(self): """Scan the GUI themes folder and list all themes. """ - if self.themeList: - return self.themeList + if self._themeList: + return self._themeList confParser = NWConfigParser() - for themeDir in os.listdir(os.path.join(self.mainConf.themeRoot, self.guiPath)): - themeConf = os.path.join( - self.mainConf.themeRoot, self.guiPath, themeDir, self.confName - ) - logger.verbose("Checking theme config for '%s'", themeDir) - try: - with open(themeConf, mode="r", encoding="utf-8") as inFile: - confParser.read_file(inFile) - except Exception as e: - self.theParent.makeAlert([ - self.tr("Could not load theme config file."), str(e) - ], nwAlert.ERROR) - continue - themeName = "" - if confParser.has_section("Main"): - if confParser.has_option("Main", "name"): - themeName = confParser.get("Main", "name") - logger.verbose("Theme name is '%s'", themeName) - if themeName != "": - self.themeList.append((themeDir, themeName)) + for themeKey, themePath in self._availThemes.items(): + logger.verbose("Checking theme config for '%s'", themeKey) + themeName = _loadInternalName(confParser, themePath) + if themeName: + self._themeList.append((themeKey, themeName)) - self.themeList = sorted(self.themeList, key=lambda x: x[1]) + self._themeList = sorted(self._themeList, key=lambda x: x[1]) - return self.themeList + return self._themeList def listSyntax(self): """Scan the syntax themes folder and list all themes. """ - if self.syntaxList: - return self.syntaxList + if self._syntaxList: + return self._syntaxList confParser = NWConfigParser() - syntaxDir = os.path.join(self.mainConf.themeRoot, self.syntaxPath) - for syntaxFile in os.listdir(syntaxDir): - syntaxPath = os.path.join(syntaxDir, syntaxFile) - if not os.path.isfile(syntaxPath): - continue - logger.verbose("Checking theme syntax for '%s'", syntaxFile) - try: - with open(syntaxPath, mode="r", encoding="utf-8") as inFile: - confParser.read_file(inFile) - except Exception as e: - self.theParent.makeAlert([ - self.tr("Could not load syntax file."), str(e) - ], nwAlert.ERROR) - return [] - syntaxName = "" - if confParser.has_section("Main"): - if confParser.has_option("Main", "name"): - syntaxName = confParser.get("Main", "name") - if len(syntaxFile) > 5 and syntaxName != "": - self.syntaxList.append((syntaxFile[:-5], syntaxName)) - logger.verbose("Syntax name is '%s'", syntaxName) + for syntaxKey, syntaxPath in self._availSyntax.items(): + logger.verbose("Checking theme syntax for '%s'", syntaxKey) + syntaxName = _loadInternalName(confParser, syntaxPath) + if syntaxName: + self._syntaxList.append((syntaxKey, syntaxName)) - self.syntaxList = sorted(self.syntaxList, key=lambda x: x[1]) + self._syntaxList = sorted(self._syntaxList, key=lambda x: x[1]) - return self.syntaxList + return self._syntaxList ## # Internal Functions ## + def _listConf(self, targetDict, checkDir): + """Scan for syntax and gui themes and populate the dictionary. + """ + if not os.path.isdir(checkDir): + return + + for checkFile in os.listdir(checkDir): + confPath = os.path.join(checkDir, checkFile) + if os.path.isfile(confPath) and confPath.endswith(".conf"): + targetDict[checkFile[:-5]] = confPath + + return + def _loadColour(self, confParser, cnfSec, cnfName): """Load a colour value from a config string. """ @@ -485,7 +429,7 @@ class GuiTheme: logger.error("Could not load theme colours for '%s' from config file", cnfName) return if len(readCol) == 3: - self.guiPalette.setColor(paletteVal, QColor(*readCol)) + self._guiPalette.setColor(paletteVal, QColor(*readCol)) return # End Class GuiTheme @@ -498,116 +442,57 @@ class GuiTheme: class GuiIcons: """The icon class manages the content of the assets/icons folder, and provides a simple interface for requesting icons. Only icons - listed in the ICON_MAP are handled. + listed in the ICON_KEYS are handled. Icons are loaded on first request, and then cached for further - requests. Each icon key in the ICON_MAP has a series of fallbacks: - * The first lookup is in the key-to-file map for the selected icon - theme. The map is specified in the icons.conf file in the theme - folder. The map makes it possible to preserve the original file - name from the icon theme were the icons were extracted. - * Second, if the icon does not exist in the theme map, the - GuiIcons class will check if there is a QStyle icon specified in - the ICON_MAP data tuple[0]. This will let Qt pull the closest - system icon. - * Third action is to look up the freedesktop icon theme name using - the fromTheme Qt call. This generally produces the same result - as the step above, but has more icons available in other cases. - * Fourth, and finally, the icon is looked up in the fallback - folder. Files in this folder must have the same file name as the - novelWriter internal icon key, with '-dark' appended to them for - the dark background version of the icon. If no dark icon exists, - the non-dark version will be returned. + requests. Each icon key in the ICON_KEYS set has standard icon set + in the icon theme conf file. The existence of the file, and the + definition of all keys are checked when the theme is loaded. + + When an icon is requested, the icon is loaded and cached. If it is + missing, a blank icon is returned and a warning issued. """ - ICON_MAP = { + ICON_KEYS = { # Project and GUI icons - "novelwriter": (None, None), - "cls_none": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_novel": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_plot": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_character": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_world": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_timeline": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_object": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_entity": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_custom": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_archive": (QStyle.SP_DriveHDIcon, "drive-harddisk"), - "cls_trash": (QStyle.SP_TrashIcon, "user-trash"), - "proj_document": (QStyle.SP_FileIcon, "x-office-document"), - "proj_title": (QStyle.SP_FileIcon, "x-office-document"), - "proj_chapter": (QStyle.SP_FileIcon, "x-office-document"), - "proj_scene": (QStyle.SP_FileIcon, "x-office-document"), - "proj_note": (QStyle.SP_FileIcon, "x-office-document"), - "proj_folder": (QStyle.SP_DirIcon, "folder"), - "proj_nwx": (None, None), - "status_lang": (None, None), - "status_time": (None, None), - "status_idle": (None, None), - "status_stats": (None, None), - "status_lines": (None, None), - "doc_h0": (QStyle.SP_FileIcon, "x-office-document"), - "doc_h1": (QStyle.SP_FileIcon, "x-office-document"), - "doc_h2": (QStyle.SP_FileIcon, "x-office-document"), - "doc_h3": (QStyle.SP_FileIcon, "x-office-document"), - "doc_h4": (QStyle.SP_FileIcon, "x-office-document"), - "search_case": (None, None), - "search_regex": (None, None), - "search_word": (None, None), - "search_loop": (None, None), - "search_project": (None, None), - "search_cancel": (None, None), - "search_preserve": (None, None), + "novelwriter", "proj_nwx", + "cls_none", "cls_novel", "cls_plot", "cls_character", "cls_world", + "cls_timeline", "cls_object", "cls_entity", "cls_custom", "cls_archive", "cls_trash", + "proj_document", "proj_title", "proj_chapter", "proj_scene", "proj_note", "proj_folder", + "status_lang", "status_time", "status_idle", "status_stats", "status_lines", + "doc_h0", "doc_h1", "doc_h2", "doc_h3", "doc_h4", + "search_case", "search_regex", "search_word", "search_loop", "search_project", + "search_cancel", "search_preserve", # General Button Icons - "folder-open": (QStyle.SP_DirOpenIcon, "folder-open"), - "delete": (QStyle.SP_DialogDiscardButton, "edit-delete"), - "close": (QStyle.SP_DialogCloseButton, "window-close"), - "done": (QStyle.SP_DialogApplyButton, None), - "clear": (QStyle.SP_LineEditClearButton, "clear_left"), - "save": (QStyle.SP_DialogSaveButton, "document-save"), - "add": (None, "list-add"), - "remove": (None, "list-remove"), - "search": (None, "edit-find"), - "search-replace": (None, "edit-find-replace"), - "edit": (None, None), - "check": (None, None), - "cross": (None, None), - "hash": (None, None), - "maximise": (None, None), - "minimise": (None, None), - "refresh": (None, None), - "reference": (None, None), - "backward": (None, None), - "forward": (None, None), - "settings": (None, None), + "delete", "close", "done", "clear", "save", "add", "remove", + "search", "search_replace", "edit", "check", "cross", "hash", + "maximise", "minimise", "refresh", "reference", "backward", + "forward", "settings", # Switches - "sticky-on": (None, None), - "sticky-off": (None, None), - "bullet-on": (None, None), - "bullet-off": (None, None), + "sticky-on", "sticky-off", + "bullet-on", "bullet-off", } DECO_MAP = { "wiz-back": "wizard-back.jpg", } - def __init__(self, theParent): + def __init__(self, theTheme): - self.mainConf = novelwriter.CONFIG - self.theParent = theParent + self.mainConf = novelwriter.CONFIG + self.theTheme = theTheme # Storage - self.qIcons = {} - self.themeMap = {} - self.themeList = [] - self.fbackName = "fallback" - self.confName = "icons.conf" + self._qIcons = {} + self._themeMap = {} + self._themeList = [] + self._confName = "icons.conf" # Icon Theme Path - self.iconPath = None - self.confFile = None + self._iconPath = os.path.join(self.mainConf.assetPath, "icons") + self._themePath = os.path.join(self._iconPath, "system") # Icon Theme Meta self.themeName = "" @@ -629,24 +514,23 @@ class GuiIcons: the GUI icons cannot really be replaced without writing specific update functions for the classes where they're used. """ - logger.debug("Loading icon theme files") - - self.themeMap = {} - checkPath = os.path.join(self.mainConf.iconPath, self.mainConf.guiIcons) - if os.path.isdir(checkPath): - logger.debug("Loading icon theme '%s'", self.mainConf.guiIcons) - self.iconPath = checkPath - self.confFile = os.path.join(checkPath, self.confName) - else: + self._themeMap = {} + themePath = self._getThemePath() + if themePath is None: + logger.warning("No icons loaded") return False + self._themePath = themePath + themeConf = os.path.join(themePath, self._confName) + logger.info("Loading icon theme '%s'", self.mainConf.guiIcons) + # Config File confParser = NWConfigParser() try: - with open(self.confFile, mode="r", encoding="utf-8") as inFile: + with open(themeConf, mode="r", encoding="utf-8") as inFile: confParser.read_file(inFile) except Exception: - logger.error("Could not load icon theme settings from: %s", self.confFile) + logger.error("Could not load icon theme settings from: %s", themeConf) novelwriter.logException() return False @@ -661,21 +545,28 @@ class GuiIcons: self.themeLicense = confParser.rdStr(cnfSec, "license", "N/A") self.themeLicenseUrl = confParser.rdStr(cnfSec, "licenseurl", "") - # Palette + # Populate Icon Map cnfSec = "Map" if confParser.has_section(cnfSec): for iconName, iconFile in confParser.items(cnfSec): - if iconName not in self.ICON_MAP: + if iconName not in self.ICON_KEYS: logger.error("Unknown icon name '%s' in config file", iconName) else: - iconPath = os.path.join(self.iconPath, iconFile) + iconPath = os.path.join(self._themePath, iconFile) if os.path.isfile(iconPath): - self.themeMap[iconName] = iconPath + self._themeMap[iconName] = iconPath logger.verbose("Icon slot '%s' using file '%s'", iconName, iconFile) else: logger.error("Icon file '%s' not in theme folder", iconFile) - logger.info("Loaded icon theme '%s'", self.mainConf.guiIcons) + # Check that icons have been defined + logger.debug("Scanning theme icons") + for iconKey in self.ICON_KEYS: + if iconKey in ("novelwriter", "proj_nwx"): + # These are not part of the theme itself + continue + if iconKey not in self._themeMap: + logger.error("No icon file specified for '%s'", iconKey) return True @@ -713,11 +604,11 @@ class GuiIcons: return, load it, and if it still doesn't exist, return an empty icon. """ - if iconKey in self.qIcons: - return self.qIcons[iconKey] + if iconKey in self._qIcons: + return self._qIcons[iconKey] else: qIcon = self._loadIcon(iconKey) - self.qIcons[iconKey] = qIcon + self._qIcons[iconKey] = qIcon return qIcon def getPixmap(self, iconKey, iconSize): @@ -758,89 +649,87 @@ class GuiIcons: def listThemes(self): """Scan the icons themes folder and list all themes. """ - if self.themeList: - return self.themeList + if self._themeList: + return self._themeList confParser = NWConfigParser() - for themeDir in os.listdir(self.mainConf.iconPath): - themePath = os.path.join(self.mainConf.iconPath, themeDir) - if not os.path.isdir(themePath) or themeDir == self.fbackName: + for themeDir in os.listdir(self._iconPath): + themePath = os.path.join(self._iconPath, themeDir) + if not os.path.isdir(themePath): continue - themeConf = os.path.join(themePath, self.confName) + logger.verbose("Checking icon theme config for '%s'", themeDir) - try: - with open(themeConf, mode="r", encoding="utf-8") as inFile: - confParser.read_file(inFile) - except Exception as e: - self.theParent.makeAlert([ - self.tr("Could not load theme config file."), str(e) - ], nwAlert.ERROR) - continue - themeName = "" - if confParser.has_section("Main"): - if confParser.has_option("Main", "name"): - themeName = confParser.get("Main", "name") - logger.verbose("Theme name is '%s'", themeName) - if themeName != "": - self.themeList.append((themeDir, themeName)) + themeConf = os.path.join(themePath, self._confName) + themeName = _loadInternalName(confParser, themeConf) + if themeName: + self._themeList.append((themeDir, themeName)) - self.themeList = sorted(self.themeList, key=lambda x: x[1]) + self._themeList = sorted(self._themeList, key=lambda x: x[1]) - return self.themeList + return self._themeList ## # Internal Functions ## - def _loadIcon(self, iconKey): - """Load an icon from the assets or themes folder, with a - preference for dark/light icons depending on theme type, if such - an icon exists. Prefer svg files over png files. Always returns - a QIcon. + def _getThemePath(self): + """Get a valid theme path. Returns None if it fails. """ - if iconKey not in self.ICON_MAP: + themePath = os.path.join(self.mainConf.assetPath, "icons", self.mainConf.guiIcons) + if not os.path.isdir(themePath): + logger.warning( + "Icon theme '%s' not found, resetting to default", self.mainConf.guiIcons + ) + self.mainConf.setDefaultIconTheme() + + themePath = os.path.join(self.mainConf.assetPath, "icons", self.mainConf.guiIcons) + if not os.path.isdir(themePath): + logger.error("Default icon theme not found") + return None + + return themePath + + def _loadIcon(self, iconKey): + """Load an icon from the assets themes folder. Is guaranteed to + return a QIcon. + """ + if iconKey not in self.ICON_KEYS: logger.error("Requested unknown icon name '%s'", iconKey) return QIcon() - # If we just want the app icon, return it right away + # If we just want the app icons, return right away if iconKey == "novelwriter": - return QIcon(os.path.join(self.mainConf.iconPath, "novelwriter.svg")) + return QIcon(os.path.join(self._iconPath, "novelwriter.svg")) + elif iconKey == "proj_nwx": + return QIcon(os.path.join(self._iconPath, "x-novelwriter-project.svg")) - # Otherwise, we start looking for it - # First in the theme folder - if iconKey in self.themeMap: - relPath = os.path.relpath(self.themeMap[iconKey], self.mainConf.iconPath) + # Otherwise, we load from the theme folder + if iconKey in self._themeMap: + relPath = os.path.relpath(self._themeMap[iconKey], self._iconPath) logger.verbose("Loading: %s", relPath) - return QIcon(self.themeMap[iconKey]) + return QIcon(self._themeMap[iconKey]) - # Next, we try to load the Qt style icons - if self.ICON_MAP[iconKey][0] is not None: - logger.verbose("Loading icon '%s' from Qt QStyle.standardIcon", iconKey) - return qApp.style().standardIcon(self.ICON_MAP[iconKey][0]) - - # If we're still here, try to set from system theme - if self.ICON_MAP[iconKey][1] is not None: - logger.verbose("Loading icon '%s' from system theme", iconKey) - if QIcon().hasThemeIcon(self.ICON_MAP[iconKey][1]): - return QIcon().fromTheme(self.ICON_MAP[iconKey][1]) - - # Finally. we check if we have a fallback icon - if self.mainConf.guiDark: - fbackIcon = os.path.join( - self.mainConf.iconPath, self.fbackName, "%s-dark.svg" % iconKey - ) - if os.path.isfile(fbackIcon): - logger.verbose("Loading icon '%s' from fallback theme (dark mode)", iconKey) - return QIcon(fbackIcon) - - fbackIcon = os.path.join(self.mainConf.iconPath, self.fbackName, "%s.svg" % iconKey) - if os.path.isfile(fbackIcon): - logger.verbose("Loading icon '%s' from fallback theme (light mode)", iconKey) - return QIcon(fbackIcon) - - # Give up and return an empty icon + # If we didn't find one, give up and return an empty icon logger.warning("Did not load an icon for '%s'", iconKey) return QIcon() # END Class GuiIcons + + +# =============================================================================================== # +# Module Functions +# =============================================================================================== # + +def _loadInternalName(confParser, confFile): + """Open a conf file and read the 'name' setting. + """ + try: + with open(confFile, mode="r", encoding="utf-8") as inFile: + confParser.read_file(inFile) + except Exception: + logger.error("Could not load file: %s", confFile) + novelwriter.logException() + return "" + + return confParser.rdStr("Main", "name", "") diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index a2f30297..1b32718f 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -83,7 +83,7 @@ class GuiMain(QMainWindow): # ============ # Core Classes and Settings - self.theTheme = GuiTheme(self) + self.theTheme = GuiTheme() self.theProject = NWProject(self) self.theIndex = NWIndex(self.theProject) self.hasProject = False diff --git a/setup/debian/copyright b/setup/debian/copyright index 5d7e2a98..a60ea0d4 100644 --- a/setup/debian/copyright +++ b/setup/debian/copyright @@ -19,12 +19,6 @@ License: GPL-3.0-or-later You should have received a copy of the GNU General Public License along with this program. If not, see . -Files: novelwriter/assets/fonts/Cantarell/* -Copyright: 2009-2010, Understanding Limited -License: OFL-1.1 - This Font Software is licensed under the SIL Open Font License, Version 1.1. - This license is available with a FAQ at: http://scripts.sil.org/OFL - Files: novelwriter/assets/icons/typicons_*.svg Copyright: 2019, Stephen Hutchings License: CC-BY-SA-4.0 diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf index 2b966644..8859e538 100644 --- a/tests/reference/baseConfig_novelwriter.conf +++ b/tests/reference/baseConfig_novelwriter.conf @@ -1,9 +1,8 @@ [Main] -timestamp = 2021-09-10 00:23:50 +timestamp = 2021-09-15 14:39:52 theme = default syntax = default_light icons = typicons_light -guidark = False guifont = guifontsize = 11 lastnotes = 0x0 diff --git a/tests/reference/guiPreferences_novelwriter.conf b/tests/reference/guiPreferences_novelwriter.conf index e498b229..f6c342ea 100644 --- a/tests/reference/guiPreferences_novelwriter.conf +++ b/tests/reference/guiPreferences_novelwriter.conf @@ -1,9 +1,8 @@ [Main] -timestamp = 2021-09-10 00:23:52 +timestamp = 2021-09-15 14:29:30 theme = default syntax = default_light icons = typicons_light -guidark = True guifont = Sans guifontsize = 12 lastnotes = 0x0 diff --git a/tests/test_base/test_base_common.py b/tests/test_base/test_base_common.py index 087cd5c1..25527513 100644 --- a/tests/test_base/test_base_common.py +++ b/tests/test_base/test_base_common.py @@ -29,12 +29,13 @@ from datetime import datetime from mock import causeOSError from tools import writeFile +from novelwriter.guimain import GuiMain from novelwriter.common import ( checkString, checkInt, checkBool, checkHandle, isHandle, isTitleTag, isItemClass, isItemType, isItemLayout, hexToInt, formatInt, formatTimeStamp, formatTime, parseTimeStamp, splitVersionNumber, - transferCase, fuzzyTime, numberToRoman, jsonEncode, makeFileNameSafe, - sha256sum, NWConfigParser + transferCase, fuzzyTime, numberToRoman, jsonEncode, readTextFile, + makeFileNameSafe, sha256sum, getGuiItem, NWConfigParser ) @@ -456,6 +457,24 @@ def testBaseCommon_JsonEncode(): # END Test testBaseCommon_JsonEncode +@pytest.mark.base +def testBaseCommon_ReadTextFile(monkeypatch, fncDir, ipsumText): + """Test the readTextFile function. + """ + testText = "\n\n".join(ipsumText) + "\n" + testFile = os.path.join(fncDir, "ipsum.txt") + writeFile(testFile, testText) + + assert readTextFile(os.path.join(fncDir, "not_a_file.txt")) == "" + assert readTextFile(testFile) == testText + + with monkeypatch.context() as mp: + mp.setattr("builtins.open", causeOSError) + assert readTextFile(testFile) == "" + +# END Test testBaseCommon_ReadTextFile + + @pytest.mark.base def testBaseCommon_MakeFileNameSafe(): """Test the makeFileNameSafe function. @@ -508,6 +527,16 @@ def testBaseCommon_Sha256Sum(monkeypatch, fncDir, ipsumText): # END Test testBaseCommon_Sha256Sum +@pytest.mark.base +def testBaseCommon_GetGuiItem(nwGUI): + """Check the GUI item function. + """ + assert getGuiItem("gibberish") is None + assert isinstance(getGuiItem("GuiMain"), GuiMain) + +# END Test testBaseCommon_GetGuiItem + + @pytest.mark.base def testBaseCommon_NWConfigParser(fncDir): """Test the NWConfigParser subclass. diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py index 996d11c5..ae9301bb 100644 --- a/tests/test_base/test_base_config.py +++ b/tests/test_base/test_base_config.py @@ -139,7 +139,7 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir): assert os.path.isfile(confFile) copyfile(confFile, testFile) - assert cmpFiles(testFile, compFile, [2, 9, 10]) + assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang")) # Load and save with OSError with monkeypatch.context() as mp: @@ -255,7 +255,7 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir): assert theList == [("en_GB", "British English"), ("fr", "Français")] copyfile(confFile, testFile) - assert cmpFiles(testFile, compFile, [2, 9, 10]) + assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang")) # END Test testBaseConfig_Init @@ -539,7 +539,7 @@ def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir): assert tmpConf.confChanged is False copyfile(confFile, testFile) - assert cmpFiles(testFile, compFile, [2, 9, 10]) + assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang")) # END Test testBaseConfig_SettersGetters diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index 4b3cf847..52d2448a 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -84,11 +84,6 @@ def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir): tabGeneral = nwPrefs.tabGeneral nwPrefs._tabBox.setCurrentWidget(tabGeneral) - qtbot.wait(keyDelay) - assert not tabGeneral.guiDark.isChecked() - qtbot.mouseClick(tabGeneral.guiDark, Qt.LeftButton) - assert tabGeneral.guiDark.isChecked() - qtbot.wait(keyDelay) assert tabGeneral.showFullPath.isChecked() qtbot.mouseClick(tabGeneral.showFullPath, Qt.LeftButton) @@ -249,8 +244,12 @@ def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir): testFile = os.path.join(outDir, "guiPreferences_novelwriter.conf") compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf") copyfile(projFile, testFile) - ignoreLines = [2, 7, 9, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, 32, 33] - assert cmpFiles(testFile, compFile, ignoreLines) + ignTuple = ( + "timestamp", "guifont", "lastnotes", "guilang", "geometry", + "preferences", "treecols", "novelcols", "projcols", "mainpane", + "docpane", "viewpane", "outlinepane", "textfont", "textsize" + ) + assert cmpFiles(testFile, compFile, ignoreStart=ignTuple) # Clean up novelwriter.CONFIG = origConf diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py index 150b3af6..b35ffa36 100644 --- a/tests/test_gui/test_gui_theme.py +++ b/tests/test_gui/test_gui_theme.py @@ -23,7 +23,7 @@ import pytest import novelwriter from PyQt5.QtGui import QColor, QPixmap, QIcon -from PyQt5.QtWidgets import QStyle, QMessageBox +from PyQt5.QtWidgets import QMessageBox keyDelay = 2 typeDelay = 1 @@ -50,7 +50,6 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): novelwriter.CONFIG.guiTheme = "default_dark" novelwriter.CONFIG.guiSyntax = "tomorrow_night_eighties" novelwriter.CONFIG.guiIcons = "typicons_colour_dark" - novelwriter.CONFIG.guiDark = True novelwriter.CONFIG.guiFont = "Cantarell" novelwriter.CONFIG.guiFontSize = 11 novelwriter.CONFIG.confChanged = True @@ -73,9 +72,8 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): assert novelwriter.CONFIG.guiTheme == "default_dark" assert novelwriter.CONFIG.guiSyntax == "tomorrow_night_eighties" assert novelwriter.CONFIG.guiIcons == "typicons_dark" - assert novelwriter.CONFIG.guiDark is True - assert novelwriter.CONFIG.guiFont == "Cantarell" - assert novelwriter.CONFIG.guiFontSize == 11 + assert novelwriter.CONFIG.guiFont != "" + assert novelwriter.CONFIG.guiFontSize > 0 # Check GUI Colours thePalette = nwGUI.palette() @@ -119,9 +117,8 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): # Test Icon class theIcons = nwGUI.theTheme.theIcons novelwriter.CONFIG.guiIcons = "invalid" - assert not theIcons.updateTheme() - novelwriter.CONFIG.guiIcons = "typicons_dark" - assert theIcons.updateTheme() + assert theIcons.updateTheme() is True + assert novelwriter.CONFIG.guiIcons == "typicons_light" # Ask for a non-existent key anImg = theIcons.loadDecoration("nonsense", 20, 20) @@ -168,17 +165,8 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): assert isinstance(anIcon, QIcon) assert not anIcon.isNull() - # Add test icons and test alternative load paths - theIcons.ICON_MAP["testicon1"] = (QStyle.SP_DriveHDIcon, None) - anIcon = theIcons.getIcon("testicon1") - assert isinstance(anIcon, QIcon) - assert not anIcon.isNull() - - theIcons.ICON_MAP["testicon2"] = (None, "folder") - anIcon = theIcons.getIcon("testicon2") - assert isinstance(anIcon, QIcon) - - theIcons.ICON_MAP["testicon3"] = (None, None) + # Check return empty icon if file not found + theIcons.ICON_KEYS.add("testicon3") anIcon = theIcons.getIcon("testicon3") assert isinstance(anIcon, QIcon) assert anIcon.isNull() diff --git a/tests/tools.py b/tests/tools.py index 03f23d34..450c4fed 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -25,7 +25,7 @@ import shutil from PyQt5.QtWidgets import qApp -def cmpFiles(fileOne, fileTwo, ignoreLines=None): +def cmpFiles(fileOne, fileTwo, ignoreLines=None, ignoreStart=None): """Compare two files, but optionally ignore lines given by a list. """ if ignoreLines is None: @@ -59,6 +59,11 @@ def cmpFiles(fileOne, fileTwo, ignoreLines=None): print("Ignoring line %d" % (n+1)) continue + if ignoreStart is not None: + if lnOne.startswith(ignoreStart): + print("Ignoring line %d" % (n+1)) + continue + if lnOne != lnTwo: print("Diff on line %d:" % (n+1)) print(" << '%s'" % lnOne)