blob: d251ec9f02bfc5fcb55c723cc776fb7cb4fa57e6 [file] [log] [blame]
# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Functions to create checkboxes for menus and toolbars."""
import sys
from typing import Callable, Iterable, Optional, NamedTuple
from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple
from prompt_toolkit.formatted_text import StyleAndTextTuples
_KEY_SEPARATOR = ' '
_CHECKED_BOX = '[✓]'
if sys.platform in ['win32']:
_CHECKED_BOX = '[x]'
class ToolbarButton(NamedTuple):
key: Optional[str] = None
description: Optional[str] = 'Button'
mouse_handler: Optional[Callable] = None
is_checkbox: bool = False
checked: Optional[Callable] = None
def to_checkbox(
checked: bool,
mouse_handler: Optional[Callable] = None,
end: str = ' ',
unchecked_style: str = 'class:checkbox',
checked_style: str = 'class:checkbox-checked',
) -> OneStyleAndTextTuple:
text = _CHECKED_BOX if checked else '[ ]'
text += end
style = checked_style if checked else unchecked_style
if mouse_handler:
return (style, text, mouse_handler)
return (style, text)
def to_checkbox_text(checked: bool, end=' '):
return to_checkbox(checked, end=end)[1]
def to_setting(
checked: bool,
text: str,
active_style='class:toolbar-setting-active',
inactive_style='',
mouse_handler=None,
):
"""Apply a style to text if checked is True."""
style = active_style if checked else inactive_style
if mouse_handler:
return (style, text, mouse_handler)
return (style, text)
def to_checkbox_with_keybind_indicator(
checked: bool,
key: str,
description: str,
mouse_handler=None,
base_style: str = '',
**checkbox_kwargs,
):
"""Create a clickable keybind indicator with checkbox for toolbars."""
if mouse_handler:
return to_keybind_indicator(key,
description,
mouse_handler,
leading_fragments=[
to_checkbox(checked, mouse_handler,
**checkbox_kwargs)
],
base_style=base_style)
return to_keybind_indicator(
key,
description,
leading_fragments=[to_checkbox(checked, **checkbox_kwargs)],
base_style=base_style)
def to_keybind_indicator(
key: str,
description: str,
mouse_handler: Optional[Callable] = None,
leading_fragments: Optional[Iterable] = None,
middle_fragments: Optional[Iterable] = None,
base_style: str = '',
key_style: str = 'class:keybind',
description_style: str = 'class:keyhelp',
):
"""Create a clickable keybind indicator for toolbars."""
if base_style:
base_style += ' '
fragments: StyleAndTextTuples = []
fragments.append((base_style + 'class:toolbar-button-decoration', ' '))
def append_fragment_with_base_style(frag_list, fragment) -> None:
if mouse_handler:
frag_list.append(
(base_style + fragment[0], fragment[1], mouse_handler))
else:
frag_list.append((base_style + fragment[0], fragment[1]))
# Add any starting fragments first
if leading_fragments:
for fragment in leading_fragments:
append_fragment_with_base_style(fragments, fragment)
# Function name
if mouse_handler:
fragments.append(
(base_style + description_style, description, mouse_handler))
else:
fragments.append((base_style + description_style, description))
if middle_fragments:
for fragment in middle_fragments:
append_fragment_with_base_style(fragments, fragment)
# Separator and keybind
if key:
if mouse_handler:
fragments.append((base_style + description_style, _KEY_SEPARATOR,
mouse_handler))
fragments.append((base_style + key_style, key, mouse_handler))
else:
fragments.append((base_style + description_style, _KEY_SEPARATOR))
fragments.append((base_style + key_style, key))
fragments.append((base_style + 'class:toolbar-button-decoration', ' '))
return fragments