1# -*- coding: utf-8 -*- 2 3# Copyright 2021 The Pigweed Authors 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# https://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16"""Functions to create checkboxes for menus and toolbars.""" 17 18import sys 19from typing import Callable, Iterable, Optional, NamedTuple 20 21from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple 22from prompt_toolkit.formatted_text import StyleAndTextTuples 23 24_KEY_SEPARATOR = ' ' 25_CHECKED_BOX = '[✓]' 26 27if sys.platform in ['win32']: 28 _CHECKED_BOX = '[x]' 29 30 31class ToolbarButton(NamedTuple): 32 key: Optional[str] = None 33 description: Optional[str] = 'Button' 34 mouse_handler: Optional[Callable] = None 35 is_checkbox: bool = False 36 checked: Optional[Callable] = None 37 38 39def to_checkbox( 40 checked: bool, 41 mouse_handler: Optional[Callable] = None, 42 end: str = ' ', 43 unchecked_style: str = 'class:checkbox', 44 checked_style: str = 'class:checkbox-checked', 45) -> OneStyleAndTextTuple: 46 text = _CHECKED_BOX if checked else '[ ]' 47 text += end 48 style = checked_style if checked else unchecked_style 49 if mouse_handler: 50 return (style, text, mouse_handler) 51 return (style, text) 52 53 54def to_checkbox_text(checked: bool, end=' '): 55 return to_checkbox(checked, end=end)[1] 56 57 58def to_setting( 59 checked: bool, 60 text: str, 61 active_style='class:toolbar-setting-active', 62 inactive_style='', 63 mouse_handler=None, 64): 65 """Apply a style to text if checked is True.""" 66 style = active_style if checked else inactive_style 67 if mouse_handler: 68 return (style, text, mouse_handler) 69 return (style, text) 70 71 72def to_checkbox_with_keybind_indicator( 73 checked: bool, 74 key: str, 75 description: str, 76 mouse_handler=None, 77 base_style: str = '', 78 **checkbox_kwargs, 79): 80 """Create a clickable keybind indicator with checkbox for toolbars.""" 81 if mouse_handler: 82 return to_keybind_indicator(key, 83 description, 84 mouse_handler, 85 leading_fragments=[ 86 to_checkbox(checked, mouse_handler, 87 **checkbox_kwargs) 88 ], 89 base_style=base_style) 90 return to_keybind_indicator( 91 key, 92 description, 93 leading_fragments=[to_checkbox(checked, **checkbox_kwargs)], 94 base_style=base_style) 95 96 97def to_keybind_indicator( 98 key: str, 99 description: str, 100 mouse_handler: Optional[Callable] = None, 101 leading_fragments: Optional[Iterable] = None, 102 middle_fragments: Optional[Iterable] = None, 103 base_style: str = '', 104 key_style: str = 'class:keybind', 105 description_style: str = 'class:keyhelp', 106): 107 """Create a clickable keybind indicator for toolbars.""" 108 if base_style: 109 base_style += ' ' 110 111 fragments: StyleAndTextTuples = [] 112 fragments.append((base_style + 'class:toolbar-button-decoration', ' ')) 113 114 def append_fragment_with_base_style(frag_list, fragment) -> None: 115 if mouse_handler: 116 frag_list.append( 117 (base_style + fragment[0], fragment[1], mouse_handler)) 118 else: 119 frag_list.append((base_style + fragment[0], fragment[1])) 120 121 # Add any starting fragments first 122 if leading_fragments: 123 for fragment in leading_fragments: 124 append_fragment_with_base_style(fragments, fragment) 125 126 # Function name 127 if mouse_handler: 128 fragments.append( 129 (base_style + description_style, description, mouse_handler)) 130 else: 131 fragments.append((base_style + description_style, description)) 132 133 if middle_fragments: 134 for fragment in middle_fragments: 135 append_fragment_with_base_style(fragments, fragment) 136 137 # Separator and keybind 138 if key: 139 if mouse_handler: 140 fragments.append((base_style + description_style, _KEY_SEPARATOR, 141 mouse_handler)) 142 fragments.append((base_style + key_style, key, mouse_handler)) 143 else: 144 fragments.append((base_style + description_style, _KEY_SEPARATOR)) 145 fragments.append((base_style + key_style, key)) 146 147 fragments.append((base_style + 'class:toolbar-button-decoration', ' ')) 148 return fragments 149