Files
UmbraEdit/umbraedit/constants.py
B.D. Murphy f421136f75 house: update website URLs to umbratools.com/umbraedit
- Update all website references from umbraedit.io to umbratools.com/umbraedit
- Update documentation URLs from docs.umbraedit.io to umbratools.com/umbraedit/docs
- Update release URLs from releases.umbraedit.io to umbratools.com/umbraedit/releases
- Update __domain__ to umbratools.com for Qt organization domain
- Update README first image to reference UmbraEdit icon SVG
- Update README link text from umbraedit.io to UmbraEdit
- Update test versioninfo expected text
2026-11-06 07:26:55 -08:00

925 lines
33 KiB
Python

"""
UmbraEdit - Constants
=======================
This file is a part of UmbraEdit.
Copyright (C) 2019 Veronica Berglyd Olsen and UmbraEdit contributors.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
""" # noqa
from __future__ import annotations
from typing import ClassVar
from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
from umbraedit.enum import (
nwBuildFmt,
nwComment,
nwItemClass,
nwItemLayout,
nwStatusShape,
nwStdLabel,
nwStdUnit,
nwTheme,
)
def trConst(text: str) -> str:
"""Translate a constant."""
return QCoreApplication.translate("Constant", text)
def trStats(text: str) -> str:
"""Translate a stats constants."""
return QCoreApplication.translate("Stats", text)
def trLabel(label: nwStdLabel) -> str:
"""Return a translated standard label."""
return QCoreApplication.translate("Constant", nwLabels.STANDARD_LABEL.get(label, ""))
def trUnit(unit: nwStdUnit) -> str:
"""Return a translated standard unit."""
return QCoreApplication.translate("Units", nwLabels.UNIT_LABELS.get(unit, ""))
class nwConst:
"""Various Constants."""
# Date and Time Formats
FMT_TSTAMP = "%Y-%m-%d %H:%M:%S" # Default format
FMT_DSTAMP = "%Y-%m-%d" # Date only format
# URLs
URL_WEB = "https://umbratools.com/umbraedit"
URL_DOCS = "https://umbratools.com/umbraedit/docs"
URL_RELEASES = "https://umbratools.com/umbraedit/releases"
URL_CODE = "https://github.com/saga-soft/UmbraEdit"
URL_REPORT = "https://github.com/saga-soft/UmbraEdit/issues"
URL_HELP = "https://github.com/saga-soft/UmbraEdit/discussions"
# Requests
USER_AGENT = "Mozilla/5.0 (compatible; UmbraEdit (Python))"
# Mime Types
MIME_HANDLE = "text/vnd.umbraedit.handle"
MIME_MARKDOWN = "text/markdown"
# Gui Settings
STATUS_MSG_TIMEOUT = 15000 # milliseconds
MAX_SEARCH_RESULT = 1000
CHECK_PASS_CHUNK = 100 # Chunk size for spell and format checking
BIG_DOC_LIMIT = 500000 # Doc size above which the initial cursor move is queued
TEXT_FONT_MIN_SIZE = 6.0 # Smallest text font size in points
TEXT_FONT_MAX_SIZE = 72.0 # Largest text font size in points
class nwRegEx:
"""Common RegExes."""
URL = r"\b(?:https?|file)://(?:www\.|(?!www))[\w/()@:%_\+-.~#!?&=]+\b"
WORDS = r"\b[^\s\-\+\/–—\[\]:]+\b" # noqa: RUF001
BREAK = r"(?i)(?<!\\)(\[br\]\n?)"
FMT_IT = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_B1 = r"(?<![\w\\])(\*{1,2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_B2 = r"(?<![\w\\])(\*{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])(~{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_HL = r"(?<![\w\\])(={2})(?![\s=])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_LN = r"(?<!\\)(\[)([^\[\]]+)(?<!\\)(\]\()([^\s()]+)(?<!\\)(\))"
FMT_SC = r"(?i)(?<!\\)(\[(?:b|/b|i|/i|s|/s|u|/u|m|/m|sup|/sup|sub|/sub|br)\])"
FMT_SV = r"(?i)(?<!\\)(\[(?:footnote|field):)(.+?)(?<!\\)(\])"
AUTO_REP = r"<([^\s<>]+)>"
class nwShortcode:
"""Document ShortCodes."""
BOLD_O = "[b]"
BOLD_C = "[/b]"
ITALIC_O = "[i]"
ITALIC_C = "[/i]"
STRIKE_O = "[s]"
STRIKE_C = "[/s]"
ULINE_O = "[u]"
ULINE_C = "[/u]"
MARK_O = "[m]"
MARK_C = "[/m]"
SUP_O = "[sup]"
SUP_C = "[/sup]"
SUB_O = "[sub]"
SUB_C = "[/sub]"
BREAK = "[br]"
FOOTNOTE_B = "[footnote:"
FIELD_B = "[field:"
COMMENT_STYLES: ClassVar[dict[nwComment, str]] = {
nwComment.FOOTNOTE: "[footnote:{0}]",
nwComment.COMMENT: "[comment:{0}]",
}
FIELD_VALUE = "[field:{0}]"
class nwStyles:
"""Style Settings for Headings."""
H_VALID = ("H0", "H1", "H2", "H3", "H4")
H_LEVEL: ClassVar[dict[str, int]] = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
H_SIZES: ClassVar[dict[int, float]] = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
H_MARKERS = ("# ", "## ", "### ", "#### ", "#! ", "##! ", "###! ")
T_NORMAL = 1.0
T_SMALL = 0.8
T_LABEL: ClassVar[dict[str, str]] = {
"H0": QT_TRANSLATE_NOOP("Constant", "Title"),
"H1": QT_TRANSLATE_NOOP("Constant", "Heading 1 (Partition)"),
"H2": QT_TRANSLATE_NOOP("Constant", "Heading 2 (Chapter)"),
"H3": QT_TRANSLATE_NOOP("Constant", "Heading 3 (Scene)"),
"H4": QT_TRANSLATE_NOOP("Constant", "Heading 4 (Section)"),
"TT": QT_TRANSLATE_NOOP("Constant", "Text Paragraph"),
"SP": QT_TRANSLATE_NOOP("Constant", "Scene Separator"),
}
T_MARGIN: ClassVar[dict[str, tuple[float, float]]] = {
"H0": (1.50, 0.60), # Title margins (top, bottom)
"H1": (1.50, 0.60), # Heading 1 margins (top, bottom)
"H2": (1.50, 0.60), # Heading 2 margins (top, bottom)
"H3": (1.20, 0.60), # Heading 3 margins (top, bottom)
"H4": (1.20, 0.60), # Heading 4 margins (top, bottom)
"TT": (0.00, 0.60), # Text margins (top, bottom)
"LI": (0.60, 0.60), # List margins (top, bottom)
"SP": (1.20, 1.20), # Separator margins (top, bottom)
"MT": (0.00, 0.60), # Meta margins (top, bottom)
"FT": (1.40, 0.40), # Footnote margins (left, bottom)
}
class nwFiles:
"""UmbraEdit Files."""
# Config Files
CONF_FILE = "umbraedit.toml"
CONF_FILE_OLD = "umbraedit.conf"
RECENT_FILE = "recentProjects.json"
RECENT_PATH = "recentPaths.json"
# Project Root Files
PROJ_FILE = "nwProject.nwx"
PROJ_LOCK = "nwProject.lock"
MANIFEST_FILE = "manifest.json"
TOC_FILE = "ToC.txt"
# Project Meta Files
BUILDS_FILE = "builds.json"
DICT_FILE = "userdict.json"
INDEX_FILE = "index.json"
OPTS_FILE = "options.json"
SESS_FILE = "sessions.jsonl"
VIEWS_FILE = "views.json"
class nwKeyWords:
"""Meta Data KeyWord Constants."""
TAG_KEY = "@tag"
POV_KEY = "@pov"
FOCUS_KEY = "@focus"
CHAR_KEY = "@char"
PLOT_KEY = "@plot"
TIME_KEY = "@time"
WORLD_KEY = "@location"
OBJECT_KEY = "@object"
ENTITY_KEY = "@entity"
CUSTOM_KEY = "@custom"
STORY_KEY = "@story"
MENTION_KEY = "@mention"
# Note: The order here affects the order of menu entries
ALL_KEYS: ClassVar[list[str]] = [
TAG_KEY,
POV_KEY,
FOCUS_KEY,
CHAR_KEY,
PLOT_KEY,
TIME_KEY,
WORLD_KEY,
OBJECT_KEY,
ENTITY_KEY,
CUSTOM_KEY,
STORY_KEY,
MENTION_KEY,
]
CAN_CREATE: ClassVar[list[str]] = [
POV_KEY,
FOCUS_KEY,
CHAR_KEY,
PLOT_KEY,
TIME_KEY,
WORLD_KEY,
OBJECT_KEY,
ENTITY_KEY,
CUSTOM_KEY,
]
CAN_LOOKUP: ClassVar[list[str]] = [
POV_KEY,
FOCUS_KEY,
CHAR_KEY,
PLOT_KEY,
TIME_KEY,
WORLD_KEY,
OBJECT_KEY,
ENTITY_KEY,
CUSTOM_KEY,
STORY_KEY,
MENTION_KEY,
]
# Set of Valid Keys
VALID_KEYS: ClassVar[set[str]] = set(ALL_KEYS)
# Map from Keys to Item Class
KEY_CLASS: ClassVar[dict[str, nwItemClass]] = {
POV_KEY: nwItemClass.CHARACTER,
FOCUS_KEY: nwItemClass.CHARACTER,
CHAR_KEY: nwItemClass.CHARACTER,
PLOT_KEY: nwItemClass.PLOT,
TIME_KEY: nwItemClass.TIMELINE,
WORLD_KEY: nwItemClass.WORLD,
OBJECT_KEY: nwItemClass.OBJECT,
ENTITY_KEY: nwItemClass.ENTITY,
CUSTOM_KEY: nwItemClass.CUSTOM,
STORY_KEY: nwItemClass.NOVEL,
}
# Map to Class Icons
KEY_ICON: ClassVar[dict[str, str]] = {
POV_KEY: "key_pov:root",
FOCUS_KEY: "key_focus:root",
CHAR_KEY: "cls_character:root",
PLOT_KEY: "cls_plot:root",
TIME_KEY: "cls_timeline:root",
WORLD_KEY: "cls_world:root",
OBJECT_KEY: "cls_object:root",
ENTITY_KEY: "cls_entity:root",
CUSTOM_KEY: "cls_custom:root",
STORY_KEY: "cls_novel:root",
MENTION_KEY: "key_mention:root",
}
class nwLists:
"""Various Lists."""
USER_CLASSES: ClassVar[list[nwItemClass]] = [
nwItemClass.CHARACTER,
nwItemClass.PLOT,
nwItemClass.WORLD,
nwItemClass.TIMELINE,
nwItemClass.OBJECT,
nwItemClass.ENTITY,
nwItemClass.CUSTOM,
]
class nwStats:
"""Text Statistics."""
CHARS = "allChars"
CHARS_TEXT = "textChars"
CHARS_TITLE = "titleChars"
CHARS_DIALOG = "dialogChars"
PARAGRAPHS = "paragraphCount"
TITLES = "titleCount"
WCHARS_ALL = "allWordChars"
WCHARS_TEXT = "textWordChars"
WCHARS_TITLE = "titleWordChars"
WORDS = "allWords"
WORDS_TEXT = "textWords"
WORDS_TITLE = "titleWords"
DIALOG_RATIO = "dialogRatio"
# Note: The order here affects the order of menu entries
ALL_FIELDS: ClassVar[list[str]] = [
WORDS,
WORDS_TEXT,
WORDS_TITLE,
CHARS,
CHARS_TEXT,
CHARS_TITLE,
WCHARS_ALL,
WCHARS_TEXT,
WCHARS_TITLE,
PARAGRAPHS,
TITLES,
]
class nwProblems:
"""Text problems."""
MISSING_AUTO_KEYS = "missingAutoKeys"
class nwLabels:
"""Various Common GUI Labels."""
CLASS_NAME: ClassVar[dict[nwItemClass, str]] = {
nwItemClass.NO_CLASS: QT_TRANSLATE_NOOP("Constant", "None"),
nwItemClass.NOVEL: QT_TRANSLATE_NOOP("Constant", "Novel"),
nwItemClass.PLOT: QT_TRANSLATE_NOOP("Constant", "Plot"),
nwItemClass.CHARACTER: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwItemClass.WORLD: QT_TRANSLATE_NOOP("Constant", "Locations"),
nwItemClass.TIMELINE: QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwItemClass.OBJECT: QT_TRANSLATE_NOOP("Constant", "Objects"),
nwItemClass.ENTITY: QT_TRANSLATE_NOOP("Constant", "Entities"),
nwItemClass.CUSTOM: QT_TRANSLATE_NOOP("Constant", "Custom"),
nwItemClass.ARCHIVE: QT_TRANSLATE_NOOP("Constant", "Archive"),
nwItemClass.TEMPLATE: QT_TRANSLATE_NOOP("Constant", "Templates"),
nwItemClass.TRASH: QT_TRANSLATE_NOOP("Constant", "Trash"),
}
CLASS_ICON: ClassVar[dict[nwItemClass, str]] = {
nwItemClass.NO_CLASS: "cls_none:root",
nwItemClass.NOVEL: "cls_novel:root",
nwItemClass.PLOT: "cls_plot:root",
nwItemClass.CHARACTER: "cls_character:root",
nwItemClass.WORLD: "cls_world:root",
nwItemClass.TIMELINE: "cls_timeline:root",
nwItemClass.OBJECT: "cls_object:root",
nwItemClass.ENTITY: "cls_entity:root",
nwItemClass.CUSTOM: "cls_custom:root",
nwItemClass.ARCHIVE: "cls_archive:root",
nwItemClass.TEMPLATE: "cls_template:root",
nwItemClass.TRASH: "cls_trash:root",
}
LAYOUT_NAME: ClassVar[dict[nwItemLayout, str]] = {
nwItemLayout.NO_LAYOUT: QT_TRANSLATE_NOOP("Constant", "None"),
nwItemLayout.DOCUMENT: QT_TRANSLATE_NOOP("Constant", "Novel Document"),
nwItemLayout.NOTE: QT_TRANSLATE_NOOP("Constant", "Project Note"),
}
STANDARD_LABEL: ClassVar[dict[nwStdLabel, str]] = {
nwStdLabel.NOTE: QT_TRANSLATE_NOOP("Constant", "Note"),
nwStdLabel.STORY_STRUCTURE: QT_TRANSLATE_NOOP("Constant", "Story Structure"),
nwStdLabel.STORY: QT_TRANSLATE_NOOP("Constant", "Story"),
nwStdLabel.SYNOPSIS: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
}
ITEM_DESCRIPTION: ClassVar[dict[str, str]] = {
"none": QT_TRANSLATE_NOOP("Constant", "None"),
"root": QT_TRANSLATE_NOOP("Constant", "Root Folder"),
"folder": QT_TRANSLATE_NOOP("Constant", "Folder"),
"document": QT_TRANSLATE_NOOP("Constant", "Novel Document"),
"doc_h1": QT_TRANSLATE_NOOP("Constant", "Novel Title Page"),
"doc_h2": QT_TRANSLATE_NOOP("Constant", "Novel Chapter"),
"doc_h3": QT_TRANSLATE_NOOP("Constant", "Novel Scene"),
"doc_h4": QT_TRANSLATE_NOOP("Constant", "Novel Section"),
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
}
ACTIVE_NAME: ClassVar[dict[bool, str]] = {
True: QT_TRANSLATE_NOOP("Constant", "Active"),
False: QT_TRANSLATE_NOOP("Constant", "Inactive"),
}
SAVED_NAME: ClassVar[dict[bool, str]] = {
True: QT_TRANSLATE_NOOP("Constant", "Saved"),
False: QT_TRANSLATE_NOOP("Constant", "Unsaved"),
}
KEY_NAME: ClassVar[dict[str, str]] = {
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
nwKeyWords.STORY_KEY: QT_TRANSLATE_NOOP("Constant", "Story"),
nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
}
KEY_SHORTCUT: ClassVar[dict[str, str]] = {
nwKeyWords.TAG_KEY: "Ctrl+K, G",
nwKeyWords.POV_KEY: "Ctrl+K, V",
nwKeyWords.FOCUS_KEY: "Ctrl+K, F",
nwKeyWords.CHAR_KEY: "Ctrl+K, C",
nwKeyWords.PLOT_KEY: "Ctrl+K, P",
nwKeyWords.TIME_KEY: "Ctrl+K, T",
nwKeyWords.WORLD_KEY: "Ctrl+K, L",
nwKeyWords.OBJECT_KEY: "Ctrl+K, O",
nwKeyWords.ENTITY_KEY: "Ctrl+K, E",
nwKeyWords.CUSTOM_KEY: "Ctrl+K, X",
nwKeyWords.STORY_KEY: "Ctrl+K, N",
nwKeyWords.MENTION_KEY: "Ctrl+K, M",
}
STATS_NAME: ClassVar[dict[str, str]] = {
nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in text"),
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in headings"),
nwStats.CHARS_DIALOG: QT_TRANSLATE_NOOP("Stats", "Characters in dialogue"),
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Stats", "Paragraphs"),
nwStats.TITLES: QT_TRANSLATE_NOOP("Stats", "Headings"),
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Stats", "Characters, no spaces"),
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in text, no spaces"),
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in headings, no spaces"),
nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words"),
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in text"),
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in headings"),
nwStats.DIALOG_RATIO: QT_TRANSLATE_NOOP("Stats", "Dialogue"),
}
STATS_DISPLAY: ClassVar[dict[str, str]] = {
nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters: {0} ({1})"),
nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words: {0} ({1})"),
}
PROBLEM_NAME: ClassVar[dict[str, str]] = {
nwProblems.MISSING_AUTO_KEYS: QT_TRANSLATE_NOOP("Constant", "Missing Auto-Replace Keys"),
}
UNIT_LABELS: ClassVar[dict[nwStdUnit, str]] = {
nwStdUnit.CHARS: QT_TRANSLATE_NOOP("Units", "characters"),
nwStdUnit.WORDS: QT_TRANSLATE_NOOP("Units", "words"),
nwStdUnit.LINES: QT_TRANSLATE_NOOP("Units", "lines"),
nwStdUnit.PIXELS: QT_TRANSLATE_NOOP("Units", "px"),
nwStdUnit.POINTS: QT_TRANSLATE_NOOP("Units", "pt"),
nwStdUnit.EM: QT_TRANSLATE_NOOP("Units", "em"),
nwStdUnit.SECONDS: QT_TRANSLATE_NOOP("Units", "seconds"),
nwStdUnit.MINUTES: QT_TRANSLATE_NOOP("Units", "minutes"),
}
BUILD_FMT: ClassVar[dict[nwBuildFmt, str]] = {
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
nwBuildFmt.FODT: QT_TRANSLATE_NOOP("Constant", "Flat Open Document (.fodt)"),
nwBuildFmt.DOCX: QT_TRANSLATE_NOOP("Constant", "Microsoft Word Document (.docx)"),
nwBuildFmt.HTML: QT_TRANSLATE_NOOP("Constant", "HTML 5 (.html)"),
nwBuildFmt.EPUB: QT_TRANSLATE_NOOP("Constant", "Electronic Publication E-book (.epub)"),
nwBuildFmt.NWD: QT_TRANSLATE_NOOP("Constant", "UmbraEdit Markup (.txt)"),
nwBuildFmt.STD_MD: QT_TRANSLATE_NOOP("Constant", "Standard Markdown (.md)"),
nwBuildFmt.EXT_MD: QT_TRANSLATE_NOOP("Constant", "Extended Markdown (.md)"),
nwBuildFmt.PDF: QT_TRANSLATE_NOOP("Constant", "Portable Document Format (.pdf)"),
nwBuildFmt.J_HTML: QT_TRANSLATE_NOOP("Constant", "JSON + HTML 5 (.json)"),
nwBuildFmt.J_NWD: QT_TRANSLATE_NOOP("Constant", "JSON + UmbraEdit Markup (.json)"),
}
BUILD_EXT: ClassVar[dict[nwBuildFmt, str]] = {
nwBuildFmt.ODT: ".odt",
nwBuildFmt.FODT: ".fodt",
nwBuildFmt.DOCX: ".docx",
nwBuildFmt.HTML: ".html",
nwBuildFmt.EPUB: ".epub",
nwBuildFmt.NWD: ".txt",
nwBuildFmt.STD_MD: ".md",
nwBuildFmt.EXT_MD: ".md",
nwBuildFmt.PDF: ".pdf",
nwBuildFmt.J_HTML: ".json",
nwBuildFmt.J_NWD: ".json",
}
SHAPES_PLAIN: ClassVar[dict[nwStatusShape, str]] = {
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
}
SHAPES_CIRCLE: ClassVar[dict[nwStatusShape, str]] = {
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
}
SHAPES_BARS: ClassVar[dict[nwStatusShape, str]] = {
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
}
SHAPES_BLOCKS: ClassVar[dict[nwStatusShape, str]] = {
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
}
FILE_FILTERS: ClassVar[dict[str, str]] = {
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
"*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
"*.csv": QT_TRANSLATE_NOOP("Constant", "CSV files"),
"*": QT_TRANSLATE_NOOP("Constant", "All files"),
}
PAGE_UNIT_NAME: ClassVar[dict[str, str]] = {
"mm": QT_TRANSLATE_NOOP("Constant", "Millimetres"),
"cm": QT_TRANSLATE_NOOP("Constant", "Centimetres"),
"in": QT_TRANSLATE_NOOP("Constant", "Inches"),
}
PAGE_UNIT_SCALE: ClassVar[dict[str, float]] = {
"mm": 1.0,
"cm": 10.0,
"in": 25.4,
}
PAPER_NAME: ClassVar[dict[str, str]] = {
"A4": QT_TRANSLATE_NOOP("Constant", "A4"),
"A5": QT_TRANSLATE_NOOP("Constant", "A5"),
"A6": QT_TRANSLATE_NOOP("Constant", "A6"),
"Legal": QT_TRANSLATE_NOOP("Constant", "US Legal"),
"Letter": QT_TRANSLATE_NOOP("Constant", "US Letter"),
"Custom": QT_TRANSLATE_NOOP("Constant", "Custom"),
}
PAPER_SIZE: ClassVar[dict[str, tuple[float, float]]] = {
"A4": (210.0, 297.0),
"A5": (148.0, 210.0),
"A6": (105.0, 148.0),
"Legal": (215.9, 355.6),
"Letter": (215.9, 279.4),
"Custom": (-1.0, -1.0),
}
THEME_COLORS: ClassVar[dict[str, str]] = {
"default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"),
"base": QT_TRANSLATE_NOOP("Constant", "Background Colour"),
"faded": QT_TRANSLATE_NOOP("Constant", "Faded Colour"),
"red": QT_TRANSLATE_NOOP("Constant", "Red"),
"orange": QT_TRANSLATE_NOOP("Constant", "Orange"),
"yellow": QT_TRANSLATE_NOOP("Constant", "Yellow"),
"green": QT_TRANSLATE_NOOP("Constant", "Green"),
"cyan": QT_TRANSLATE_NOOP("Constant", "Cyan"),
"blue": QT_TRANSLATE_NOOP("Constant", "Blue"),
"purple": QT_TRANSLATE_NOOP("Constant", "Purple"),
}
THEME_MODE_ICON: ClassVar[dict[nwTheme, str]] = {
nwTheme.AUTO: "theme_auto:sidebar",
nwTheme.LIGHT: "theme_light:sidebar",
nwTheme.DARK: "theme_dark:sidebar",
}
THEME_MODE_LABEL: ClassVar[dict[nwTheme, str]] = {
nwTheme.AUTO: QT_TRANSLATE_NOOP("Constant", "System Theme"),
nwTheme.LIGHT: QT_TRANSLATE_NOOP("Constant", "Light Theme"),
nwTheme.DARK: QT_TRANSLATE_NOOP("Constant", "Dark Theme"),
}
COMMENT_ICON: ClassVar[dict[nwComment, str]] = {
nwComment.PLAIN: "cmn_general:faded",
nwComment.IGNORE: "cmn_general:disabled",
nwComment.SYNOPSIS: "cmn_general:note",
nwComment.SHORT: "cmn_general:note",
nwComment.NOTE: "cmn_note:note",
nwComment.FOOTNOTE: "cmn_note:active",
nwComment.COMMENT: "cmn_general:faded",
nwComment.STORY: "cmn_story:note",
}
BACKUP_INTERVAL: ClassVar[dict[str, str]] = {
"session": QT_TRANSLATE_NOOP("Constant", "Per Session"),
"day": QT_TRANSLATE_NOOP("Constant", "Per Day"),
"week": QT_TRANSLATE_NOOP("Constant", "Per Week"),
"month": QT_TRANSLATE_NOOP("Constant", "Per Month"),
}
FILTER_GROUPS: ClassVar[dict[str, str]] = {
"documents": QT_TRANSLATE_NOOP("Constant", "Document Filters"),
"content": QT_TRANSLATE_NOOP("Constant", "Content Filters"),
}
FILTER_TYPES: ClassVar[dict[str, str]] = {
"novel": QT_TRANSLATE_NOOP("Constant", "Novel documents"),
"notes": QT_TRANSLATE_NOOP("Constant", "Project notes"),
"inactive": QT_TRANSLATE_NOOP("Constant", "Inactive documents"),
"headings": QT_TRANSLATE_NOOP("Constant", "Headings"),
"text": QT_TRANSLATE_NOOP("Constant", "Body text paragraphs"),
"meta": QT_TRANSLATE_NOOP("Constant", "Tags and references"),
"comments": QT_TRANSLATE_NOOP("Constant", "Comments and footnotes"),
}
BREAK_TYPES: ClassVar[dict[int, str]] = {
0: QT_TRANSLATE_NOOP("Constant", "No Break"),
1: QT_TRANSLATE_NOOP("Constant", "Any Page"),
2: QT_TRANSLATE_NOOP("Constant", "Odd Page"),
}
class nwHeadFmt:
"""Manuscript Header Formats."""
BR = "{BR}"
TITLE = "{Title}"
CH_NUM = "{Chapter}"
CH_WORD = "{Chapter:Word}"
CH_ROMU = "{Chapter:URoman}"
CH_ROML = "{Chapter:LRoman}"
SC_NUM = "{Scene}"
SC_ABS = "{Scene:Abs}"
CHAR_POV = "{Char:POV}"
CHAR_FOCUS = "{Char:Focus}"
HRULE = "----"
PAGE_HEADERS: ClassVar[list[str]] = [
TITLE,
CH_NUM,
CH_WORD,
CH_ROMU,
CH_ROML,
SC_NUM,
SC_ABS,
CHAR_POV,
CHAR_FOCUS,
]
# Document Page Header
DOC_PROJECT = "{Project}"
DOC_AUTHOR = "{Author}"
DOC_PAGE = "{Page}"
DOC_AUTO_ODD = "{Project} / {Author} / {Page}"
DOC_AUTO_EVEN = "{Page} / {Author} / {Project}"
class nwQuotes:
"""Allowed quotation marks.
Source: https://en.wikipedia.org/wiki/Quotation_mark
"""
SYMBOLS: ClassVar[dict[str, str]] = {
"\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
"\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
"\u2018": QT_TRANSLATE_NOOP("Constant", "Left single quotation mark"),
"\u2019": QT_TRANSLATE_NOOP("Constant", "Right single quotation mark"),
"\u201a": QT_TRANSLATE_NOOP("Constant", "Single low-9 quotation mark"),
"\u201b": QT_TRANSLATE_NOOP("Constant", "Single high-reversed-9 quotation mark"),
"\u201c": QT_TRANSLATE_NOOP("Constant", "Left double quotation mark"),
"\u201d": QT_TRANSLATE_NOOP("Constant", "Right double quotation mark"),
"\u201e": QT_TRANSLATE_NOOP("Constant", "Double low-9 quotation mark"),
"\u201f": QT_TRANSLATE_NOOP("Constant", "Double high-reversed-9 quotation mark"),
"\u2e42": QT_TRANSLATE_NOOP("Constant", "Double low-reversed-9 quotation mark"),
"\u2039": QT_TRANSLATE_NOOP("Constant", "Single left-pointing angle quotation mark"),
"\u203a": QT_TRANSLATE_NOOP("Constant", "Single right-pointing angle quotation mark"),
"\u00ab": QT_TRANSLATE_NOOP("Constant", "Double left-pointing angle quotation mark"),
"\u00bb": QT_TRANSLATE_NOOP("Constant", "Double right-pointing angle quotation mark"),
"\u300c": QT_TRANSLATE_NOOP("Constant", "Left corner bracket"),
"\u300d": QT_TRANSLATE_NOOP("Constant", "Right corner bracket"),
"\u300e": QT_TRANSLATE_NOOP("Constant", "Left white corner bracket"),
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
}
DASHES: ClassVar[dict[str, str]] = {
"": QT_TRANSLATE_NOOP("Constant", "None"),
"\u2013": QT_TRANSLATE_NOOP("Constant", "Short dash"),
"\u2014": QT_TRANSLATE_NOOP("Constant", "Long dash"),
"\u2015": QT_TRANSLATE_NOOP("Constant", "Horizontal bar"),
}
ALLOWED: ClassVar[list[str]] = [
"\u0027",
"\u0022",
"\u2018",
"\u2019",
"\u201a",
"\u201b",
"\u201c",
"\u201d",
"\u201e",
"\u201f",
"\u2e42",
"\u2039",
"\u203a",
"\u00ab",
"\u00bb",
"\u300c",
"\u300d",
"\u300e",
"\u300f",
"\u2013",
"\u2014",
"\u2015",
]
class nwUnicode:
"""Supported unicode character constants and their HTML equivalents."""
# Unicode Constants
# =================
# Quotation Marks
U_QUOT = "\u0022" # Quotation mark
U_APOS = "\u0027" # Apostrophe
U_LAQUO = "\u00ab" # Left-pointing double angle quotation mark
U_RAQUO = "\u00bb" # Right-pointing double angle quotation mark
U_LSQUO = "\u2018" # Left single quotation mark
U_RSQUO = "\u2019" # Right single quotation mark
U_SBQUO = "\u201a" # Single low-9 quotation mark
U_SUQUO = "\u201b" # Single high-reversed-9 quotation mark
U_LDQUO = "\u201c" # Left double quotation mark
U_RDQUO = "\u201d" # Right double quotation mark
U_BDQUO = "\u201e" # Double low-9 quotation mark
U_UDQUO = "\u201f" # Double high-reversed-9 quotation mark
U_LSAQUO = "\u2039" # Single left-pointing angle quotation mark
U_RSAQUO = "\u203a" # Single right-pointing angle quotation mark
U_BDRQUO = "\u2e42" # Double low-reversed-9 quotation mark
U_LCQUO = "\u300c" # Left corner bracket
U_RCQUO = "\u300d" # Right corner bracket
U_LWCQUO = "\u300e" # Left white corner bracket
U_RWCQUO = "\u300f" # Right white corner bracket
# Punctuation
U_FGDASH = "\u2012" # Figure dash
U_ENDASH = "\u2013" # Short dash
U_EMDASH = "\u2014" # Long dash
U_HBAR = "\u2015" # Horizontal bar
U_HELLIP = "\u2026" # Ellipsis
U_MAPOS = "\u02bc" # Modifier letter single apostrophe
U_PRIME = "\u2032" # Prime
U_DPRIME = "\u2033" # Double prime
# Spaces and Lines
U_NBSP = "\u00a0" # Non-breaking space
U_THSP = "\u2009" # Thin space
U_THNBSP = "\u202f" # Thin non-breaking space
U_ENSP = "\u2002" # Short (en) space
U_EMSP = "\u2003" # Long (em) space
U_MMSP = "\u205f" # Medium mathematical space
U_LSEP = "\u2028" # Line separator
U_PSEP = "\u2029" # Paragraph separator
# Symbols
U_CHECK = "\u2714" # Heavy check mark
U_CROSS = "\u2715" # Heavy cross mark
U_BULL = "\u2022" # List bullet
U_TRBULL = "\u2023" # Triangle bullet
U_HYBULL = "\u2043" # Hyphen bullet
U_FLOWER = "\u2055" # Flower punctuation mark
U_PERMIL = "\u2030" # Per mille sign
U_DEGREE = "\u00b0" # Degree symbol
U_MINUS = "\u2212" # Minus sign
U_TIMES = "\u00d7" # Multiplication sign
U_DIVIDE = "\u00f7" # Division sign
# Special
U_RLM = "\u200f" # Right-to-left mark
U_UNKN = "\ufffd" # Unknown character
U_NAC1 = "\ufffe" # Not a character
U_NAC2 = "\uffff" # Not a character
# Placeholders
U_LBREAK = "\u21b2" # Downwards Arrow With Tip Leftwards
# HTML Equivalents
# ================
# Quotes
H_QUOT = "&quot;"
H_APOS = "&#39;"
H_LAQUO = "&laquo;"
H_RAQUO = "&raquo;"
H_LSQUO = "&lsquo;"
H_RSQUO = "&rsquo;"
H_SBQUO = "&sbquo;"
H_SUQUO = "&#8219;"
H_LDQUO = "&ldquo;"
H_RDQUO = "&rdquo;"
H_BDQUO = "&bdquo;"
H_UDQUO = "&#8223;"
H_LSAQUO = "&lsaquo;"
H_RSAQUO = "&rsaquo;"
H_BDRQUO = "&#11842;"
H_LCQUO = "&#12300;"
H_RCQUO = "&#12301;"
H_LWCQUO = "&#12302;"
H_RWCQUO = "&#12303;"
# Punctuation
H_FGDASH = "&#8210;"
H_ENDASH = "&ndash;"
H_EMDASH = "&mdash;"
H_HBAR = "&#8213;"
H_HELLIP = "&hellip;"
H_MAPOS = "&#700;"
H_PRIME = "&prime;"
H_DPRIME = "&#8243;"
# Spaces
H_NBSP = "&nbsp;"
H_THSP = "&thinsp;"
H_THNBSP = "&#8239;"
H_ENSP = "&ensp;"
H_EMSP = "&emsp;"
# Symbols
H_CHECK = "&#10004;"
H_CROSS = "&#10005;"
H_BULL = "&bull;"
H_TRBULL = "&#8227;"
H_HYBULL = "&hybull;"
H_FLOWER = "&#8277;"
H_PERMIL = "&#8240;"
H_DEGREE = "&deg;"
H_MINUS = "&minus;"
H_TIMES = "&times;"
H_DIVIDE = "&divide;"
# Unicode symbols expected to be used on the UI
UI_SYMBOLS: ClassVar[list[str]] = [
U_QUOT,
U_APOS,
U_LAQUO,
U_RAQUO,
U_LSQUO,
U_RSQUO,
U_SBQUO,
U_SUQUO,
U_LDQUO,
U_RDQUO,
U_BDQUO,
U_UDQUO,
U_LSAQUO,
U_RSAQUO,
U_BDRQUO,
U_LCQUO,
U_RCQUO,
U_LWCQUO,
U_RWCQUO,
U_FGDASH,
U_ENDASH,
U_EMDASH,
U_HBAR,
U_HELLIP,
U_MAPOS,
U_PRIME,
U_DPRIME,
U_NBSP,
U_THSP,
U_THNBSP,
U_ENSP,
U_EMSP,
U_MMSP,
U_CHECK,
U_CROSS,
U_BULL,
U_TRBULL,
U_HYBULL,
U_FLOWER,
U_PERMIL,
U_DEGREE,
U_MINUS,
U_TIMES,
U_DIVIDE,
U_LBREAK,
]
class nwHtmlUnicode:
"""Unicode to HTML Map."""
U_TO_H: ClassVar[dict[str, str]] = {
# Quotes
nwUnicode.U_QUOT: nwUnicode.H_QUOT,
nwUnicode.U_APOS: nwUnicode.H_APOS,
nwUnicode.U_LAQUO: nwUnicode.H_LAQUO,
nwUnicode.U_RAQUO: nwUnicode.H_RAQUO,
nwUnicode.U_LSQUO: nwUnicode.H_LSQUO,
nwUnicode.U_RSQUO: nwUnicode.H_RSQUO,
nwUnicode.U_SBQUO: nwUnicode.H_SBQUO,
nwUnicode.U_SUQUO: nwUnicode.H_SUQUO,
nwUnicode.U_LDQUO: nwUnicode.H_LDQUO,
nwUnicode.U_RDQUO: nwUnicode.H_RDQUO,
nwUnicode.U_BDQUO: nwUnicode.H_BDQUO,
nwUnicode.U_UDQUO: nwUnicode.H_UDQUO,
nwUnicode.U_LSAQUO: nwUnicode.H_LSAQUO,
nwUnicode.U_RSAQUO: nwUnicode.H_RSAQUO,
nwUnicode.U_BDRQUO: nwUnicode.H_BDRQUO,
nwUnicode.U_LCQUO: nwUnicode.H_LCQUO,
nwUnicode.U_RCQUO: nwUnicode.H_RCQUO,
nwUnicode.U_LWCQUO: nwUnicode.H_LWCQUO,
nwUnicode.U_RWCQUO: nwUnicode.H_RWCQUO,
# Punctuation
nwUnicode.U_FGDASH: nwUnicode.H_FGDASH,
nwUnicode.U_ENDASH: nwUnicode.H_ENDASH,
nwUnicode.U_EMDASH: nwUnicode.H_EMDASH,
nwUnicode.U_HBAR: nwUnicode.H_HBAR,
nwUnicode.U_HELLIP: nwUnicode.H_HELLIP,
nwUnicode.U_MAPOS: nwUnicode.H_MAPOS,
nwUnicode.U_PRIME: nwUnicode.H_PRIME,
nwUnicode.U_DPRIME: nwUnicode.H_DPRIME,
# Spaces
nwUnicode.U_NBSP: nwUnicode.H_NBSP,
nwUnicode.U_THSP: nwUnicode.H_THSP,
nwUnicode.U_THNBSP: nwUnicode.H_THNBSP,
nwUnicode.U_ENSP: nwUnicode.H_ENSP,
nwUnicode.U_EMSP: nwUnicode.H_EMSP,
# Symbols
nwUnicode.U_CHECK: nwUnicode.H_CHECK,
nwUnicode.U_CROSS: nwUnicode.H_CROSS,
nwUnicode.U_BULL: nwUnicode.H_BULL,
nwUnicode.U_TRBULL: nwUnicode.H_TRBULL,
nwUnicode.U_HYBULL: nwUnicode.H_HYBULL,
nwUnicode.U_FLOWER: nwUnicode.H_FLOWER,
nwUnicode.U_PERMIL: nwUnicode.H_PERMIL,
nwUnicode.U_DEGREE: nwUnicode.H_DEGREE,
nwUnicode.U_MINUS: nwUnicode.H_MINUS,
nwUnicode.U_TIMES: nwUnicode.H_TIMES,
nwUnicode.U_DIVIDE: nwUnicode.H_DIVIDE,
}