diff --git a/PySimpleGUIQt/PySimpleGUIQt.py b/PySimpleGUIQt/PySimpleGUIQt.py index 3015bdd6..63fa020c 100644 --- a/PySimpleGUIQt/PySimpleGUIQt.py +++ b/PySimpleGUIQt/PySimpleGUIQt.py @@ -1,14 +1,18 @@ #!/usr/bin/python3 -version = __version__ = "0.35.0.12 Unreleased\nMassive update of docstrings (thanks nngogol), default for slider tick interval set automatically now, margins added to Window but not yet hooked up, VSeparator added (spelling error), added Radio.reset_group and removed clearing all when one of them is cleared (recent change), added default key for one_line_progress_meter, auto-add keys to tables & trees, InputText element gets new disabled-readonly foreground and background color settings and also a readonly parameter, InputText gets border_width parameter, fixed up some docstrings, popup gets new image and any_key_closes parms, input type popups also get image parameter, error checks for trying to manipulate a window prior to finalize, added a dummy Element.expand method, added theme_add_new, added Window.set_title" +version = __version__ = "0.35.0.15 Unreleased\nMassive update of docstrings (thanks nngogol), default for slider tick interval set automatically now, margins added to Window but not yet hooked up, VSeparator added (spelling error), added Radio.reset_group and removed clearing all when one of them is cleared (recent change), added default key for one_line_progress_meter, auto-add keys to tables & trees, InputText element gets new disabled-readonly foreground and background color settings and also a readonly parameter, InputText gets border_width parameter, fixed up some docstrings, popup gets new image and any_key_closes parms, input type popups also get image parameter, error checks for trying to manipulate a window prior to finalize, added a dummy Element.expand method, added theme_add_new, added Window.set_title, updated to the latest themes from tktiner port, big styles update (thanks nngogol!), more Styles work, changed popup text layout to match tkinter port" + +__version__ = version.split()[0] # For PEP 396 and PEP 345 + +# The shortened version of version +try: + ver = version.split(' ')[0] +except: + ver = '' + port = 'PySimpleGUIQt' -import sys -import datetime -import textwrap -import pickle -import random -import warnings +import sys, datetime, textwrap, pickle, random, warnings, time try: # Because Raspberry Pi is still on 3.4....it's not critical if this module isn't imported on the Pi from typing import List, Any, Union, Tuple, Dict # because this code has to run on 2.7 can't use real type hints. Must do typing only in comments except: @@ -53,7 +57,6 @@ g_time_start = 0 g_time_end = 0 g_time_delta = 0 -import time def TimerStart(): @@ -129,6 +132,7 @@ OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR = ('white', BLUES[0]) # Colors should never b CURRENT_LOOK_AND_FEEL = 'DarkBlue3' +# CURRENT_LOOK_AND_FEEL = 'DarkRed' DEFAULT_ERROR_BUTTON_COLOR = ("#FFFFFF", "#FF0000") DEFAULT_BACKGROUND_COLOR = None @@ -306,6 +310,8 @@ POPUP_BUTTONS_OK_CANCEL = 4 POPUP_BUTTONS_OK = 0 POPUP_BUTTONS_NO_BUTTONS = 5 +# def apply_new_font(css_dict, font_string): +# return css_dict.update({k.strip().replace('_', '-') : v.strip() for k,v in font_string.replace('\n', '').split(';')}) # ---------------------------------------------------------------------- # # Cascading structure.... Objects get larger # @@ -437,21 +443,20 @@ class Element(): def Update(self, widget, background_color=None, text_color=None, font=None, visible=None): if not self._widget_was_created(): return - style = str(widget.styleSheet()) - add_brace = False - if len(style) != 0 and style[-1] == '}': - style = style[:-1] - add_brace = True - if font is not None: - style += create_style_from_font(font) + + a_style = self.css_style_obj[0] + # print(f'a_style = {a_style}') + if font is not None: #= apply_new_font(css_props_dict, create_style_from_font(font)) + a_style['font'] = create_style_from_font(font) if text_color is not None: - style += ' color: %s;' % text_color + a_style['color'] = text_color self.TextColor = text_color if background_color is not None: - style += 'background-color: %s;' % background_color - if add_brace: - style += '}' - widget.setStyleSheet(style) + a_style['background-color'] = background_color + self.BackgroundColor = background_color + + # print(f'a_style = {a_style}') + widget.setStyleSheet(a_style.build_css_string()) set_widget_visiblity(widget, visible) @@ -941,6 +946,9 @@ class Listbox(Element): update = Update +LBox = Listbox +LB = Listbox + # ---------------------------------------------------------------------- # # Radio # # ---------------------------------------------------------------------- # @@ -1031,6 +1039,9 @@ class Radio(Element): update = Update +R = Radio +Rad = Radio + # ---------------------------------------------------------------------- # # Checkbox # # ---------------------------------------------------------------------- # @@ -3225,6 +3236,8 @@ class Menu(Element): """ key = key if key is not None else k self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR + self.MenuItemTextColor = theme_text_color() + self.MenuItemBackgroundColor = theme_background_color() self.MenuDefinition = menu_definition self.TKMenu = None self.Tearoff = tearoff @@ -3344,8 +3357,8 @@ class Table(Element): self.AutoSizeColumns = auto_size_columns self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color - self.HeaderTextColor = header_text_color if header_text_color is not None else LOOK_AND_FEEL_TABLE[CURRENT_LOOK_AND_FEEL]['TEXT_INPUT'] - self.HeaderBackgroundColor = header_background_color if header_background_color is not None else LOOK_AND_FEEL_TABLE[CURRENT_LOOK_AND_FEEL]['INPUT'] + self.HeaderTextColor = header_text_color if header_text_color is not None else theme_input_text_color() + self.HeaderBackgroundColor = header_background_color if header_background_color is not None else theme_input_background_color() self.HeaderFont = header_font self.Justification = justification self.InitialState = None @@ -3471,7 +3484,7 @@ class Tree(Element): def __init__(self, data=None, headings=None, visible_column_map=None, col_widths=None, col0_width=10, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, show_expanded=False, change_submits=False, enable_events=False, font=None, size=(200,600), - justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None, k=None, + justification='right', header_text_color=None, header_background_color=None, header_font=None, text_color=None, background_color=None, num_rows=None, pad=None, key=None, k=None, tooltip=None, visible=True, size_px=(None,None), metadata=None): """ :param data: The data represented using a PySimpleGUI provided TreeData class @@ -3504,6 +3517,12 @@ class Tree(Element): :type size: ??? :param justification: 'left', 'right', 'center' are valid choices :type justification: (str) + :param header_text_color: sets the text color for the header + :type header_text_color: (str) + :param header_background_color: sets the background color for the header + :type header_background_color: (str) + :param header_font: specifies the font family, size, etc + :type header_font: Union[str, Tuple[str, int]] :param text_color: color of the text :type text_color: (str) :param background_color: color of background @@ -3535,6 +3554,9 @@ class Tree(Element): self.AutoSizeColumns = auto_size_columns self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color + self.HeaderTextColor = header_text_color if header_text_color is not None else theme_input_text_color() + self.HeaderBackgroundColor = header_background_color if header_background_color is not None else theme_input_background_color() + self.HeaderFont = header_font self.Justification = justification self.InitialState = None self.SelectMode = select_mode @@ -4089,7 +4111,7 @@ class Window: CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row - if type(element) == list: + if type(element) is list: PopupError('Error creating layout', 'Layout has a LIST instead of an ELEMENT', 'This means you have a badly placed ]', @@ -4851,31 +4873,37 @@ def convert_tkinter_filetypes_to_qt(filetypes): # =========================================================================== # def create_style_from_font(font): """ - Convert from font string/tyuple into a Qt style sheet string + Convert from font string/tuple into a Qt style sheet string :param font: "Arial 10 Bold" or ('Arial', 10, 'Bold) :return: style string that can be combined with other style strings """ - if font is None: - return '' + if font is None: return '' + _font = font.split(' ') if type(font) is str else font - if type(font) is str: - _font = font.split(' ') - else: - _font = font - - style = '' - style += 'font-family: %s;\n' % _font[0] - style += 'font-size: %spt;\n' % _font[1] - font_items = '' - for item in _font[2:]: - if item == 'underline': - style += 'text-decoration: underline;\n' + # parsing name + size + font_name, font_size = _font[:2] + # parsing options: + is_bold, is_underline = False, False + if len(_font) > 2: + options = _font[2:] + for some_option in options: + if some_option == 'underline': + is_underline = True else: - font_items += item + ' ' - if font_items != '': - style += 'font: %s;\n' % (font_items) - return style + is_bold = True + + # build + is_bold_text = 'font-weight : bold;' if is_bold else '' + is_underline_text = 'text-decoration: underline;' if is_underline else '' + + return textwrap.dedent(f''' + {is_underline_text} + {is_bold_text} + font-family: "{font_name}"; + font-size: {font_size}pt; + '''.strip()).replace('\n', '') + def set_widget_visiblity(widget, visible): if visible is False: @@ -5646,7 +5674,7 @@ def AddTrayMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=Fa while i < (len(sub_menu_info)): item = sub_menu_info[i] if i != len(sub_menu_info) - 1: - if type(sub_menu_info[i + 1]) == list: + if type(sub_menu_info[i + 1]) is list: new_menu = QMenu(top_menu) item = sub_menu_info[i] try: @@ -5696,8 +5724,22 @@ def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False) while i < (len(sub_menu_info)): item = sub_menu_info[i] if i != len(sub_menu_info) - 1: - if type(sub_menu_info[i + 1]) == list: + if type(sub_menu_info[i + 1]) is list: new_menu = QMenu(top_menu) + # + # # === style === + # menu_style = _Style('QMenu') + # menu_style['font'] = create_style_from_font(element.Font) + # if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: + # menu_style['color'] = element.TextColor + # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + # menu_style['background-color'] = element.BackgroundColor + # # style['margin'] = full_element_pad + # new_menu.setStyleSheet(menu_style.build_css_string()) + # print(menu_style) + # # element.css_style_obj = (style,) + # # === style === end + # # Key handling.... strip off key before setting text item = sub_menu_info[i] try: @@ -5763,44 +5805,148 @@ Q:::::::QQ::::::::Q t::::::tttt:::::t # ===================================== Qt CODE STARTS HERE ====================================================== # # ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # -def style_entry(**kwargs): - generated_style = '' - for Qt_property, value in kwargs.items(): - generated_style += "\t{} : {};\n".format(Qt_property.replace('_','-'), value) - - # generated_style += "}" - return generated_style - -def style_generate(qt_element_type, entries): - generated_style = qt_element_type + " {\n" - generated_style += entries - generated_style += "}" - return generated_style +# to_css_prop(css_prop.replace('_','-'), value) +def _to_css_prop(key_, val_): + return "{}:{}; ".format(key_.replace('_', '-'), val_) +# def style_generate(qt_element_type, css_props_str): +# return '%s {\n %s \n}' % (qt_element_type, css_props_str) +_valid_css_fields = ['align-content', 'align-items', 'align-self', 'background', 'background-attachment', 'background-color', 'background-image', 'background-position', 'background-size', 'border', 'border-collapse', 'border-image', 'border-radius', 'border-spacing', 'bottom', 'box-decoration-break', 'caret-color', 'clear', 'clip-path', 'color', 'color-adjust', 'column-count', 'column-fill', 'column-gap', 'column-rule', 'column-rule-color', 'column-rule-style', 'column-rule-width', 'column-span', 'column-width', 'columns', 'contain', 'content', 'counter-increment', 'counter-reset', 'counter-set', 'cursor', 'direction', 'display', 'empty-cells', 'fill', 'filter', 'flex', 'flex-basis', 'flex-direction', 'flex-flow', 'flex-grow', 'flex-shrink', 'flex-wrap', 'float', 'font', 'font-display', 'font-family', 'font-feature-settings', 'font-kerning', 'font-optical-sizing', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-synthesis', 'font-variant', 'font-variant-numeric', 'font-weight', 'gap', 'grid-column', 'grid-row', 'grid-template-columns', 'grid-template-rows', 'hanging-punctuation', 'height', 'hyphens', 'image-rendering', 'initial-letter', 'inline-size', 'inset', 'inset-block', 'inset-block-end', 'inset-block-start', 'inset-inline', 'inset-inline-end', 'inset-inline-start', 'isolation', 'justify-content', 'left', 'letter-spacing', 'line-clamp', 'line-height', 'list-style', 'margin', 'mask-image', 'mask-position', 'mask-repeat', 'mask-size', 'max-height', 'max-width', 'min-height', 'min-width', 'mix-blend-mode', 'object-fit', 'object-position', 'offset-anchor', 'offset-distance', 'offset-path', 'offset-rotate', 'opacity', 'order', 'orphans', 'outline', 'outline-offset', 'overflow', 'overflow-anchor', 'overflow-wrap', 'overscroll-behavior', 'padding', 'page-break', 'paint-order', 'perspective', 'perspective-origin', 'place-items', 'pointer-events', 'position', 'quotes', 'resize', 'right', 'row-gap', 'scroll-behavior', 'scroll-margin', 'scroll-padding', 'scroll-snap-align', 'scroll-snap-stop', 'scroll-snap-type', 'scrollbar', 'scrollbar-color', 'scrollbar-gutter', 'scrollbar-width', 'shape-image-threshold', 'shape-margin', 'shape-outside', 'speak', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-width', 'tab-size', 'table-layout', 'text-align', 'text-align-last', 'text-decoration', 'text-decoration-color', 'text-decoration-line', 'text-decoration-skip', 'text-decoration-skip-ink', 'text-decoration-style', 'text-decoration-thickness', 'text-indent', 'text-justify', 'text-overflow', 'text-rendering', 'text-shadow', 'text-stroke', 'text-transform', 'text-underline-offset', 'text-underline-position', 'top', 'touch-action', 'transform', 'transform-origin', 'transform-style', 'transition', 'transition-delay', 'transition-duration', 'transition-property', 'transition-timing-function', 'unicode-bidi', 'unicode-range', 'user-select', 'vertical-align', 'visibility', 'white-space', 'widows', 'width', 'will-change', 'word-break', 'word-spacing', 'writing-mode', 'z-index', 'zoom'] +def is_valid_css_prop(a_css_prop): + '''Check if a given property EXISTS in qt Spec''' + global _valid_css_fields + norm_ = a_css_prop.replace('_', '-') + return norm_ in _valid_css_fields -class Style(object): - def __init__(self, id, **kwargs): - self.content = id + " {\n}" - self.add(**kwargs) +class _Style(object): + ''' + API - def add(self, **kwargs): - self.content = self.content[:-1] - for key, value in kwargs.items(): + # step 1 - make a style + ss = Style(QLabel) + + # step 2 - add fields + ss['font'] = create_style_from_font() + ss['background_color'] = (color, color_default) + ss['color'] = (color, color_default) + # step 2.1 - add additions + ss.append_css_to_end.append(" QScrollBar:vertical { ... some css here ... } ") + # step 2.2 - add anchor + ss.my_anchor = '::chunk' + + # step 3 - build result + css_str = ss.build_css_string() + qt_widget.setStyleSheet(css_str) + + ====== Special fields + - font + - margin + Why they are special? Because of the formatting. + + === === === + made by nngogol + ''' + + def __init__(self, widget_name=''): + self.widget_name = widget_name + self.css_props = {} + self.my_anchor = None + + self.logging = True + self.logging = not True + self.append_css_to_end = [] + + self.make_secure_check = True # Check if "css property is valid, i.e. it's present in default names". + # Make makes development safer, if you have a erro in spelling css-property + # In production: it can be disabled, I guess. + + def __setitem__(self, css_prop_name, css_prop_value): + + # validation + if not isinstance(css_prop_value, (tuple, list, str)): + raise Exception('Bad value fro css property -> %s.' % css_prop_value) + if self.make_secure_check: + if not is_valid_css_prop(css_prop_name): + raise Exception('Bad css property name: ' % css_prop_name) + + self.css_props[css_prop_name] = css_prop_value + + def build_css_string(self): + # no css props added -> return empty string + if not self.css_props: # empty case + print(f' final_str # {self.widget_name} = ""') + return '' + + css_props_str_list = [] + for key, value in self.css_props.items(): + # special cases: + if key == 'margin': + # validation + if not isinstance(value, (tuple, list)): + raise Exception('Cant handle this TYPE for margin property : %s ' % str(type(value))) + + result_css_string = '' + + if len(value) == 4: + # skip all zeros + if value[0] == value[1] == value[2] == value[3] == 0: result_css_string = '' + + result_css_string = 'margin : {}px {}px {}px {}px;'.format(*value) + elif len(value) == 1: + # skip all zeros + if value[0] == 0: continue + + result_css_string = 'margin : {}px;'.format(value[0]) + else: + raise Exception('Bad value for margin property: ' % str(value)) + + # # Fix for this case: + # # Wrong: margin: 0px; + # # Right: margin: 0; + # result_css_string = result_css_string.replace(': 0px', ': 0') + + css_props_str_list.append(result_css_string) + + continue + # if key == 'border': ... + + # it's a css string! Format: 'propery: value;'' + if isinstance(value, str): + # is css prop name + css prop value + if ':' in value: + css_props_str_list.append(value) + # is css value + else: + css_props_str_list.append(_to_css_prop(key, value)) + # we continue, because it was 'string type parsing' + continue + + isnot = None + # it's a pair! Format: (val, default_val) if isinstance(value, (tuple, list)): - value, isnot = value - else: - isnot = None - if value is not None and value != isnot: - self.content += "\t{} : {};\n".format(key.replace("_", "-"), value) - self.content += "}" + user_css_prop_value, isnot = value - def append(self, value): - self.content = self.content[:-1] + value + "\n}" + if user_css_prop_value is not None and user_css_prop_value != isnot: + css_props_str_list.append(_to_css_prop(key, user_css_prop_value)) + + # join all props + css_all = ''.join(css_props_str_list) + final_str = css_all + if self.widget_name: + my_anchor = '' if self.my_anchor is None else self.my_anchor + final_str = '%s%s { %s }' % (self.widget_name, my_anchor, css_all) + + # if needed: append some css from self.append_css_to_end + final_str += ' '.join(self.append_css_to_end) + + if self.logging: print(f'final css string (self.widget_name): {final_str}') + return final_str def __repr__(self): - return self.content + return self.build_css_string() +align2qt_align = {'c' : Qt.AlignCenter, 'l' : Qt.AlignLeft, 'r' : Qt.AlignRight} def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): """ :param form: a window class @@ -5810,6 +5956,7 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): :param toplevel_form: ??? :type toplevel_form: (Window) """ + # align2qt_align border_depth = toplevel_win.BorderDepth if toplevel_win.BorderDepth is not None else DEFAULT_BORDER_WIDTH # --------------------------------------------------------------------------- # @@ -5824,12 +5971,10 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): # *********** ------- Loop through ELEMENTS ------- ***********# # *********** Make TK Row ***********# qt_row_layout = QHBoxLayout() - if container_elem.ElementJustification.startswith('c'): - qt_row_layout.setAlignment(Qt.AlignCenter) - elif container_elem.ElementJustification.startswith('r'): - qt_row_layout.setAlignment(Qt.AlignRight) - elif container_elem.ElementJustification.startswith('l'): - qt_row_layout.setAlignment(Qt.AlignLeft) + elem_align = container_elem.ElementJustification[0] + + if elem_align in align2qt_align: + qt_row_layout.setAlignment(align2qt_align[elem_align]) for col_num, element in enumerate(flex_row): element.ParentForm = toplevel_win # save the button's parent form object element.row_frame = qt_row_layout @@ -5860,11 +6005,12 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): auto_size_text = False # if user has specified a size then it shouldn't autosize full_element_pad = [0,0,0,0] # Top, Right, Bottom, Left elementpad = element.Pad if element.Pad is not None else toplevel_win.ElementPadding - if type(elementpad[0]) != tuple: # left and right + if type(elementpad[0]) is not tuple: # left and right full_element_pad[1] = full_element_pad[3] = elementpad[0] else: full_element_pad[3], full_element_pad[1] = elementpad[0] - if type(elementpad[1]) != tuple: # top and bottom + + if type(elementpad[1]) is not tuple: # top and bottom full_element_pad[0] = full_element_pad[2] = elementpad[1] else: full_element_pad[0], full_element_pad[2] = elementpad[1] @@ -5883,18 +6029,16 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): column_widget = QGroupBox() element.Widget = element.QT_QGroupBox = column_widget # column_widget.setFrameShape(QtWidgets.QFrame.NoFrame) - style = create_style_from_font(font) - if element.BackgroundColor is not None: - style = style_entry(background_color=element.BackgroundColor) - # style += 'background-color: %s;' % element.BackgroundColor - style += style_entry(border='0px solid gray') - # style += style_entry(margin='{}px {}px {}px {}px'.format(*full_element_pad)) - # style += style_entry(margin='0px 0px 0px 0px') - # style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - # style += 'border: 0px solid gray; ' - style = style_generate('QGroupBox', style) - column_widget.setStyleSheet(style) + # === style === + style = _Style('QGroupBox') + style['font'] = create_style_from_font(font) + if element.BackgroundColor is not None: + style['background_color'] = element.BackgroundColor + style['border'] = '0px solid gray' # FIXv2 + column_widget.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end column_layout = QFormLayout() element.vbox_layout = column_vbox = QVBoxLayout() @@ -5917,10 +6061,7 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): if not element.Visible: column_widget.setVisible(False) - if scroll: - qt_row_layout.addWidget(scroll) - else: - qt_row_layout.addWidget(column_widget) + qt_row_layout.addWidget(scroll if scroll else column_widget) # ------------------------- TEXT placement element ------------------------- # elif element_type == ELEM_TYPE_TEXT: element.Widget = element.QT_Label = qlabel = QLabel(element.DisplayText, toplevel_win.QTWindow) @@ -5930,24 +6071,24 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): justification = toplevel_win.TextJustification else: justification = DEFAULT_TEXT_JUSTIFICATION - if justification[0] == 'c': - element.QT_Label.setAlignment(Qt.AlignCenter) - elif justification[0] == 'r': - element.QT_Label.setAlignment(Qt.AlignRight) + + if justification[0] in align2qt_align: + element.QT_Label.setAlignment(align2qt_align[justification[0]]) if not auto_size_text: if element_size[0] is not None: element.QT_Label.setFixedWidth(element_size[0]) if element_size[1] is not None: element.QT_Label.setFixedHeight(element_size[1]) # element.QT_Label.setWordWrap(True) - style = Style('QLabel') - style.append(create_style_from_font(font)) - style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) - style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) - element.QT_Label.setStyleSheet(style.content) - if element.ClickSubmits: - element.QT_Label.mousePressEvent = element._QtCallbackTextClicked + # === style === + style = _Style('QLabel') + style['font'] = create_style_from_font(font) + style['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) + element.QT_Label.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end if element.Relief is not None: if element.Relief in (RELIEF_RIDGE, RELIEF_RAISED): @@ -5960,8 +6101,8 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): if element.Margins is not None: m = element.Margins qlabel.setContentsMargins(m[0], m[2], m[1], m[3]) # L T B R - if element.Tooltip: - element.QT_Label.setToolTip(element.Tooltip) + if element.Tooltip: element.QT_Label.setToolTip(element.Tooltip) + if element.ClickSubmits: element.QT_Label.mousePressEvent = element._QtCallbackTextClicked if not element.Visible: element.QT_Label.setVisible(False) qt_row_layout.addWidget(element.QT_Label) @@ -5971,15 +6112,19 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): btext = element.ButtonText btype = element.BType element.Widget = element.QT_QPushButton = QPushButton(btext) - style = Style('QPushButton') - style.append(create_style_from_font(font)) - style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) - style.add(background_color=(element.BackgroundColor)) + # === style === + style = _Style('QPushButton') + style['font'] = create_style_from_font(font) + style['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) + style['background_color'] = (element.BackgroundColor) if element.BorderWidth == 0: - style.add(border='none') - style.add(margin='{}px {}px {}px {}px'.format(*full_element_pad)) - # style.add(border='{}px solid gray '.format(border_depth)) - element.QT_QPushButton.setStyleSheet(style.content) + style['border'] = 'none' + style['margin'] = full_element_pad + # style['border'] = '{}px solid gray '.format(border_depth) + element.QT_QPushButton.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + # element.QT_QPushButton.setFlat(False) if (element.AutoSizeButton is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None) and element.ImageData is None: if element_size[0] is not None: @@ -5987,27 +6132,12 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): if element_size[1] is not None: element.QT_QPushButton.setFixedHeight(element_size[1]) - # - # elif element.Data is not None: - # qlabel.setText('') - # ba = QtCore.QByteArray.fromRawData(element.Data) - # pixmap = QtGui.QPixmap() - # pixmap.loadFromData(ba) - # qlabel.setPixmap(pixmap) - # elif element.DataBase64: - # qlabel.setText('') - # ba = QtCore.QByteArray.fromBase64(element.DataBase64) - # pixmap = QtGui.QPixmap() - # pixmap.loadFromData(ba) - # qlabel.setPixmap(pixmap) - if element.ImageFilename is not None: element.QT_QPushButton.setIcon(QtGui.QPixmap(element.ImageFilename)) element.QT_QPushButton.setIconSize(QtGui.QPixmap(element.ImageFilename).rect().size()) if element.ImageData: ba = QtCore.QByteArray.fromBase64(element.ImageData) - pixmap = QtGui.QPixmap() - pixmap.loadFromData(ba) + pixmap = QtGui.QPixmap(); pixmap.loadFromData(ba) element.QT_QPushButton.setIcon(pixmap) element.QT_QPushButton.setIconSize(pixmap.rect().size()) @@ -6031,29 +6161,30 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): qlineedit.dragEnterEvent = element._dragEnterEvent qlineedit.dropEvent = element._dropEvent - if element.Justification[0] == 'c': - element.QT_QLineEdit.setAlignment(Qt.AlignCenter) - elif element.Justification[0] == 'r': - element.QT_QLineEdit.setAlignment(Qt.AlignRight) + if element.Justification[0] in align2qt_align: + element.QT_QLineEdit.setAlignment(align2qt_align[element.Justification[0]]) element.QT_QLineEdit.setText(str(default_text)) - style = Style('QLineEdit') - style.append(create_style_from_font(font)) + # === style === + style = _Style('QLineEdit') + style['font'] = create_style_from_font(font) if element.Disabled or element.ReadOnly: if element.disabled_readonly_background_color: - style.add(background_color=(element.disabled_readonly_background_color, COLOR_SYSTEM_DEFAULT)) + style['background_color'] = (element.disabled_readonly_background_color, COLOR_SYSTEM_DEFAULT) else: - style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) if element.disabled_readonly_text_color: - style.add(color=(element.disabled_readonly_text_color, COLOR_SYSTEM_DEFAULT)) + style['color'] = (element.disabled_readonly_text_color, COLOR_SYSTEM_DEFAULT) else: - style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) + style['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) else: - style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) - style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) - style.add(margin='{}px {}px {}px {}px'.format(*full_element_pad)) - style.add(border='{}px solid gray '.format(border_depth)) - element.QT_QLineEdit.setStyleSheet(style.content) + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) + style['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) + style['margin'] = full_element_pad + style['border'] = '{}px solid gray '.format(border_depth) + element.QT_QLineEdit.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end if element.AutoSizeText is False or toplevel_win.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6095,16 +6226,19 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): else: width = max_line_len - style = Style('QComboBox') - style.append(create_style_from_font(font)) - style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) - style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) - style.add(border='{}px solid gray '.format(border_depth)) - style2 = Style('QListView') - style2.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) - style2.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) + # === style === + style = _Style('QComboBox') + style['font'] = create_style_from_font(font) + style['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) + style['border'] = '{}px solid gray '.format(border_depth) + # style2 = Style('QListView') + # style2['color'] = (element.TextColor, COLOR_SYSTEM_DEFAULT) + # style2['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) - element.QT_ComboBox.setStyleSheet(style.content+style2.content) + element.QT_ComboBox.setStyleSheet(style.build_css_string())# content+style2.content) + element.css_style_obj = (style,) + # === style === end if not auto_size_text: if element_size[0] is not None: @@ -6145,23 +6279,28 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) != 0 else 0 element.Widget = element.QT_ListWidget = QListWidget() style = element.QT_ListWidget.styleSheet() + # import pdb; pdb.set_trace(); + # style += """QScrollBar:vertical { # border: none; # background:lightgray; # width:12px; # margin: 0px 0px 0px 0px; # } """ - style = 'QListWidget {' - style += create_style_from_font(font) + # === style === + style = _Style('QListWidget') + style['font'] = create_style_from_font(font) if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: - style += 'color: %s;' % element.TextColor + style['color'] = element.TextColor if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - element.QT_ListWidget.setStyleSheet(style) + style['background-color'] = element.BackgroundColor # example for mike here + style['margin'] = full_element_pad + style['border'] = '{}px solid gray; '.format(border_depth) + element.QT_ListWidget.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + if not auto_size_text: if element_size[0] is not None: element.QT_ListWidget.setFixedWidth(element_size[0]) @@ -6176,15 +6315,11 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_ListWidget.setSelectionMode(QAbstractItemView.ContiguousSelection) elif element.SelectMode == SELECT_MODE_SINGLE: element.QT_ListWidget.setSelectionMode(QAbstractItemView.SingleSelection) + if element.Disabled: element.QT_ListWidget.setDisabled(True) + if element.ChangeSubmits: element.QT_ListWidget.currentRowChanged.connect(element._QtCurrentRowChanged) - if element.Disabled: - element.QT_ListWidget.setDisabled(True) - - if element.ChangeSubmits: - element.QT_ListWidget.currentRowChanged.connect(element._QtCurrentRowChanged) # add all Values to the ListWidget - items = [str(v) for v in element.Values] - element.QT_ListWidget.addItems(items) + element.QT_ListWidget.addItems([str(v) for v in element.Values]) # select the default items for index, value in enumerate(element.Values): item = element.QT_ListWidget.item(index) @@ -6207,17 +6342,17 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_TextEdit.dragEnterEvent = element._dragEnterEvent element.QT_TextEdit.dropEvent = element._dropEvent - style = 'QTextEdit {' - style += create_style_from_font(font) + # === style === + style = _Style('QTextEdit') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray; '.format(border_depth) + element.QT_TextEdit.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - element.QT_TextEdit.setStyleSheet(style) if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6253,16 +6388,18 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): width, height = element_size element.Widget = element.QT_TextBrowser = QTextBrowser() element.QT_TextBrowser.setDisabled(False) - style = 'QTextBrowser {' - style += create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - element.QT_TextBrowser.setStyleSheet(style) + + # === style === + style = _Style('QTextBrowser') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + element.QT_TextBrowser.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6285,14 +6422,17 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_Checkbox.setChecked(element.InitialState) if element.Disabled: element.QT_Checkbox.setDisabled(True) - style = create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - element.QT_Checkbox.setStyleSheet(style) + # === style === + style = _Style('QCheckBox') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + element.QT_Checkbox.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6321,18 +6461,26 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_QProgressBar.setValue(element.StartValue) if element.Orientation.lower().startswith('v'): element.QT_QProgressBar.setOrientation(QtCore.Qt.Vertical) - style = '' + + # === style === + style = _Style('QProgressBar') + style_chunk = _Style('QProgressBar::chunk') # style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) # style += 'border: {}px solid gray; '.format(border_depth) if element.BarColor != (None, None): if element.BarColor[0] is not None: - style += "QProgressBar::chunk { background-color: %s; }"%element.BarColor[0] - if element.BarColor[1] is not None: - style += "QProgressBar { border: %spx solid grey; border-radius: 0px; background-color: %s; }"%(border_depth, element.BarColor[1]) - else: - style += "QProgressBar { border: %spx solid grey; border-radius: 0px; background-color: %s}"%(border_depth, DEFAULT_PROGRESS_BAR_COLOR[1]) + style_chunk['background-color'] = element.BarColor[0] - element.QT_QProgressBar.setStyleSheet(style) + style['border'] = '%spx solid grey' % border_depth + style['border-radius'] = '0px' + style['background-color'] = str(element.BarColor[1] \ + if element.BarColor[1] is not None \ + else DEFAULT_PROGRESS_BAR_COLOR[1]) + + + element.QT_QProgressBar.setStyleSheet(style.build_css_string()+style_chunk.build_css_string()) + element.css_style_obj = (style, style_chunk) + # === style === end element.QT_QProgressBar.setTextVisible(False) if element.Tooltip: @@ -6349,15 +6497,17 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_Radio_Button = qradio if element.Disabled: element.QT_Radio_Button.setDisabled(True) - if default_value: - qradio.setChecked(True) - style = create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - element.QT_Radio_Button.setStyleSheet(style) + if default_value: qradio.setChecked(True) + + # === style === + style = _Style('QRadioButton') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + element.QT_Radio_Button.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6393,16 +6543,17 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_Spinner.setValue(element.QT_Spinner.valueFromText(element.DefaultValue)) except: pass - style = 'QSpinBox {' - style += create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - element.QT_Spinner.setStyleSheet(style) + # === style === + style = _Style('QSpinBox') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + element.QT_Spinner.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + # element.QT_Spinner.setRange(element.Values[0], element.Values[1]) if not auto_size_text: if element_size[0] is not None: @@ -6424,22 +6575,18 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element = element # type: Output element.Widget = element.QT_TextBrowser = QTextBrowser() element.QT_TextBrowser.setDisabled(False) - style = 'QTextBrowser {' - style += create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - # style += """QScrollBar:vertical { - # border: none; - # background:lightgray; - # width:12px; - # margin: 0px 0px 0px 0px; - # } """ - style += '}' - element.QT_TextBrowser.setStyleSheet(style) + + # === style === + style = _Style('QTextBrowser') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + # style += "QScrollBar:vertical {border: none; background:lightgray; width:12px; margin: 0px 0px 0px 0px; } " + element.QT_TextBrowser.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: @@ -6477,12 +6624,14 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): pixmap.loadFromData(ba) qlabel.setPixmap(pixmap) - style = '' - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - element.QT_QLabel.setStyleSheet(style) - if element.Tooltip: - element.QT_QLabel.setToolTip(element.Tooltip) + # === style === + style = _Style('QLabel') + style['margin'] = full_element_pad + element.QT_QLabel.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + if element.Tooltip: element.QT_QLabel.setToolTip(element.Tooltip) if element.ClickSubmits: element.QT_QLabel.mousePressEvent = element.QtCallbackImageClicked if not element.Visible: @@ -6504,12 +6653,15 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_QGraphicsScene.setSceneRect(0,0,element.CanvasSize[0],element.CanvasSize[1]) element.QT_QGraphicsView.setScene(element.QT_QGraphicsScene) - style = Style('QGraphicsView') - style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) - style.add(margin='{}px {}px {}px {}px'.format(*full_element_pad)) - style.add(border='{}px solid gray '.format(border_depth)) + # === style === + style = _Style('QGraphicsView') + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) + style['margin'] = full_element_pad + style['border'] = '{}px solid gray '.format(border_depth) # print(f'style content = {style.content}') - element.QT_QGraphicsView.setStyleSheet(style.content) + element.QT_QGraphicsView.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end qgraphicsview.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) qgraphicsview.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) @@ -6535,10 +6687,26 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): baritem.setTitle(menu_entry[0]) element.QT_QMenuBar.addAction(baritem.menuAction()) AddMenuItem(baritem, menu_entry[1], element) + # === style === + menu_style = _Style('QMenu') + menu_style['font'] = create_style_from_font(font) + if element.MenuItemTextColor is not None and element.MenuItemTextColor != COLOR_SYSTEM_DEFAULT: + menu_style['color'] = element.MenuItemTextColor + if element.MenuItemBackgroundColor is not None and element.MenuItemBackgroundColor != COLOR_SYSTEM_DEFAULT: + menu_style['background-color'] = element.MenuItemBackgroundColor + # style['margin'] = full_element_pad + baritem.setStyleSheet(menu_style.build_css_string()) + # === style === end + + if element.BackgroundColor != COLOR_SYSTEM_DEFAULT: - style = Style('QMenuBar') - style.add(background_color=(element.BackgroundColor)) - element.QT_QMenuBar.setStyleSheet(style.content) + # === style === + style = _Style('QMenuBar') + style['background_color'] = (element.BackgroundColor, COLOR_SYSTEM_DEFAULT) + element.QT_QMenuBar.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + if not element.Visible: element.QT_QMenuBar.setVisible(False) toplevel_win.QT_QMainWindow.setMenuBar(element.QT_QMenuBar) @@ -6546,16 +6714,22 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_BUTTONMENU: btext = element.ButtonText element.Widget = element.QT_QPushButton = QPushButton(btext) - style = create_style_from_font(font) + + # === style === + style = _Style('QPushButton') + style['font'] = create_style_from_font(font) if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: - style += 'color: %s;' % element.TextColor + style['color'] = element.TextColor if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: - style += 'background-color: %s;' % element.BackgroundColor + style['background-color'] = element.BackgroundColor if element.BorderWidth == 0: - style += 'border: none;' - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - # style += 'border: {}px solid gray; '.format(border_depth) - element.QT_QPushButton.setStyleSheet(style) + style['border'] = 'none' + style['margin'] = full_element_pad + element.QT_QPushButton.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + + if (element.AutoSizeButton is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None) and element.ImageData is None: if element_size[0] is not None: element.QT_QPushButton.setFixedWidth(element_size[0]) @@ -6582,6 +6756,18 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): qmenu.setTitle(menu_def[0]) AddMenuItem(qmenu, menu_def[1], element) + # === style === + menu_style = _Style('QMenu') + menu_style['font'] = create_style_from_font(font) + if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: + menu_style['color'] = element.TextColor + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + menu_style['background-color'] = element.BackgroundColor + # style['margin'] = full_element_pad + qmenu.setStyleSheet(menu_style.build_css_string()) + # element.css_style_obj = (style,) + # === style === end + element.QT_QPushButton.setMenu(qmenu) if element.Tooltip: element.QT_QPushButton.setToolTip(element.Tooltip) @@ -6592,21 +6778,23 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_FRAME: element.Widget = column_widget = QGroupBox() element.QT_QGroupBox = column_widget - style = create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor + + # === style === + style = _Style('QGroupBox') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor # style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) # style += 'border: {}px solid gray; '.format(border_depth) - column_widget.setStyleSheet(style) + column_widget.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + column_widget.setTitle(element.Title) - column_layout = QFormLayout() - column_vbox = QVBoxLayout() + column_layout, column_vbox = QFormLayout(), QVBoxLayout() PackFormIntoFrame(element, column_layout, toplevel_win) - column_vbox.addLayout(column_layout) - column_widget.setLayout(column_vbox) + column_vbox.addLayout(column_layout); column_widget.setLayout(column_vbox) if element.Tooltip: column_widget.setToolTip(element.Tooltip) if not element.Visible: @@ -6617,11 +6805,15 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.Widget = tab_widget = QWidget() element.QT_QWidget = tab_widget # tab_widget.setFrameShape(QtWidgets.QFrame.NoFrame) - style = create_style_from_font(font) + + # === style === + style = _Style('QTabWidget') + style['font'] = create_style_from_font(font) if element.BackgroundColor is not None: # style += 'background-color: %s;' % element.BackgroundColor # style += 'QTabWidget > QWidget > QWidget {background: %s;}'% element.BackgroundColor - style += 'QTabWidget::pane {background: %s;}'% element.BackgroundColor + style['background-color'] = element.BackgroundColor + style.my_anchor = '::pane' # style += 'background-color: %s;' % element.BackgroundColor tab_widget.setAutoFillBackground(True) palette = tab_widget.palette() @@ -6629,12 +6821,13 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): tab_widget.setPalette(palette) # style += 'border: {}px solid gray; '.format(border_depth) - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - # print(f'Tab widget style {style}') - tab_widget.setStyleSheet(style) + style['margin'] = full_element_pad + tab_widget.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end - column_layout = QFormLayout() - column_vbox = QVBoxLayout() + + column_layout, column_vbox = QFormLayout(), QVBoxLayout() PackFormIntoFrame(element, column_layout, toplevel_win) @@ -6650,14 +6843,22 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element = element # type:TabGroup element.Widget = element.QT_QTabWidget = qtab =QTabWidget() - style = qtab.styleSheet() + # === style === + style = _Style('QTabWidget') + # print(f'qtab.styleSheet() -> {qtab.styleSheet()}') + # style = qtab.styleSheet() # FIXv2 if element.SelectedTitleColor not in (None, COLOR_SYSTEM_DEFAULT): - style += 'QTabBar::tab:selected {background: %s;}'%element.SelectedTitleColor + style.my_anchor = '::tab:selected' + style['background'] = element.SelectedTitleColor if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): - style += 'QTabBar::tab {background: %s;}'% element.BackgroundColor + style.my_anchor = '::tab' + style['background'] = element.BackgroundColor if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): - style += 'QTabBar::tab {color: %s;}'%element.TextColor - qtab.setStyleSheet(style) + style.my_anchor = '::tab' + style['color'] = element.TextColor + qtab.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end if element.TabLocation is not None: position_dict = {'left': QtWidgets.QTabWidget.TabPosition.West, 'right': QtWidgets.QTabWidget.TabPosition.East, 'top': QtWidgets.QTabWidget.TabPosition.North, 'bottom': QtWidgets.QTabWidget.TabPosition.South, 'lefttop': QtWidgets.QTabWidget.TabPosition.North, @@ -6679,22 +6880,20 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_INPUT_SLIDER: element = element # type: Slider element.Widget = element.QT_Slider = QSlider() - if element.Orientation.startswith('h'): - element.QT_Slider.setOrientation(Qt.Horizontal) - else: - element.QT_Slider.setOrientation(Qt.Vertical) - if element.Disabled: - element.QT_Slider.setDisabled(True) - style = create_style_from_font(font) - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - element.QT_Slider.setStyleSheet(style) + element.QT_Slider.setOrientation(Qt.Horizontal if element.Orientation.startswith('h') else Qt.Vertical) + if element.Disabled: element.QT_Slider.setDisabled(True) - element.QT_Slider.setMinimum(element.Range[0]) - element.QT_Slider.setMaximum(element.Range[1]) + # === style === + style = _Style('QSlider') + style['font'] = create_style_from_font(font) + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + element.QT_Slider.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end + element.QT_Slider.setMinimum(element.Range[0]); element.QT_Slider.setMaximum(element.Range[1]) position = QSlider.TicksBothSides if element.Relief == RELIEF_TICK_POSITION_NO_TICKS: position = QSlider.NoTicks @@ -6712,13 +6911,11 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): if element.TickInterval is not None: element.QT_Slider.setTickInterval(element.TickInterval) + if element_size[0] is not None: element.QT_Slider.setFixedWidth(element_size[0]) + if element_size[1] is not None: element.QT_Slider.setFixedHeight(element_size[1]) if element.Resolution is not None: element.QT_Slider.setSingleStep(element.Resolution) element.QT_Slider.setPageStep(element.Resolution) - if element_size[0] is not None: - element.QT_Slider.setFixedWidth(element_size[0]) - if element_size[1] is not None: - element.QT_Slider.setFixedHeight(element_size[1]) element.QT_Slider.setValue(element.DefaultValue) if element.ChangeSubmits: @@ -6732,30 +6929,24 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_INPUT_DIAL: element.Widget = element.QT_Dial = qdial = QDial() - style = create_style_from_font(font) - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - element.QT_Dial.setStyleSheet(style) + # === style === + style = _Style('QDial') + style['font'] = create_style_from_font(font) + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + element.QT_Dial.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) + # === style === end - if element.Disabled: - element.QT_Dial.setDisabled(True) - - element.QT_Dial.setMinimum(element.Range[0]) - element.QT_Dial.setMaximum(element.Range[1]) - - qdial.setNotchesVisible(True) - if element.TickInterval is not None: - qdial.setNotchTarget(element.TickInterval) - if element.Resolution is not None: - element.QT_Dial.setSingleStep(element.Resolution) - if element_size[0] is not None: - element.QT_Dial.setFixedWidth(element_size[0]) - if element_size[1] is not None: - element.QT_Dial.setFixedHeight(element_size[1]) + if element.Disabled: element.QT_Dial.setDisabled(True) + element.QT_Dial.setMinimum(element.Range[0]); element.QT_Dial.setMaximum(element.Range[1]) element.QT_Dial.setValue(element.DefaultValue) - + qdial.setNotchesVisible(True) + if element.TickInterval is not None: qdial.setNotchTarget(element.TickInterval) + if element.Resolution is not None: element.QT_Dial.setSingleStep(element.Resolution) + if element_size[0] is not None: element.QT_Dial.setFixedWidth(element_size[0]) + if element_size[1] is not None: element.QT_Dial.setFixedHeight(element_size[1]) if element.ChangeSubmits: element.QT_Dial.valueChanged.connect(element._QtCallbackValueChanged) if element.Tooltip: @@ -6775,29 +6966,27 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): if element.NumRows is not None: element.QT_TableWidget.setFixedHeight(element.NumRows*35+25) # element.QT_TableWidget = QTableWidget() - style = '' - if element.HeaderBackgroundColor is not None: - style += 'QHeaderView::section {background-color: %s;}\n' % element.HeaderBackgroundColor - if element.HeaderTextColor is not None: - style += 'QHeaderView::section {color: %s;}\n' % element.HeaderTextColor - style += 'QTableWidget {' - style += create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;\n' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor + # === style === + style = _Style('QTableWidget') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + + # more css: ScrollBar + style.append_css_to_end.append(" QScrollBar:vertical {border: none; background:lightgray; width:12px; margin: 0px 0px 0px 0px; } ") + # more css: QHeaderView + header_style = _Style('QHeaderView::section') + header_style['font'] = create_style_from_font(element.HeaderFont if element.HeaderFont is not None else font) + header_style['background-color'] = element.HeaderBackgroundColor + header_style['color'] = element.HeaderTextColor + + element.QT_TableWidget.setStyleSheet(style.build_css_string() + header_style.build_css_string()) + element.css_style_obj = (style, header_style) + # === style === end - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - style += """QScrollBar:vertical { - border: none; - background:lightgray; - width:12px; - margin: 0px 0px 0px 0px; - } """ - element.QT_TableWidget.setStyleSheet(style) if element.ChangeSubmits: element.QT_TableWidget.itemSelectionChanged.connect(element._QtCallbackCellActivated) element.QT_TableWidget.setRowCount(len(element.Values)) @@ -6849,11 +7038,10 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): # treeview.column(heading, width=width * CharWidthInPixels(), anchor=anchor) def add_treeview_data(node, widget): # print(f'Inserting {node.key} under parent {node.parent}') + child = widget if node != element.TreeData.root_node: child = QTreeWidgetItem(widget) child.setText(0, str(node.text)) - else: - child = widget # if node.key != '': # child.setData(0,0,node.values) if type(node.icon) is bytes: @@ -6874,22 +7062,25 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): add_treeview_data(element.TreeData.root_node, element.QT_QTreeWidget) - style = 'QTreeWidget {' - style += create_style_from_font(font) - if element.TextColor is not None: - style += 'color: %s;\n' % element.TextColor - if element.BackgroundColor is not None: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - style += 'border: {}px solid gray; '.format(border_depth) - style += '}' - style += """QScrollBar:vertical { - border: none; - background:lightgray; - width:12px; - margin: 0px 0px 0px 0px; - } """ - element.QT_QTreeWidget.setStyleSheet(style) + # === style === + style = _Style('QTreeWidget') + style['font'] = create_style_from_font(font) + if element.TextColor is not None: style['color'] = element.TextColor + if element.BackgroundColor is not None: style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + style['border'] = '{}px solid gray'.format(border_depth) + style.append_css_to_end.append(" QScrollBar:vertical {border: none; background:lightgray; width:12px; margin: 0px 0px 0px 0px; } ") + + header_style = _Style('QHeaderView::section') + header_style['font'] = create_style_from_font(element.HeaderFont if element.HeaderFont is not None else font) + header_style['background-color'] = element.HeaderBackgroundColor + header_style['color'] = element.HeaderTextColor + + element.QT_QTreeWidget.setStyleSheet(style.build_css_string() + header_style.build_css_string()) + element.css_style_obj = (style, header_style) + # === style === end + + if element.ChangeSubmits: element.QT_QTreeWidget.itemSelectionChanged.connect(element._QtCallbackCellActivated) @@ -6910,23 +7101,23 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): element.QT_Label.setFixedWidth(element_size[0]) if element_size[1] is not None: element.QT_Label.setFixedHeight(element_size[1]) - style = '' + style = _Style('QLabel') if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: - style += 'color: %s;' % element.TextColor + style['color'] = element.TextColor if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: - style += 'background-color: %s;' % element.BackgroundColor - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - element.QT_Label.setStyleSheet(style) + style['background-color'] = element.BackgroundColor + style['margin'] = full_element_pad + element.QT_Label.setStyleSheet(style.build_css_string()) + element.css_style_obj = (style,) qlabel.setFrameStyle(QFrame.VLine if element.Orientation[0] =='v' else QFrame.HLine) qt_row_layout.addWidget(element.QT_Label) - pass # ............................DONE WITH ROW pack the row of widgets ..........................# - qt_row_layout.setSpacing(toplevel_win.ElementPadding[0]) - containing_frame.setSpacing(toplevel_win.ElementPadding[1]) + qt_row_layout.setSpacing(0) + containing_frame.setSpacing(0) containing_frame.addRow('', qt_row_layout) # done with row, pack the row of widgets @@ -6936,7 +7127,6 @@ def PackFormIntoFrame(container_elem, containing_frame, toplevel_win): def ConvertFlexToTK(window): InitializeResults(window) - pass master = 000000 PackFormIntoFrame(window, window.QFormLayout, window) # ....................................... DONE creating and laying out window ..........................# @@ -8329,8 +8519,6 @@ def ChangeLookAndFeel(index, force=False): :type index: (str) :param force: no longer used :type force: (bool) - :return: None - :rtype: None """ global CURRENT_LOOK_AND_FEEL @@ -8355,7 +8543,7 @@ def ChangeLookAndFeel(index, force=False): elif opt2 in lf_values: ix = lf_values.index(opt2) else: - ix = random.randint(0, len(lf_values) - 1) + ix = random.random.randint(0, len(lf_values) - 1) print('** Warning - {} Theme is not a valid theme. Change your theme call. **'.format(index)) print('valid values are', list_of_look_and_feel_values()) print('Instead, please enjoy a random Theme named {}'.format(list_of_look_and_feel_values()[ix])) @@ -8367,7 +8555,6 @@ def ChangeLookAndFeel(index, force=False): # Color the progress bar using button background and input colors...unless they're the same if colors['PROGRESS'] != COLOR_SYSTEM_DEFAULT: - if colors['PROGRESS'] == DEFAULT_PROGRESS_BAR_COMPUTE: if colors['BUTTON'][1] != colors['INPUT'] and colors['BUTTON'][1] != colors['BACKGROUND']: colors['PROGRESS'] = colors['BUTTON'][1], colors['INPUT'] else: # if the same, then use text input on top of input color @@ -8556,8 +8743,11 @@ def Popup(*args, title=None, button_color=None, background_color=None, text_colo # fancy code to check if string and convert if not is not need. Just always convert to string :-) # if not isinstance(message, str): message = str(message) message = str(message) - if message.count('\n'): - message_wrapped = message + if message.count('\n'): # if there are line breaks, then wrap each segment separately + # message_wrapped = message # used to just do this, but now breaking into smaller pieces + message_wrapped = '' + msg_list = message.split('\n') # break into segments that will each be wrapped + message_wrapped = '\n'.join([textwrap.fill(msg, local_line_width) for msg in msg_list]) else: message_wrapped = textwrap.fill(message, local_line_width) message_wrapped_lines = message_wrapped.count('\n') + 1 @@ -8566,7 +8756,8 @@ def Popup(*args, title=None, button_color=None, background_color=None, text_colo max_line_total = max(max_line_total, width_used) # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines - layout.append([Text(message_wrapped, auto_size_text=True, text_color=text_color, background_color=background_color)]) + window.AddRow( + Text(message_wrapped, auto_size_text=True, text_color=text_color, background_color=background_color)) total_lines += height # if total_lines < 3: