def figureOutHeight(self, _width=100, content=""): temp_label = Label(width=_width, markup=True, text=content) d = temp_label._font_properties dkw = dict(zip(d, [getattr(temp_label, x) for x in d])) from kivy.core.text.markup import MarkupLabel la = MarkupLabel(**dkw) w, h = la.render(real=False) # makes the _lines variables # Grab the heights dimensions of the input (guard against empty string) input_heights = [] for entry in la._lines: heights = [item[1] for item in entry[4]] input_heights.extend(heights) input_height = max(input_heights) if len(input_heights) > 0 else 0 return input_height*len(la._lines)
def _create_line_label(self, text, hint=False): # Create a label from a text, using line options ntext = text.replace(u'\n', u'').replace(u'\t', u' ' * self.tab_width) if self.password and not hint: # Don't replace hint_text with * ntext = u'*' * len(ntext) ntext = self._get_bbcode(ntext) kw = self._get_line_options() cid = u'{}\0{}\0{}'.format(ntext, self.password, kw) texture = Cache_get('textinput.label', cid) if texture is None: # FIXME right now, we can't render very long line... # if we move on "VBO" version as fallback, we won't need to # do this. # try to find the maximum text we can handle label = Label(text=ntext, **kw) if text.find(u'\n') > 0: label.text = u'' else: label.text = ntext label.refresh() # ok, we found it. texture = label.texture Cache_append('textinput.label', cid, texture) label.text = '' return texture
def _create_line_label(self, text): # Create a label from a text, using line options ntext = text.replace("\n", "").replace("\t", " " * self.tab_width) if self.password: ntext = "*" * len(ntext) ntext = self._get_bbcode(ntext) kw = self._get_line_options() cid = "%s\0%s" % (ntext, str(kw)) texture = Cache_get("textinput.label", cid) if not texture: # FIXME right now, we can't render very long line... # if we move on "VBO" version as fallback, we won't need to do this. # try to found the maximum text we can handle label = Label(text=ntext, **kw) if text.find("\n") > 0: label.text = "" else: label.text = ntext try: label.refresh() except ValueError: return # ok, we found it. texture = label.texture Cache_append("textinput.label", cid, texture) label.text = "" return texture
def _create_line_label(self, text, hint=False): # Create a label from a text, using line options ntext = text.replace('\n', '').replace('\t', ' ' * self.tab_width) if self.password and not hint: # Don't replace hint_text with * ntext = '*' * len(ntext) ntext = self._get_bbcode(ntext) kw = self._get_line_options() cid = '%s\0%s' % (ntext, str(kw)) texture = Cache_get('textinput.label', cid) if not texture: # FIXME right now, we can't render very long line... # if we move on "VBO" version as fallback, we won't need to do this. # try to found the maximum text we can handle label = Label(text=ntext, **kw) if text.find('\n') > 0: label.text = '' else: label.text = ntext try: label.refresh() except ValueError: return # ok, we found it. texture = label.texture Cache_append('textinput.label', cid, texture) label.text = '' return texture
def _create_label(self): # create the core label class according to markup value if self._label is not None: cls = self._label.__class__ else: cls = None if cls is not CoreMarkupLabel: # markup have change, we need to change our rendering method. d = TerminalWidgetKivy._font_properties dkw = dict(list(zip(d, [getattr(self, x) for x in d]))) self._label = CoreMarkupLabel(**dkw) self._update_line_options()
def checkCorrect(self, testWordStr, inputStr, decodedChar): if (self.gTimerState["mainGame"]): mainWord = MarkupLabel(testWordStr).markup[1] if (len(inputStr) > len(mainWord)): self.nextWord() #Get new word, Reset text elif (len(inputStr) > 0): #Highlight correct/wrong if (mainWord[len(inputStr) - 1] == decodedChar ): #Extract text from markup, then extract char at index textHighlight = "#baed91" #Correct, green self.game_totalScore += 10 else: textHighlight = "#ff6961" #Wrong, red self.lblTestWord.text = "[color={}]{}[/color]".format( textHighlight, mainWord) self.lblScore.text = "Score: %05d" % self.game_totalScore if (len(inputStr) == len(mainWord)): #Check if it's last word self.cancelTimer(self.beforeNextWordClk) self.beforeNextWordClk = Clock.schedule_once( self.loadNextWord, 0.5) #Wait for 0.5 second before showing next word
class TerminalWidgetKivy(FocusBehavior, Widget, TerminalWidget): _font_properties = ('lines', 'font_size', 'font_name', 'bold', 'italic', 'underline', 'strikethrough', 'halign', 'valign', 'padding_left', 'padding_top', 'padding_right', 'padding_bottom', 'shorten', 'mipmap', 'line_height', 'max_lines', 'strip', 'split_str', 'unicode_errors', 'font_hinting', 'font_kerning', 'font_blended') def __init__(self, session, **kwargs): self._trigger_texture = Clock.create_trigger(self._texture_update, -1) super(TerminalWidgetKivy, self).__init__(**kwargs) self.session = session self.tab_width = session.get_tab_width() self.refresh_font() # bind all the property for recreating the texture d = TerminalWidgetKivy._font_properties fbind = self.fbind update = self._trigger_texture_update fbind('disabled', update, 'disabled') for x in d: fbind(x, update, x) self._label = None self._create_label() self.line_rects = {} self._touch_count = 0 self.cancel_selection() self.font_kerning = True # force the texture creation self._trigger_texture() def _create_label(self): # create the core label class according to markup value if self._label is not None: cls = self._label.__class__ else: cls = None if cls is not CoreMarkupLabel: # markup have change, we need to change our rendering method. d = TerminalWidgetKivy._font_properties dkw = dict(list(zip(d, [getattr(self, x) for x in d]))) self._label = CoreMarkupLabel(**dkw) self._update_line_options() def _create_line_label(self): d = TerminalWidgetKivy._font_properties dkw = dict(list(zip(d, [getattr(self, x) for x in d]))) return CoreMarkupLabel(**dkw) def _update_line_options(self): min_line_ht = self._label.get_extents('_')[1] self.line_height = min_line_ht self._label.options['color'] = [1,1,1,1] def _trigger_texture_update(self, name=None, source=None, value=None): # check if the label core class need to be switch to a new one if source: if name == 'font_size': self._label.options[name] = value else: self._label.options[name] = value if name != 'lines': self._trigger_texture() def _texture_update(self, *largs): self._update_line_options() logging.getLogger('term_widget').debug('texture update, cursor visible:{}'.format(self.cursor_visible)) lines = [line[:] for line in self.lines] line_options = [line_option[:] for line_option in self.line_options] c_col, c_row = self.term_cursor self.canvas.clear() dy = self.line_height + self.line_spacing y = self.height x = 0 last_f_color = self.session.cfg.default_foreground_color last_b_color = self.session.cfg.default_background_color last_mode = 0 for i in range(len(lines)): x = 0 b_x = 0 line = lines[i] line_option = line_options[i] if i < len(line_options) else [] col = 0 last_col = 0 text = '' text_parts = [] def render_text(t, xxxx): cur_f_color, cur_b_color = last_f_color, last_b_color if last_mode & TextMode.REVERSE: cur_f_color, cur_b_color = last_b_color, last_f_color text = ''.join(['[color=', self._get_color_hex(cur_f_color), ']', escape_markup(t), '[/color]']) text_parts.append(text) return self._add_background(t, cur_b_color, xxxx, y - (i + 1) * dy) last_option = None for col in range(len(line_option)): if line_option[col] is None: continue if last_option == line_option[col]: continue f_color, b_color, mode = line_option[col] n_f_color, n_b_color, n_mode = last_f_color, last_b_color, last_mode # foreground if f_color and len(f_color) > 0: n_f_color = f_color elif f_color is None: n_f_color = self.session.cfg.default_foreground_color # background if b_color and len(b_color) > 0: n_b_color = b_color elif b_color is None: n_b_color = self.session.cfg.default_background_color #mode if mode is not None: n_mode = mode if (n_f_color, n_b_color, n_mode) == (last_f_color, last_b_color, last_mode): continue if last_col < col: if self.cursor_visible and i == c_row and last_col <= c_col and c_col < col: b_x = render_text(''.join(line[last_col: c_col]), b_x) tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(''.join(line[c_col: c_col + 1]), b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b b_x = render_text(''.join(line[c_col + 1: col]), b_x) else: b_x = render_text(''.join(line[last_col: col]), b_x) last_col = col last_option = line_option[col] last_f_color, last_b_color, last_mode = n_f_color, n_b_color, n_mode if last_col < len(line): if self.cursor_visible and i == c_row and last_col <= c_col and c_col < len(line): b_x = render_text(''.join(line[last_col: c_col]), b_x) tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(''.join(line[c_col: c_col + 1]), b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b b_x = render_text(''.join(line[c_col + 1:]), b_x) else: b_x = render_text(''.join(line[last_col:]), b_x) if self.cursor_visible and i == c_row and c_col >= len(line): tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(' ', b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b #add background to fill empty cols if b_x < self.width: tmp_b_c, last_b_color = last_b_color, self.session.cfg.default_background_color render_text(' ' * (self.visible_cols + 1), b_x) last_b_color = tmp_b_c try: self._add_text(i, ''.join(text_parts), x, y - (i + 1) * dy) except: logging.exception('show text:{},x={},y={}'.format(''.join(text_parts), x, y - (i + 1) * dy)) def _get_color_hex(self, l_color): return '#%02x%02x%02x%02x' % (l_color[0], l_color[1], l_color[2], l_color[3]) def _add_background(self, text, color, x, y): if not text or len(text) == 0: return x cid = '%s\0%02x%02x%02x%02x' % (text, color[0], color[1], color[2], color[3]) t = Cache_get('termwidget.b', cid) if t is not None: if self.session.cfg.debug_more: logging.getLogger('term_widget').debug('reuse the background texture, pos={}, {}, size={}'.format(x, y, t.size)) self.canvas.add(Rectangle(texture=t, pos=(x , y), size=t.size)) return x + t.size[0] from kivy.graphics import Color from kivy.graphics.instructions import InstructionGroup from kivy.graphics.texture import Texture size = Cache_get('termwidget.b_size', text) if size is None: text = self.norm_text(text) size = self._label.get_extents(text) size = (size[0], size[1] + 1) Cache_append('termwidget.b_size', text, size) t = Texture.create(size=size) buf = color * size[0] * size[1] buf = b''.join(map(chr, buf)) t.blit_buffer(buf, colorfmt='rgba', bufferfmt='ubyte') Cache_append('termwidget.b', cid, t) self.canvas.add(Rectangle(texture=t, pos=(x , y), size=size, group='background')) return x + size[0] def _add_text(self, line_num, text, x, y): self.line_rects[line_num] = Rectangle(size=(0,0), pos=(x, y)) if not text or len(text) == 0: return label = Cache_get('termwidget.label', text) texture = None if label is None: label = self._create_line_label() text = self.norm_text(text) label.text = text#.decode('utf_8', errors='ignore') label.refresh() if label.texture: label.texture.bind() texture = label.texture Cache_append('termwidget.label', text, label) if self.session.cfg.debug_more: logging.getLogger('term_widget').debug('cache the foreground texture, pos={}, {}, size={}'.format(x, y, texture.size)) else: texture = label.texture if self.session.cfg.debug_more: logging.getLogger('term_widget').debug('reuse the foreground texture, pos={}, {}, size={}'.format(x, y, texture.size)) self.line_rects[line_num] = Rectangle(texture=texture, size=texture.size, pos=(x, y), group='foreground') self.canvas.add(self.line_rects[line_num]) def _get_text_width(self, text): width = Cache_get('termwidget.width', text) if width is not None: return width txt = self.norm_text(text) width = self._label.get_extents(txt)[0] Cache_append('termwidget.width', text, width) return width def refresh(self): self._trigger_texture() def on_touch_down(self, touch): touch_pos = touch.pos if not self.collide_point(*touch_pos): return super(TerminalWidgetKivy, self).on_touch_down(touch) touch.grab(self) self._touch_count += 1 cursor = self._get_cursor_from_xy(*touch_pos) if not self._selection_touch: self.cancel_selection() self._selection_touch = touch self._selection_from = self._selection_to = cursor self._update_selection() self.focus = True return super(TerminalWidgetKivy, self).on_touch_down(touch) def on_touch_move(self, touch): if touch.grab_current is not self: return super(TerminalWidgetKivy, self).on_touch_move(touch) if self._selection_touch is touch: self._selection_to = self._get_cursor_from_xy(touch.x, touch.y) self._update_selection() return super(TerminalWidgetKivy, self).on_touch_move(touch) def on_touch_up(self, touch): if touch.grab_current is not self: return super(TerminalWidgetKivy, self).on_touch_up(touch) touch.ungrab(self) self._touch_count -= 1 if self._selection_touch is touch: self._selection_to = self._get_cursor_from_xy(touch.x, touch.y) self._update_selection(True) self.focus = True return super(TerminalWidgetKivy, self).on_touch_up(touch) def _get_cursor_from_xy(self, x, y): '''Return the (row, col) of the cursor from an (x, y) position. ''' padding_left = self.padding[0] padding_top = self.padding[1] l = self.lines dy = self.line_height + self.line_spacing cx = x - self.x cy = (self.top - padding_top) - y cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1)) _get_text_width = self._get_text_width for i in range(0, len(l[cy])): if _get_text_width(''.join(l[cy][:i])) + \ _get_text_width(l[cy][i]) * 0.6 + \ padding_left > cx: return i, cy return len(l[cy]), cy # # Selection control # def cancel_selection(self): super(TerminalWidgetKivy, self).cancel_selection() self._selection_touch = None def _update_selection(self, finished=False): self._selection_finished = finished if not finished: self._selection = True else: self._selection = True self._selection_touch = None self._update_graphics_selection() def _update_graphics_selection(self): if not self._selection: return self.canvas.remove_group('selection') dy = self.line_height + self.line_spacing padding_top = self.padding[1] padding_bottom = self.padding[3] _top = self.top y = _top - padding_top miny = self.y + padding_bottom maxy = _top - padding_top draw_selection = self._draw_selection a, b = self.get_selection() s1c, s1r = a s2c, s2r = b s2r += 1 # pass only the selection lines[] # passing all the lines can get slow when dealing with a lot of text y -= s1r * dy _lines = self.lines _get_text_width = self._get_text_width width = self.width padding_left = self.padding[0] padding_right = self.padding[2] x = self.x canvas_add = self.canvas.add selection_color = self.selection_color for line_num, value in enumerate(_lines[s1r:s2r], start=s1r): r = self.line_rects[line_num] if miny <= y <= maxy + dy: draw_selection(r.pos, r.size, line_num, (s1c, s1r), (s2c, s2r - 1), _lines, _get_text_width, width, padding_left, padding_right, x, canvas_add, selection_color) y -= dy def _draw_selection(self, *largs): pos, size, line_num, (s1c, s1r), (s2c, s2r),\ _lines, _get_text_width, width,\ padding_left, padding_right, x, canvas_add, selection_color = largs # Draw the current selection on the widget. if line_num < s1r or line_num > s2r or line_num >= len(_lines): return x, y = pos w, h = size x1 = x x2 = x + w if line_num == s1r: lines = _lines[line_num] if not lines: return s1c = s1c if s1c <= len(lines) else len(lines) x1 += _get_text_width(''.join(lines[:s1c])) if line_num == s2r: lines = _lines[line_num] if not lines: return s2c = s2c if s2c <= len(lines) else len(lines) x2 = x + _get_text_width(''.join(lines[:s2c])) width_minus_padding = width - (padding_right + padding_left) maxx = x + width_minus_padding if x1 > maxx: return x1 = max(x1, x) x2 = min(x2, x + width_minus_padding) canvas_add(Color(*selection_color, group='selection')) canvas_add(Rectangle( pos=(x1, pos[1]), size=(x2 - x1, size[1] + 1), group='selection')) def copy_to_clipboard(self, data): from kivy.core.clipboard import Clipboard Clipboard.copy(data) def paste_from_clipboard(self): from kivy.core.clipboard import Clipboard return Clipboard.paste() def refresh_font(self): if self.session and self.session.cfg: config = self.session.cfg.config cfg = self.session.cfg self.font_name, nouse_font_name, self.font_size = cfg.get_font_info() # # Properties # selection_color = ListProperty([0.1843, 0.6549, 0.8313, .5]) font_name = StringProperty('WenQuanYi') font_size = NumericProperty('17.5sp') line_height = NumericProperty(1.0) line_spacing = NumericProperty(1.0) bold = BooleanProperty(False) italic = BooleanProperty(False) underline = BooleanProperty(False) strikethrough = BooleanProperty(False) padding_left = NumericProperty(0) padding_top = NumericProperty(0) padding_right = NumericProperty(0) padding_bottom = NumericProperty(0) padding = ReferenceListProperty(padding_left, padding_top, padding_right, padding_bottom) halign = OptionProperty('left', options=['left', 'center', 'right', 'justify']) valign = OptionProperty('top', options=['bottom', 'middle', 'center', 'top']) texture = ObjectProperty(None, allownone=True) texture_size = ListProperty([0, 0]) mipmap = BooleanProperty(False) shorten = BooleanProperty(False) split_str = StringProperty('') unicode_errors = OptionProperty( 'replace', options=('strict', 'replace', 'ignore')) max_lines = NumericProperty(0) strip = BooleanProperty(False) font_hinting = OptionProperty( 'mono', options=[None, 'normal', 'light', 'mono'], allownone=True) font_kerning = BooleanProperty(True) font_blended = BooleanProperty(True)
def insert_text(self, substring, from_undo=False): self.page = self.parent.parent.parent if substring == "AC": self.text = "" return if substring == "Del": if self.last_press in "\r\n=": self.insert_text("AC") else: self.do_backspace() return if substring == "*": substring = "x" if substring == "**": substring = "^" if substring == "/": substring = "÷" if substring == "a\u00b2": substring = "^2" if substring == "ceil": if self.selection_text: self.text = self.text.replace(self.selection_text, f"ceil({self.selection_text})") else: self.text = f"ceil({self.text})" return if substring == "|a|": if self.selection_text: self.text = self.text.replace(self.selection_text, f"abs({self.selection_text})") else: self.text = f"abs({self.text})" return if substring == "floor": if self.selection_text: self.text = self.text.replace(self.selection_text, f"floor({self.selection_text})") else: self.text = f"floor({self.text})" return if substring == "\u221aa": if self.selection_text: self.text = self.text.replace(self.selection_text, f"sqrt({self.selection_text})") else: self.text = f"sqrt({self.text})" return if substring == "a!": substring = "!" if substring == str(config_data['base']) + '\u00aa': substring = str(config_data['base']) + '^' if self.last_press in "+-÷x^%\u00b1": if self.last_press == substring: return else: if self.text and substring in "+-÷x^%": self.do_backspace() if substring in "÷x^" and (self.text == "0" or not self.text): return if ((current_page[0] == "standard" and substring not in string.digits + "%()+-x÷^.!=\r\n" + string.ascii_letters and not substring.isdecimal() and substring != "^2") or (current_page[0] == "scientific" and substring not in string.digits + "%()e+-x÷^.!sincotae=\r\n" and substring != "^2" and substring not in ['sin', 'cos', 'tan', 'cosec', 'cot', 'sec', 'log'] and substring not in [ 'sin\u00af\u00b9', 'cos\u00af\u00b9', 'tan\u00af\u00b9', 'cosec\u00af\u00b9', 'cot\u00af\u00b9', 'sec\u00af\u00b9' ] and substring != str(config_data['base'] + '^') and substring != '\u03c0') or (current_page[0] == "convert" and substring not in string.digits + ".=\r\n") or (current_page[0] == "days" and substring not in string.digits + "=\r\n")): return self.last_press = substring if substring in ["\r", "\n", "="]: if self.text == 'pass': self.text = '' self.page.parent.parent.parent.parent.options_open( self.page.layout.buttons[-1][-1]) self.modal_pass = ModalView(size_hint=(0.8, 0.8)) self.modal_pass.add_widget(Pass()) self.modal_pass.open() self.modal_pass.bind( on_dismiss=lambda *args: self.page.parent.parent.parent.parent.options_close()) return if self.text[-1] in "+-÷x^(%": self.page.preview.text = "Complete the equation first!" return self.last_press = substring for opr in "+-÷x^()!%": if self.text.count(opr): break else: if current_page[0] not in ["scientific", "convert", "days"]: link = False if re.findall("[0-9]", self.text): return if self.text.count('.') == 0 and self.text.isalpha: self.text = "www."+self.text+".com" link = True elif self.text.count('.') == 1: if 'www' in self.text: self.text += ".com" else: self.text = "www."+self.text link = True if self.text.count('.') == 2 or link: webbrowser.get().open_new_tab(self.text) self.page.preview.text = "Opened in web browser!" Clock.schedule_once(lambda dt: setattr( self.page.preview, 'text', ''), 1) self.text = '' return self.page.old_text = self.text self.page.preview.text = "[ref=self.old_text]" + \ self.text + "[/ref]" if current_page[0] == "standard": substring = self.text substring = self.replace(substring) if "!" in self.text: substring = self.fac_solve(self.text) try: substring = Basic(exp=substring).solution except: self.page.preview.text = ( "There's some error!") return elif current_page[0] == "scientific": substring = self.text substring = self.replace(substring) if "!" in substring: substring = self.fac_solve(substring) rad = 1 if self.page.layout.buttons[0][2].text == "RAD" else 0 for r in ["sin", "tan", "cos", "cot", "cosec", "sec"]: substring = substring.replace(r, f"Basic(rad={rad}).{r}") for r in [ "sin\u00af\u00b9", "tan\u00af\u00b9", "cos\u00af\u00b9", "cot\u00af\u00b9", "cosec\u00af\u00b9", "sec\u00af\u00b9" ]: r1 = r.replace("\u00af\u00b9", "") substring = substring.replace(r, f"a{r1}") substring = substring.replace( "log", f"Basic(base={config_data['base']}).log") from math import factorial try: substring = Basic(exp=substring).solution except: self.page.preview.text = "Something went wrong!" return elif current_page[0] == "convert": if not self.quantity: self.quantity = self.page.layout.buttons[0][1].text if not self.from_unit: self.from_unit = self.page.layout.buttons[1][1].text if not self.to_unit: self.to_unit = self.page.layout.buttons[1][3].text try: substring = (str( eval("Convert." + self.quantity) (self.text.split()[0], self.from_unit, self.to_unit)) + " " + self.to_unit) self.page.preview.text = ("[ref=self.old_text]" + self.text + " " + self.from_unit + "[/ref]") except: self.page.preview.text = "There's some error!" return elif current_page[0] == "days": try: substring = days_number( self.page.layout.buttons[1][0].text, self.page.layout.buttons[1][2].text, ) if self.page.layout.buttons[2][-1].state == "down": substring += 1 if self.page.layout.buttons[3][-1].state == "down": substring -= 1 substring = str(substring) self.page.preview.text = f"{self.page.layout.buttons[1][0].text} to {self.page.layout.buttons[1][2].text}" except: self.page.preview.text = "Oops! Couldn't find that!" return self.solved = True write_history( self.page.preview.text if current_page[0] == "days" else MarkupLabel(self.page.preview.text).markup[1], substring, current_page[0], ) self.text = "" if self.text == "0" and substring != ".": self.do_backspace() for sub_ in substring: return super(Text, self).insert_text(substring, from_undo=from_undo)
def modal_update_old(self): print("modal_update_old()") #def modal_update(columnHeadings, rows): # How do I get this data from kivy; inside this function? drill down to the .text # Where are the columnHeading fields in kivy data? in cells with .id == "Header_Label". # grid object is present here. # - - - - - - - - - - print("From DataGrid.remove_row(self, n_cols({}), instance, **kwargs)". format(n_cols)) childs = grid.children print(str(childs)) #childs = self.parent.children selected = 0 # No cells selected, yet. doUpdate = True theData = {} for ch in childs: print("ch: " + str(ch)) for c in reversed(ch.children): print("c: " + str(c)) if c.id != "Header_Label": print("c.id: " + str(c.id)) if c.state == "down": #print(str(c.state)) #print("self.remove_widget(c) was here.") #self.remove_widget(c) nml2 = MarkupLabel(c.text).markup print(" Value: " + nml2[1]) print( str(c.id) + ' - ' + str(c.state) + ' - ' + nml2[1]) theData[selected] = nml2[1] # Keep this data for update. print("theData: " + theData) selected += 1 # Another cell selected. if selected > 4: print("Only a single row may be selected for update.") doUpdate = False if selected == 0: # If not selected, above; then pick the first row in memory which is the last row on the screen. print("You must select a row to be updated.") doUpdate = False #print(str(selected)) #for ch in childs: # print(str(ch)) # count_01 = n_cols # count_02 = 0 # count = -1 # #count = 0 # # TODO; next 3 lines loop forever. grid.children must be the wrong object to set this to? # while True: # count += 1 # if count >= n_cols: # break # #while (count + + < n_cols): # print(count) # if n_cols != len(ch.children): # for c in ch.children: # print(c) # if c.id != "Header_Label": # print("Length: " + str(len(ch.children)), end='') # print(" N_cols: " + str(n_cols + 1), end='') # # print(" self.remove_widget(c) was here.") # #self.remove_widget(c) # #count += 1 # break # else: # break # else: # break if not doUpdate: # TODO; Display the error message in kivy so folks can see it. print("Can not doUpdate because of some previous error.") exit() print("doUpdate") print("Data: " + theData) # - - - - - - - - - - columnHeadings = ['ID', 'Nome', 'Preco', 'IVA'] # TODO; where are the product fields inside kivy data? rows = { 1: ['000', 'Product Name 1', '123.45', '23'], 2: ['001', 'Product Name 2', '234.56', '34'], 3: ['002', 'Product Name 3', '345.67', '45'] } #def modal_update(self, columnHeadings, rows): print("modal_update {}".format(columnHeadings)) print("{}".format(rows)) # TODO; copied modal_insert to modal_update; now make modal_update work! # data should contain Column headings (labels) and Data. # columnHeadings = ['ID', 'Nome', 'Preco', 'IVA'] # rows = {1:['000', 'Product Name 1', '123.45', '23'], # 2:['001', 'Product Name 2', '234.56', '34'] # 3:['002', 'Product Name 3', '345.67', '45'] # } # modal_update(self, columnHeadings, rows) # TODO; Make this variable according to the count of items in columnHeadings and rows['1']! elementsCH = len(columnHeadings) elementsR = len( rows[1]) # TODO; shouldn't we iterate through the selected rows? if elementsCH != elementsR: # TODO; logg or msgbox this! # error() inform somebody print( "Something is wrong, the number of columnHeadings ({}) != the number of rows (())!" .format(elementsCH, elementsR)) exit() insertion_grid = GridLayout(cols=2) # TODO; Apply iteration here! # for elementsR: # lbl? = Label(text=columnHeadings[?], id="lbl") # txt? = TextInput(text=rows['?'][0], id="txtinp") lbl1 = Label(text=columnHeadings[0], id="lbl") txt1 = TextInput(text=rows[1][0], id="txtinp") insertion_grid.add_widget(lbl1) insertion_grid.add_widget(txt1) lbl2 = Label(text=columnHeadings[1], id="lbl") txt2 = TextInput(text=rows[1][1], id="txtinp") insertion_grid.add_widget(lbl2) insertion_grid.add_widget(txt2) lbl3 = Label(text=columnHeadings[2], id="lbl") txt3 = TextInput(text=rows[1][2], id="txtinp") insertion_grid.add_widget(lbl3) insertion_grid.add_widget(txt3) lbl4 = Label(text=columnHeadings[3], id="lbl") txt4 = TextInput(text=rows[1][3], id="txtinp") insertion_grid.add_widget(lbl4) insertion_grid.add_widget(txt4) #lbl1 = Label(text='ID', id="lbl") #lbl2 = Label(text='Nome', id="lbl") #lbl3 = Label(text='Preco', id="lbl") #lbl4 = Label(text='IVA', id="lbl") #txt1 = TextInput(text='000', id="txtinp") #txt2 = TextInput(text='Product Name', id="txtinp") #txt3 = TextInput(text='123.45', id="txtinp") #txt4 = TextInput(text='23', id="txtinp") # create content and assign to the view content = Button(text='Close me!') modal_layout = BoxLayout(orientation="vertical") modal_layout.add_widget(insertion_grid) def update_def(self): input_list = [] for text_inputs in reversed(self.parent.children[2].children): if text_inputs.id == "txtinp": input_list.append(text_inputs.text) print(input_list) # TODO; how do I make this an UPDATE? print(input_list) grid.update_row(input_list, body_alignment, col_size, self) # def update_row(self, n_cols, instance, **kwargs): #grid.add_row(input_list, body_alignment, col_size, self) # def add_row(self, row_data, row_align, cols_size, instance, **kwargs): # print view # view.dismiss update_btn = Button(text="Update", on_press=update_def) modal_layout.add_widget(update_btn) modal_layout.add_widget(content) view = ModalView(auto_dismiss=False) view.add_widget(modal_layout) # bind the on_press event of the button to the dismiss function content.bind(on_press=view.dismiss) update_btn.bind(on_release=view.dismiss) view.open()
def update_row(self, row_data, row_align, cols_size, instance, **kwargs): #def add_row(self, row_data, row_align, cols_size, instance, **kwargs): #def update_row(self, n_cols, instance, **kwargs): print("update_row()") doUpdate = True theData = {} childs = self.parent.children # DataGrid.children selected = 0 for ch in childs: # DataGrid.children[n] n = all children print("ch: " + str(ch)) for c in reversed(ch.children): # DataGrid.children[n].children print("c: " + str(c)) if c.id != "Header_Label": print("c.id: " + str(c.id)) # HINT; google kivy datagrid state and find source that references kivy objects. if c.state == "down": # state can be ('normal', 'down', ...) print(str(c.id) + ' - ' + str(c.state), end='') nml2 = MarkupLabel(c.text).markup print("A cell or column item on the selected row.", end='') print(" N_cols: " + str(n_cols), end='') print(" Id: " + str(c.id), end='') print(" Length: " + str(len(ch.children)), end='') print(" Value: " + nml2[1]) #self.remove_widget(c) #print (str(c.id) + ' - ' + str(c.state)) theData[selected] = nml2[ 1] # Keep this data for update. print("theData: " + str(theData)) selected += 1 if selected == 0: # None were found to be state='down' so delete something - the bottom row. # But, interestingly, the bottom row on the screen is the first row in memory. # Except that items that have .id == 'Header_Label' are the first row(s) in memory. for ch in childs: count_01 = n_cols count_02 = 0 selected = 0 while ( selected < n_cols ): # Number of columns in a row; must delete all columns in the row. if n_cols != len(ch.children): for c in ch.children: if c.id != "Header_Label": print( "A cell or column item on the selected row.", end='') #print("Data: " + str(c.text)) nml2 = MarkupLabel(c.text).markup #print("~m: {}".format(nml2)) print("N_cols: " + str(n_cols), end='') print(" Count: " + str(selected), end='') print(" Id: " + str(c.id), end='') print(" Length: " + str(len(ch.children)), end='') print(" Value: " + nml2[1]) theData[selected] = nml2[ 1] # Keep this data for update. print("theData: " + str(theData)) #self.remove_widget(c) # there goes one of the columns in the row. selected += 1 break else: break else: break if not doUpdate: # TODO; Display the error message in kivy so folks can see it. print("Can not doUpdate because of some previous error.") exit() print("If the data is OK then do the ENTRY and UPDATE here.") print("doUpdate") print("Data: " + str(theData)) print("TODO; ENTRY screen") print("TODO; rob entry screen from add_row?") print("TODO; UPDATE DataGrid") print("TODO; UPDATE database") print("Done updating items.")
class TerminalWidgetKivy(FocusBehavior, Widget, TerminalWidget): _font_properties = ('lines', 'font_size', 'font_name', 'bold', 'italic', 'underline', 'strikethrough', 'halign', 'valign', 'padding_left', 'padding_top', 'padding_right', 'padding_bottom', 'shorten', 'mipmap', 'line_height', 'max_lines', 'strip', 'split_str', 'unicode_errors', 'font_hinting', 'font_kerning', 'font_blended') def __init__(self, session, **kwargs): self._trigger_texture = Clock.create_trigger(self._texture_update, -1) super(TerminalWidgetKivy, self).__init__(**kwargs) self.session = session self.tab_width = session.get_tab_width() self.refresh_font() # bind all the property for recreating the texture d = TerminalWidgetKivy._font_properties fbind = self.fbind update = self._trigger_texture_update fbind('disabled', update, 'disabled') for x in d: fbind(x, update, x) self._label = None self._create_label() self.line_rects = {} self._touch_count = 0 self.cancel_selection() self.font_kerning = True # force the texture creation self._trigger_texture() def _create_label(self): # create the core label class according to markup value if self._label is not None: cls = self._label.__class__ else: cls = None if cls is not CoreMarkupLabel: # markup have change, we need to change our rendering method. d = TerminalWidgetKivy._font_properties dkw = dict(list(zip(d, [getattr(self, x) for x in d]))) self._label = CoreMarkupLabel(**dkw) self._update_line_options() def _create_line_label(self): d = TerminalWidgetKivy._font_properties dkw = dict(list(zip(d, [getattr(self, x) for x in d]))) return CoreMarkupLabel(**dkw) def _update_line_options(self): min_line_ht = self._label.get_extents('_')[1] self.line_height = min_line_ht self._label.options['color'] = [1, 1, 1, 1] def _trigger_texture_update(self, name=None, source=None, value=None): # check if the label core class need to be switch to a new one if source: if name == 'font_size': self._label.options[name] = value else: self._label.options[name] = value if name != 'lines': self._trigger_texture() def _texture_update(self, *largs): self._update_line_options() logging.getLogger('term_widget').debug( 'texture update, cursor visible:{}'.format(self.cursor_visible)) lines = [line[:] for line in self.lines] line_options = [line_option[:] for line_option in self.line_options] c_col, c_row = self.term_cursor self.canvas.clear() dy = self.line_height + self.line_spacing y = self.height x = 0 last_f_color = self.session.cfg.default_foreground_color last_b_color = self.session.cfg.default_background_color last_mode = 0 for i in range(len(lines)): x = 0 b_x = 0 line = lines[i] line_option = line_options[i] if i < len(line_options) else [] col = 0 last_col = 0 text = '' text_parts = [] def render_text(t, xxxx): cur_f_color, cur_b_color = last_f_color, last_b_color if last_mode & TextMode.REVERSE: cur_f_color, cur_b_color = last_b_color, last_f_color text = ''.join([ '[color=', self._get_color_hex(cur_f_color), ']', escape_markup(t), '[/color]' ]) text_parts.append(text) return self._add_background(t, cur_b_color, xxxx, y - (i + 1) * dy) last_option = None for col in range(len(line_option)): if line_option[col] is None: continue if last_option == line_option[col]: continue f_color, b_color, mode = line_option[col] n_f_color, n_b_color, n_mode = last_f_color, last_b_color, last_mode # foreground if f_color and len(f_color) > 0: n_f_color = f_color elif f_color is None: n_f_color = self.session.cfg.default_foreground_color # background if b_color and len(b_color) > 0: n_b_color = b_color elif b_color is None: n_b_color = self.session.cfg.default_background_color #mode if mode is not None: n_mode = mode if (n_f_color, n_b_color, n_mode) == (last_f_color, last_b_color, last_mode): continue if last_col < col: if self.cursor_visible and i == c_row and last_col <= c_col and c_col < col: b_x = render_text(''.join(line[last_col:c_col]), b_x) tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(''.join(line[c_col:c_col + 1]), b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b b_x = render_text(''.join(line[c_col + 1:col]), b_x) else: b_x = render_text(''.join(line[last_col:col]), b_x) last_col = col last_option = line_option[col] last_f_color, last_b_color, last_mode = n_f_color, n_b_color, n_mode if last_col < len(line): if self.cursor_visible and i == c_row and last_col <= c_col and c_col < len( line): b_x = render_text(''.join(line[last_col:c_col]), b_x) tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(''.join(line[c_col:c_col + 1]), b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b b_x = render_text(''.join(line[c_col + 1:]), b_x) else: b_x = render_text(''.join(line[last_col:]), b_x) if self.cursor_visible and i == c_row and c_col >= len(line): tmp_l_f, last_f_color, tmp_l_b, last_b_color = \ last_f_color, last_b_color, last_b_color, self.session.cfg.default_cursor_color b_x = render_text(' ', b_x) last_f_color, last_b_color = tmp_l_f, tmp_l_b #add background to fill empty cols if b_x < self.width: tmp_b_c, last_b_color = last_b_color, self.session.cfg.default_background_color render_text(' ' * (self.visible_cols + 1), b_x) last_b_color = tmp_b_c try: self._add_text(i, ''.join(text_parts), x, y - (i + 1) * dy) except: logging.exception('show text:{},x={},y={}'.format( ''.join(text_parts), x, y - (i + 1) * dy)) def _get_color_hex(self, l_color): return '#%02x%02x%02x%02x' % (l_color[0], l_color[1], l_color[2], l_color[3]) def _add_background(self, text, color, x, y): if not text or len(text) == 0: return x cid = '%s\0%02x%02x%02x%02x' % (text, color[0], color[1], color[2], color[3]) t = Cache_get('termwidget.b', cid) if t is not None: if self.session.cfg.debug_more: logging.getLogger('term_widget').debug( 'reuse the background texture, pos={}, {}, size={}'.format( x, y, t.size)) self.canvas.add(Rectangle(texture=t, pos=(x, y), size=t.size)) return x + t.size[0] from kivy.graphics import Color from kivy.graphics.instructions import InstructionGroup from kivy.graphics.texture import Texture size = Cache_get('termwidget.b_size', text) if size is None: text = self.norm_text(text) size = self._label.get_extents(text) size = (size[0], size[1] + 1) Cache_append('termwidget.b_size', text, size) t = Texture.create(size=size) buf = color * size[0] * size[1] buf = b''.join(map(chr, buf)) t.blit_buffer(buf, colorfmt='rgba', bufferfmt='ubyte') Cache_append('termwidget.b', cid, t) self.canvas.add( Rectangle(texture=t, pos=(x, y), size=size, group='background')) return x + size[0] def _add_text(self, line_num, text, x, y): self.line_rects[line_num] = Rectangle(size=(0, 0), pos=(x, y)) if not text or len(text) == 0: return label = Cache_get('termwidget.label', text) texture = None if label is None: label = self._create_line_label() text = self.norm_text(text) label.text = text #.decode('utf_8', errors='ignore') label.refresh() if label.texture: label.texture.bind() texture = label.texture Cache_append('termwidget.label', text, label) if self.session.cfg.debug_more: logging.getLogger('term_widget').debug( 'cache the foreground texture, pos={}, {}, size={}'.format( x, y, texture.size)) else: texture = label.texture if self.session.cfg.debug_more: logging.getLogger('term_widget').debug( 'reuse the foreground texture, pos={}, {}, size={}'.format( x, y, texture.size)) self.line_rects[line_num] = Rectangle(texture=texture, size=texture.size, pos=(x, y), group='foreground') self.canvas.add(self.line_rects[line_num]) def _get_text_width(self, text): width = Cache_get('termwidget.width', text) if width is not None: return width txt = self.norm_text(text) width = self._label.get_extents(txt)[0] Cache_append('termwidget.width', text, width) return width def refresh(self): self._trigger_texture() def on_touch_down(self, touch): touch_pos = touch.pos if not self.collide_point(*touch_pos): return super(TerminalWidgetKivy, self).on_touch_down(touch) touch.grab(self) self._touch_count += 1 cursor = self._get_cursor_from_xy(*touch_pos) if not self._selection_touch: self.cancel_selection() self._selection_touch = touch self._selection_from = self._selection_to = cursor self._update_selection() self.focus = True return super(TerminalWidgetKivy, self).on_touch_down(touch) def on_touch_move(self, touch): if touch.grab_current is not self: return super(TerminalWidgetKivy, self).on_touch_move(touch) if self._selection_touch is touch: self._selection_to = self._get_cursor_from_xy(touch.x, touch.y) self._update_selection() return super(TerminalWidgetKivy, self).on_touch_move(touch) def on_touch_up(self, touch): if touch.grab_current is not self: return super(TerminalWidgetKivy, self).on_touch_up(touch) touch.ungrab(self) self._touch_count -= 1 if self._selection_touch is touch: self._selection_to = self._get_cursor_from_xy(touch.x, touch.y) self._update_selection(True) self.focus = True return super(TerminalWidgetKivy, self).on_touch_up(touch) def _get_cursor_from_xy(self, x, y): '''Return the (row, col) of the cursor from an (x, y) position. ''' padding_left = self.padding[0] padding_top = self.padding[1] l = self.lines dy = self.line_height + self.line_spacing cx = x - self.x cy = (self.top - padding_top) - y cy = int(boundary(round(cy / dy - 0.5), 0, len(l) - 1)) _get_text_width = self._get_text_width for i in range(0, len(l[cy])): if _get_text_width(''.join(l[cy][:i])) + \ _get_text_width(l[cy][i]) * 0.6 + \ padding_left > cx: return i, cy return len(l[cy]), cy # # Selection control # def cancel_selection(self): super(TerminalWidgetKivy, self).cancel_selection() self._selection_touch = None def _update_selection(self, finished=False): self._selection_finished = finished if not finished: self._selection = True else: self._selection = True self._selection_touch = None self._update_graphics_selection() def _update_graphics_selection(self): if not self._selection: return self.canvas.remove_group('selection') dy = self.line_height + self.line_spacing padding_top = self.padding[1] padding_bottom = self.padding[3] _top = self.top y = _top - padding_top miny = self.y + padding_bottom maxy = _top - padding_top draw_selection = self._draw_selection a, b = self.get_selection() s1c, s1r = a s2c, s2r = b s2r += 1 # pass only the selection lines[] # passing all the lines can get slow when dealing with a lot of text y -= s1r * dy _lines = self.lines _get_text_width = self._get_text_width width = self.width padding_left = self.padding[0] padding_right = self.padding[2] x = self.x canvas_add = self.canvas.add selection_color = self.selection_color for line_num, value in enumerate(_lines[s1r:s2r], start=s1r): r = self.line_rects[line_num] if miny <= y <= maxy + dy: draw_selection(r.pos, r.size, line_num, (s1c, s1r), (s2c, s2r - 1), _lines, _get_text_width, width, padding_left, padding_right, x, canvas_add, selection_color) y -= dy def _draw_selection(self, *largs): pos, size, line_num, (s1c, s1r), (s2c, s2r),\ _lines, _get_text_width, width,\ padding_left, padding_right, x, canvas_add, selection_color = largs # Draw the current selection on the widget. if line_num < s1r or line_num > s2r or line_num >= len(_lines): return x, y = pos w, h = size x1 = x x2 = x + w if line_num == s1r: lines = _lines[line_num] if not lines: return s1c = s1c if s1c <= len(lines) else len(lines) x1 += _get_text_width(''.join(lines[:s1c])) if line_num == s2r: lines = _lines[line_num] if not lines: return s2c = s2c if s2c <= len(lines) else len(lines) x2 = x + _get_text_width(''.join(lines[:s2c])) width_minus_padding = width - (padding_right + padding_left) maxx = x + width_minus_padding if x1 > maxx: return x1 = max(x1, x) x2 = min(x2, x + width_minus_padding) canvas_add(Color(*selection_color, group='selection')) canvas_add( Rectangle(pos=(x1, pos[1]), size=(x2 - x1, size[1] + 1), group='selection')) def copy_to_clipboard(self, data): from kivy.core.clipboard import Clipboard Clipboard.copy(data) def paste_from_clipboard(self): from kivy.core.clipboard import Clipboard return Clipboard.paste() def refresh_font(self): if self.session and self.session.cfg: config = self.session.cfg.config cfg = self.session.cfg self.font_name, nouse_font_name, self.font_size = cfg.get_font_info( ) # # Properties # selection_color = ListProperty([0.1843, 0.6549, 0.8313, .5]) font_name = StringProperty('WenQuanYi') font_size = NumericProperty('17.5sp') line_height = NumericProperty(1.0) line_spacing = NumericProperty(1.0) bold = BooleanProperty(False) italic = BooleanProperty(False) underline = BooleanProperty(False) strikethrough = BooleanProperty(False) padding_left = NumericProperty(0) padding_top = NumericProperty(0) padding_right = NumericProperty(0) padding_bottom = NumericProperty(0) padding = ReferenceListProperty(padding_left, padding_top, padding_right, padding_bottom) halign = OptionProperty('left', options=['left', 'center', 'right', 'justify']) valign = OptionProperty('top', options=['bottom', 'middle', 'center', 'top']) texture = ObjectProperty(None, allownone=True) texture_size = ListProperty([0, 0]) mipmap = BooleanProperty(False) shorten = BooleanProperty(False) split_str = StringProperty('') unicode_errors = OptionProperty('replace', options=('strict', 'replace', 'ignore')) max_lines = NumericProperty(0) strip = BooleanProperty(False) font_hinting = OptionProperty('mono', options=[None, 'normal', 'light', 'mono'], allownone=True) font_kerning = BooleanProperty(True) font_blended = BooleanProperty(True)