diff --git a/python/configs/plug/far2l/fardialogbuilder.py b/python/configs/plug/far2l/fardialogbuilder.py index 988f1db4f..706a2481e 100644 --- a/python/configs/plug/far2l/fardialogbuilder.py +++ b/python/configs/plug/far2l/fardialogbuilder.py @@ -73,7 +73,7 @@ def __init__(self, varname, text, **kwargs): self.text = text def get_best_size(self): - return (len(self.text), 1) + return (len(self.text.replace('&','')), 1) def makeItem(self, dlg): self.data = dlg.s2f(self.text) @@ -84,10 +84,15 @@ class EDIT(Element): dit = "DI_EDIT" def __init__(self, varname, width, mask=None, height=1, **kwargs): + if "history" in kwargs: + history = kwargs.pop("history") + else: + history = None super().__init__(varname, **kwargs) self.width = width self.height = height self.mask = None + self.history = history def get_best_size(self): return (self.width, self.height) @@ -97,6 +102,9 @@ def makeItem(self, dlg): if self.mask is not None: self.param = {"Mask": dlg.s2f(self.mask)} self.flags = dlg.ffic.DIF_MASKEDIT + elif self.history is not None: + self.param = {"History": dlg.s2f(self.history)} + self.flags = dlg.ffic.DIF_HISTORY super().makeItem(dlg) @@ -127,7 +135,7 @@ def __init__(self, varname, text, **kwargs): def get_best_size(self): # [ text ] - return (4 + len(self.text), 1) + return (4 + len(self.text.replace('&','')), 1) def makeItem(self, dlg): self.data = dlg.s2f(self.text) @@ -145,7 +153,7 @@ def __init__(self, varname, text, checked=0, **kwargs): def get_best_size(self): # [?] text - return (4 + len(self.text), 1) + return (4 + len(self.text.replace('&','')), 1) def makeItem(self, dlg): self.data = dlg.s2f(self.text) @@ -162,7 +170,7 @@ def __init__(self, varname, text, selected=0, **kwargs): def get_best_size(self): # (?) text - return (4 + len(self.text), 1) + return (4 + len(self.text.replace('&','')), 1) def makeItem(self, dlg): self.data = dlg.s2f(self.text) @@ -173,10 +181,14 @@ class COMBOBOX(Element): dit = "DI_COMBOBOX" def __init__(self, varname, selected, *items, **kwargs): + if "width" in kwargs: + width = kwargs.pop("width") + else: + width = max([len(s) for s in items]) super().__init__(varname, **kwargs) self.selected = selected self.items = items - self.width = max([len(s) for s in items]) + self.width = width def get_best_size(self): return (2 + self.width, 1) @@ -247,8 +259,8 @@ class USERCONTROL(Element): def __init__(self, varname, width, height, **kwargs): super().__init__(varname, **kwargs) - self.width - self.height + self.width = width + self.height = height def get_best_size(self): return (self.width, self.height) @@ -320,6 +332,22 @@ def makeItem(self, dlg): control.makeItem(dlg) +class FlowSizer(sizer.FlowSizer): + def __init__(self, cols, *controls, border=(0, 0, 0, 0)): + super().__init__(cols) + self.controls = controls + for control in controls: + self.add(control, border) + + def makeID(self, dlg): + for control in self.controls: + control.makeID(dlg) + + def makeItem(self, dlg): + for control in self.controls: + control.makeItem(dlg) + + class DialogBuilder(sizer.HSizer): def __init__( self, plugin, dialogProc, title, helptopic, flags, contents, border=(2, 1, 2, 1) diff --git a/python/configs/plug/far2l/fardialogsizer.py b/python/configs/plug/far2l/fardialogsizer.py index c8e39453b..e54914eb8 100644 --- a/python/configs/plug/far2l/fardialogsizer.py +++ b/python/configs/plug/far2l/fardialogsizer.py @@ -1,4 +1,4 @@ -__all__ = ["Window", "HSizer", "VSizer"] +__all__ = ["Window", "Spacer", "HSizer", "VSizer", "GridSizer"] class Orientation: @@ -19,6 +19,10 @@ def get_best_size(self): raise NotImplementedError("Window.get_best_size") +class Spacer(Window): + def get_best_size(self): + return self.size + class Box: def __init__(self, window, border): self.window = window @@ -88,3 +92,51 @@ class HSizer(Sizer): class VSizer(Sizer): orientation = Orientation.vertical + + +class FlowSizer(Sizer): + def __init__(self, cols, border=(0, 0, 0, 0)): + self.boxes = [[]] + self.cols = cols + self.border = border + self.sizes = None + self.col_widths = None + self.row_heights = None + + def add(self, w, border=(0, 0, 1, 0)): + box = self.boxes[-1] + if len(box) == self.cols: + box = [] + self.boxes.append(box) + box.append(Box(w, border)) + + def move(self, x, y, w, h): + self.size(x, y, w, h) + + def size(self, l, t, r, b): + l += self.border[0] + t += self.border[1] + r -= self.border[2] + b -= self.border[3] + cy = 0 + for row in range(len(self.boxes)): + cx = 0 + for col in range(len(self.boxes[row])): + box = self.boxes[row][col] + bx, by = box.get_best_size() + box.size(l+cx, t+cy, l+cx+self.col_widths[col], t+cy+by) + cx += self.col_widths[col] + cy += self.row_heights[row] + + def get_best_size(self): + while len(self.boxes[-1])%self.cols: + self.add(Spacer()) + sizes = [[col.get_best_size() for col in row] for row in self.boxes] + col_widths = [max(sizes[row_nr][col_nr][0] for row_nr in range(len(sizes))) for col_nr in range(len(sizes[0]))] + row_heights = [max(col[1] for col in row) for row in sizes] + self.sizes = sizes + self.col_widths = col_widths + self.row_heights = row_heights + w = sum(col_widths) + h = sum(row_heights) + return w, h diff --git a/python/configs/plug/plugins/ucharmap.py b/python/configs/plug/plugins/ucharmap.py index d7c6871f7..23c83c7e1 100644 --- a/python/configs/plug/plugins/ucharmap.py +++ b/python/configs/plug/plugins/ucharmap.py @@ -1,5 +1,14 @@ import logging from far2l.plugin import PluginBase +from far2l.fardialogbuilder import ( + TEXT, + BUTTON, + USERCONTROL, + HLine, + HSizer, + VSizer, + DialogBuilder, +) log = logging.getLogger(__name__) @@ -9,426 +18,156 @@ class Plugin(PluginBase): label = "Python Character Map" openFrom = ["PLUGINSMENU", "COMMANDLINE", "EDITOR", "VIEWER"] - def Rebuild(self, hDlg): - self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 0, 0) - prefix = ["", "&"] - for i in range(len(self.symbols)): - row = i // self.max_col - col = i % self.max_col - p = prefix[row == self.cur_row and col == self.cur_col] - offset = self.first_text_item + row * self.max_col + col - ch = self.s2f(p + self.symbols[i]) - self.info.SendDlgMessage( - hDlg, self.ffic.DM_SETTEXTPTR, offset, self.ffi.cast("LONG_PTR", ch) - ) - self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 1, 0) - def OpenPlugin(self, OpenFrom): + try: + return self._OpenPlugin(OpenFrom) + except Exception as ex: + log.exception('run') + + def GetCursorPos(self, hDlg, ID): + cpos = self.ffi.new("COORD *", dict(X=0, Y=0)) + self.info.SendDlgMessage(hDlg, self.ffic.DM_GETCURSORPOS, ID, self.ffi.cast("LONG_PTR", cpos)) + return (cpos.X, cpos.Y) + + def SetCursorPos(self, hDlg, ID, col, row): + cpos = self.ffi.new("COORD *", dict(X=col, Y=row)) + self.info.SendDlgMessage(hDlg, self.ffic.DM_SETCURSORPOS, ID, self.ffi.cast("LONG_PTR", cpos)) + + def _OpenPlugin(self, OpenFrom): if 0: import debugpy - debugpy.breakpoint() - symbols = [] - for i in range(256): - symbols.append(chr(i)) - symbols.extend( - [ - "Ђ", - "Ѓ", - "‚", - "ѓ", - "„", - "…", - "†", - "‡", - "€", - "‰", - "Љ", - "‹", - "Њ", - "Ќ", - "Ћ", - "Џ", - "ђ", - "‘", - "’", - "“", - "”", - "•", - "–", - "—", - "˜", - "™", - "љ", - "›", - "њ", - "ќ", - "ћ", - "џ", - " ", - "Ў", - "ў", - "Ј", - "¤", - "Ґ", - "¦", - "§", - "Ё", - "©", - "Є", - "«", - "¬", - "­", - "®", - "Ї", - "°", - "±", - "І", - "і", - "ґ", - "µ", - "¶", - "·", - "ё", - "№", - "є", - "»", - "ј", - "Ѕ", - "ѕ", - "ї", - "А", - "Б", - "В", - "Г", - "Д", - "Е", - "Ж", - "З", - "И", - "Й", - "К", - "Л", - "М", - "Н", - "О", - "П", - "Р", - "С", - "Т", - "У", - "Ф", - "Х", - "Ц", - "Ч", - "Ш", - "Щ", - "Ъ", - "Ы", - "Ь", - "Э", - "Ю", - "Я", - "а", - "б", - "в", - "г", - "д", - "е", - "ж", - "з", - "и", - "й", - "к", - "л", - "м", - "н", - "о", - "п", - "р", - "с", - "т", - "у", - "ф", - "х", - "ц", - "ч", - "ш", - "щ", - "ъ", - "ы", - "ь", - "э", - "ю", - "я", - "░", - "▒", - "▓", - "│", - "┤", - "╡", - "╢", - "╖", - "╕", - "╣", - "║", - "╗", - "╝", - "╜", - "╛", - "┐", - "└", - "┴", - "┬", - "├", - "─", - "┼", - "╞", - "╟", - "╚", - "╔", - "╩", - "╦", - "╠", - "═", - "╬", - "╧", - "╨", - "╤", - "╥", - "╙", - "╘", - "╒", - "╓", - "╫", - "╪", - "┘", - "┌", - "█", - "▄", - "▌", - "▐", - "▀", - "∙", - "√", - "■", - "⌠", - "≈", - "≤", - "≥", - "⌡", - "²", - "÷", - "ą", - "ć", - "ę", - "ł", - "ń", - "ó", - "ś", - "ż", - "ź", - "Ą", - "Ć", - "Ę", - "Ł", - "Ń", - "Ó", - "Ś", - "Ż", - "Ź", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ] - ) - Items = [ - ( - self.ffic.DI_DOUBLEBOX, - 3, - 1, - 38, - 18, - 0, - {"Selected": 0}, - 0, - 0, - self.s2f("Character Map"), - 0, - ), - ( - self.ffic.DI_BUTTON, - 7, - 17, - 12, - 18, - 0, - {"Selected": 0}, - 1, - self.ffic.DIF_DEFAULT + self.ffic.DIF_CENTERGROUP, - self.s2f("OK"), - 0, - ), - ( - self.ffic.DI_BUTTON, - 13, - 17, - 38, - 18, - 0, - {"Selected": 0}, - 0, - self.ffic.DIF_CENTERGROUP, - self.s2f("Cancel"), - 0, - ), - ( - self.ffic.DI_USERCONTROL, - 3, - 2, - 38, - 16, - 0, - {"Selected": 0}, - 0, - self.ffic.DIF_FOCUS, - self.ffi.NULL, - 0, - ), - ] - self.cur_row = 0 - self.cur_col = 0 + self.max_col = 32 + symbols = ''.join([chr(i) for i in range(256)])+( + 'ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏ' + 'ђ‘’“”•–—˜™љ›њќћџ' + ' ЎўЈ¤Ґ¦§Ё©Є«¬"®Ї' + '°±Ііґµ¶·ё№є»јЅѕї' + 'АБВГДЕЖЗИЙКЛМНОП' + 'РСТУФХЦЧШЩЪЫЬЭЮЯ' + 'абвгдежзийклмноп' + 'рстуфхцчшщъыьэюя' + '░▒▓│┤╡╢╖╕╣║╗╝╜╛┐' + '└┴┬├─┼╞╟╚╔╩╦╠═╬╧' + '╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀' + '∙√■⌠≈≤≥⌡²÷ąćęłńó' + 'śżźĄĆĘŁŃÓŚŻŹ' + ) + n = len(symbols) % self.max_col + if n: + symbols += ' '*(self.max_col-n) self.max_row = len(symbols) // self.max_col - self.first_text_item = len(Items) - self.symbols = symbols - self.text = None - + self.text = '' + self.charbuf = self.ffi.new("CHAR_INFO []", len(symbols)) + attrNormal = 0x170 + attrSelected = 0x1c for i in range(len(symbols)): - row = i // self.max_col - col = i % self.max_col - Items.append( - ( - self.ffic.DI_TEXT, - 5 + col, - self.first_text_item - 2 + row, - 5 + col, - self.first_text_item - 2 + row, - 0, - {"Selected": 0}, - 0, - 0, - self.ffi.NULL, - 0, - ) - ) + cb = self.charbuf[i] + cb.Attributes = attrNormal + cb.Char.UnicodeChar = ord(symbols[i]) + + def xy2lin(col, row): + return row * self.max_col + col + + def setColor(col, row, attr): + self.charbuf[xy2lin(col, row)].Attributes = attr + + def updateOffset(offset): + char = symbols[offset] + dlg.SetText(dlg.ID_voffset, f"{offset}") + dlg.SetText(dlg.ID_vchar, f'{char}/{ord(char):4x}') @self.ffi.callback("FARWINDOWPROC") def DialogProc(hDlg, Msg, Param1, Param2): if Msg == self.ffic.DN_INITDIALOG: - self.Rebuild(hDlg) + self.SetCursorPos(hDlg, dlg.ID_hex, 0, 0) + setColor(0, 0, attrSelected) + updateOffset(0) + self.info.SendDlgMessage(hDlg, self.ffic.DM_SETCURSORSIZE, dlg.ID_hex, 1|(100<<32)) return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) elif Msg == self.ffic.DN_BTNCLICK: - log.debug( - "btn DialogProc({0}, {1})".format( - Param1, Param2 - ) - ) + #log.debug(f"btn DialogProc({Param1}, {Param2})") + col, row = self.GetCursorPos(hDlg, dlg.ID_hex) + offset = xy2lin(col, row) + self.text = symbols[offset] + updateOffset(offset) + #log.debug(f"enter:{offset} row:{row} col:{col}, ch:{self.text} cb={self.charbuf[offset].Attributes:x}") return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) - elif Msg == self.ffic.DN_KEY and Param1 == self.first_text_item - 1: - log.debug( - "key DialogProc({0}, {1}, {2}, {3})".format( - hDlg, "DN_KEY", Param1, Param2 - ) - ) + elif Msg == self.ffic.DN_KEY and Param1 == dlg.ID_hex: + col, row = self.GetCursorPos(hDlg, dlg.ID_hex) + setColor(col, row, attrNormal) + #log.debug(f"key DialogProc({Param1}, {Param2:x}), col={col} row={row})") if Param2 == self.ffic.KEY_LEFT: - self.cur_col -= 1 + col -= 1 elif Param2 == self.ffic.KEY_UP: - self.cur_row -= 1 + row -= 1 elif Param2 == self.ffic.KEY_RIGHT: - self.cur_col += 1 + col += 1 elif Param2 == self.ffic.KEY_DOWN: - self.cur_row += 1 + row += 1 elif Param2 == self.ffic.KEY_ENTER: - offset = self.cur_row * self.max_col + self.cur_col - self.text = self.symbols[offset] - log.debug( - "enter:{0} row:{1} col:{2}, ch:{3}".format( - offset, self.cur_row, self.cur_col, self.text - ) - ) + offset = xy2lin(col, row) + self.text = symbols[offset] + #log.debug(f"enter:{offset} row:{row} col:{col}, ch:{self.text} cb={self.charbuf[offset].Attributes:x}") return 0 elif Param2 == self.ffic.KEY_ESC: return 0 else: return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) - if self.cur_col == self.max_col: - self.cur_col = 0 - elif self.cur_col == -1: - self.cur_col = self.max_col - 1 - if self.cur_row == self.max_row: - self.cur_row = 0 - elif self.cur_row == -1: - self.cur_row = self.max_row - 1 - self.Rebuild(hDlg) + if col == self.max_col: + col = 0 + elif col == -1: + col = self.max_col - 1 + if row == self.max_row: + row = 0 + elif row == -1: + row = self.max_row - 1 + setColor(col, row, attrSelected) + offset = xy2lin(col, row) + updateOffset(offset) + #log.debug(f"col={col}/{self.max_col} row={row}/{self.max_row}") + self.SetCursorPos(hDlg, dlg.ID_hex, col, row) return 1 - elif Msg == self.ffic.DN_MOUSECLICK: - log.debug( - "mou DialogProc({0}, {1}, {2}, {3})".format( - hDlg, "DN_MOUSECLICK", Param1, Param2 - ) - ) - ch = Param1 - self.first_text_item - if ch >= 0: - focus = self.info.SendDlgMessage(hDlg, self.ffic.DM_GETFOCUS, 0, 0) - log.debug("ch:{0} focus:{1}".format(ch, focus)) - if focus != self.first_text_item - 1: - self.info.SendDlgMessage( - hDlg, self.ffic.DM_SETFOCUS, self.first_text_item - 1, 0 - ) - self.cur_row = ch // self.max_col - self.cur_col = ch % self.max_col - self.cur_col = min(max(0, self.cur_col), self.max_col - 1) - self.cur_row = min(max(0, self.cur_row), self.max_row - 1) - offset = self.cur_row * self.max_col + self.cur_col - self.text = self.symbols[offset] - self.Rebuild(hDlg) - return 0 + elif Msg == self.ffic.DN_MOUSECLICK and Param1 == dlg.ID_hex: + col, row = self.GetCursorPos(hDlg, dlg.ID_hex) + setColor(col, row, attrNormal) + mou = self.ffi.cast("MOUSE_EVENT_RECORD *", Param2) + col = mou.dwMousePosition.X + row = mou.dwMousePosition.Y + setColor(col, row, attrSelected) + self.SetCursorPos(hDlg, dlg.ID_hex, col, row) + #log.debug(f"mou DialogProc(col={col} row={row})") + offset = xy2lin(col, row) + self.text = self.symbols[offset] + updateOffset(offset) return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) - fdi = self.ffi.new("struct FarDialogItem []", Items) - hDlg = self.info.DialogInit( - self.info.ModuleNumber, - -1, - -1, - 42, - 20, - self.s2f("Character Map"), - fdi, - len(fdi), - 0, - 0, + b = DialogBuilder( + self, DialogProc, + "Python CharMap", + "charmap", 0, + VSizer( + HSizer( + TEXT(None, "Offset:"), + TEXT("voffset", " "*8), + TEXT(None, "Char:"), + TEXT("vchar", " "*6), + ), + HLine(), + USERCONTROL('hex', self.max_col, self.max_row, param={'VBuf':self.ffi.cast("CHAR_INFO *", self.ffi.addressof(self.charbuf))}), + HLine(), + HSizer( + BUTTON("vok", "OK", flags=self.ffic.DIF_CENTERGROUP), + BUTTON("vcancel", "Cancel", flags=self.ffic.DIF_CENTERGROUP), + ), + ), ) - res = self.info.DialogRun(hDlg) - if res == 1 and self.text: + dlg = b.build(-1, -1) + + res = self.info.DialogRun(dlg.hDlg) + if res in (1, dlg.ID_vok): self.info.FSF.CopyToClipboard(self.s2f(self.text)) - self.info.DialogFree(hDlg) + self.info.DialogFree(dlg.hDlg) diff --git a/python/configs/plug/plugins/ucharmapold.py b/python/configs/plug/plugins/ucharmapold.py new file mode 100644 index 000000000..d7c6871f7 --- /dev/null +++ b/python/configs/plug/plugins/ucharmapold.py @@ -0,0 +1,434 @@ +import logging +from far2l.plugin import PluginBase + + +log = logging.getLogger(__name__) + + +class Plugin(PluginBase): + label = "Python Character Map" + openFrom = ["PLUGINSMENU", "COMMANDLINE", "EDITOR", "VIEWER"] + + def Rebuild(self, hDlg): + self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 0, 0) + prefix = ["", "&"] + for i in range(len(self.symbols)): + row = i // self.max_col + col = i % self.max_col + p = prefix[row == self.cur_row and col == self.cur_col] + offset = self.first_text_item + row * self.max_col + col + ch = self.s2f(p + self.symbols[i]) + self.info.SendDlgMessage( + hDlg, self.ffic.DM_SETTEXTPTR, offset, self.ffi.cast("LONG_PTR", ch) + ) + self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 1, 0) + + def OpenPlugin(self, OpenFrom): + if 0: + import debugpy + + debugpy.breakpoint() + symbols = [] + for i in range(256): + symbols.append(chr(i)) + symbols.extend( + [ + "Ђ", + "Ѓ", + "‚", + "ѓ", + "„", + "…", + "†", + "‡", + "€", + "‰", + "Љ", + "‹", + "Њ", + "Ќ", + "Ћ", + "Џ", + "ђ", + "‘", + "’", + "“", + "”", + "•", + "–", + "—", + "˜", + "™", + "љ", + "›", + "њ", + "ќ", + "ћ", + "џ", + " ", + "Ў", + "ў", + "Ј", + "¤", + "Ґ", + "¦", + "§", + "Ё", + "©", + "Є", + "«", + "¬", + "­", + "®", + "Ї", + "°", + "±", + "І", + "і", + "ґ", + "µ", + "¶", + "·", + "ё", + "№", + "є", + "»", + "ј", + "Ѕ", + "ѕ", + "ї", + "А", + "Б", + "В", + "Г", + "Д", + "Е", + "Ж", + "З", + "И", + "Й", + "К", + "Л", + "М", + "Н", + "О", + "П", + "Р", + "С", + "Т", + "У", + "Ф", + "Х", + "Ц", + "Ч", + "Ш", + "Щ", + "Ъ", + "Ы", + "Ь", + "Э", + "Ю", + "Я", + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "й", + "к", + "л", + "м", + "н", + "о", + "п", + "р", + "с", + "т", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "щ", + "ъ", + "ы", + "ь", + "э", + "ю", + "я", + "░", + "▒", + "▓", + "│", + "┤", + "╡", + "╢", + "╖", + "╕", + "╣", + "║", + "╗", + "╝", + "╜", + "╛", + "┐", + "└", + "┴", + "┬", + "├", + "─", + "┼", + "╞", + "╟", + "╚", + "╔", + "╩", + "╦", + "╠", + "═", + "╬", + "╧", + "╨", + "╤", + "╥", + "╙", + "╘", + "╒", + "╓", + "╫", + "╪", + "┘", + "┌", + "█", + "▄", + "▌", + "▐", + "▀", + "∙", + "√", + "■", + "⌠", + "≈", + "≤", + "≥", + "⌡", + "²", + "÷", + "ą", + "ć", + "ę", + "ł", + "ń", + "ó", + "ś", + "ż", + "ź", + "Ą", + "Ć", + "Ę", + "Ł", + "Ń", + "Ó", + "Ś", + "Ż", + "Ź", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ] + ) + Items = [ + ( + self.ffic.DI_DOUBLEBOX, + 3, + 1, + 38, + 18, + 0, + {"Selected": 0}, + 0, + 0, + self.s2f("Character Map"), + 0, + ), + ( + self.ffic.DI_BUTTON, + 7, + 17, + 12, + 18, + 0, + {"Selected": 0}, + 1, + self.ffic.DIF_DEFAULT + self.ffic.DIF_CENTERGROUP, + self.s2f("OK"), + 0, + ), + ( + self.ffic.DI_BUTTON, + 13, + 17, + 38, + 18, + 0, + {"Selected": 0}, + 0, + self.ffic.DIF_CENTERGROUP, + self.s2f("Cancel"), + 0, + ), + ( + self.ffic.DI_USERCONTROL, + 3, + 2, + 38, + 16, + 0, + {"Selected": 0}, + 0, + self.ffic.DIF_FOCUS, + self.ffi.NULL, + 0, + ), + ] + self.cur_row = 0 + self.cur_col = 0 + self.max_col = 32 + self.max_row = len(symbols) // self.max_col + self.first_text_item = len(Items) + self.symbols = symbols + self.text = None + + for i in range(len(symbols)): + row = i // self.max_col + col = i % self.max_col + Items.append( + ( + self.ffic.DI_TEXT, + 5 + col, + self.first_text_item - 2 + row, + 5 + col, + self.first_text_item - 2 + row, + 0, + {"Selected": 0}, + 0, + 0, + self.ffi.NULL, + 0, + ) + ) + + @self.ffi.callback("FARWINDOWPROC") + def DialogProc(hDlg, Msg, Param1, Param2): + if Msg == self.ffic.DN_INITDIALOG: + self.Rebuild(hDlg) + return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) + elif Msg == self.ffic.DN_BTNCLICK: + log.debug( + "btn DialogProc({0}, {1})".format( + Param1, Param2 + ) + ) + return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) + elif Msg == self.ffic.DN_KEY and Param1 == self.first_text_item - 1: + log.debug( + "key DialogProc({0}, {1}, {2}, {3})".format( + hDlg, "DN_KEY", Param1, Param2 + ) + ) + if Param2 == self.ffic.KEY_LEFT: + self.cur_col -= 1 + elif Param2 == self.ffic.KEY_UP: + self.cur_row -= 1 + elif Param2 == self.ffic.KEY_RIGHT: + self.cur_col += 1 + elif Param2 == self.ffic.KEY_DOWN: + self.cur_row += 1 + elif Param2 == self.ffic.KEY_ENTER: + offset = self.cur_row * self.max_col + self.cur_col + self.text = self.symbols[offset] + log.debug( + "enter:{0} row:{1} col:{2}, ch:{3}".format( + offset, self.cur_row, self.cur_col, self.text + ) + ) + return 0 + elif Param2 == self.ffic.KEY_ESC: + return 0 + else: + return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) + if self.cur_col == self.max_col: + self.cur_col = 0 + elif self.cur_col == -1: + self.cur_col = self.max_col - 1 + if self.cur_row == self.max_row: + self.cur_row = 0 + elif self.cur_row == -1: + self.cur_row = self.max_row - 1 + self.Rebuild(hDlg) + return 1 + elif Msg == self.ffic.DN_MOUSECLICK: + log.debug( + "mou DialogProc({0}, {1}, {2}, {3})".format( + hDlg, "DN_MOUSECLICK", Param1, Param2 + ) + ) + ch = Param1 - self.first_text_item + if ch >= 0: + focus = self.info.SendDlgMessage(hDlg, self.ffic.DM_GETFOCUS, 0, 0) + log.debug("ch:{0} focus:{1}".format(ch, focus)) + if focus != self.first_text_item - 1: + self.info.SendDlgMessage( + hDlg, self.ffic.DM_SETFOCUS, self.first_text_item - 1, 0 + ) + self.cur_row = ch // self.max_col + self.cur_col = ch % self.max_col + self.cur_col = min(max(0, self.cur_col), self.max_col - 1) + self.cur_row = min(max(0, self.cur_row), self.max_row - 1) + offset = self.cur_row * self.max_col + self.cur_col + self.text = self.symbols[offset] + self.Rebuild(hDlg) + return 0 + return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) + + fdi = self.ffi.new("struct FarDialogItem []", Items) + hDlg = self.info.DialogInit( + self.info.ModuleNumber, + -1, + -1, + 42, + 20, + self.s2f("Character Map"), + fdi, + len(fdi), + 0, + 0, + DialogProc, + 0, + ) + res = self.info.DialogRun(hDlg) + if res == 1 and self.text: + self.info.FSF.CopyToClipboard(self.s2f(self.text)) + self.info.DialogFree(hDlg) diff --git a/python/configs/plug/plugins/udebug.py b/python/configs/plug/plugins/udebug.py index 26a1c4690..5d0baaf82 100644 --- a/python/configs/plug/plugins/udebug.py +++ b/python/configs/plug/plugins/udebug.py @@ -48,7 +48,7 @@ def debug(self): debugpy.wait_for_client() # debugpy.breakpoint() except: - log.exception() + log.exception('configured') finally: t.close() diff --git a/python/configs/plug/plugins/udocker.py b/python/configs/plug/plugins/udocker.py index 8913ac191..b83fb0aba 100644 --- a/python/configs/plug/plugins/udocker.py +++ b/python/configs/plug/plugins/udocker.py @@ -27,30 +27,6 @@ log = logging.getLogger(__name__) -TICKS_PER_SECOND = 10000000 -EPOCH_DIFFERENCE = 11644473600 - -FILE_ATTRIBUTE_READONLY = 0x00000001 -FILE_ATTRIBUTE_HIDDEN = 0x00000002 -FILE_ATTRIBUTE_SYSTEM = 0x00000004 -FILE_ATTRIBUTE_DIRECTORY = 0x00000010 -FILE_ATTRIBUTE_ARCHIVE = 0x00000020 -FILE_ATTRIBUTE_DEVICE = 0x00000040 -FILE_ATTRIBUTE_NORMAL = 0x00000080 -FILE_ATTRIBUTE_TEMPORARY = 0x00000100 -FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 -FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 -FILE_ATTRIBUTE_COMPRESSED = 0x00000800 -FILE_ATTRIBUTE_OFFLINE = 0x00001000 -FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 -FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 -FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x00008000 -FILE_ATTRIBUTE_VIRTUAL = 0x00010000 -FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x00020000 -FILE_ATTRIBUTE_BROKEN = 0x00200000 -FILE_ATTRIBUTE_EXECUTABLE = 0x00400000 - - class Plugin(PluginVFS): label = "Python Docker" openFrom = ["PLUGINSMENU", "DISKMENU"] @@ -63,12 +39,18 @@ def OpenPlugin(self, OpenFrom): self.devicepath = "/" return True + def devStart(self, name): + self.clt.start(name) + + def devStop(self, name): + self.clt.stop(name) + def devLoadDevices(self): for d in self.clt.list(): if d[2]: - self.addName(d[1], FILE_ATTRIBUTE_DIRECTORY, 0) + self.addName(d[1], self.ffic.FILE_ATTRIBUTE_DIRECTORY, 0) else: - self.addName(d[1], FILE_ATTRIBUTE_OFFLINE, 0) + self.addName(d[1], self.ffic.FILE_ATTRIBUTE_OFFLINE, 0) def devSelectDevice(self, name): self.device = None @@ -124,17 +106,17 @@ def addResult(self, result): if rec.st_name in (".", ".."): continue attr = 0 - attr |= FILE_ATTRIBUTE_DIRECTORY if rec.st_mode & stat.S_IFDIR else 0 - attr |= FILE_ATTRIBUTE_DEVICE if rec.st_mode & stat.S_IFCHR else 0 - attr |= FILE_ATTRIBUTE_ARCHIVE if rec.st_mode & stat.S_IFREG else 0 + attr |= self.ffic.FILE_ATTRIBUTE_DIRECTORY if rec.st_mode & stat.S_IFDIR else 0 + attr |= self.ffic.FILE_ATTRIBUTE_DEVICE if rec.st_mode & stat.S_IFCHR else 0 + attr |= self.ffic.FILE_ATTRIBUTE_ARCHIVE if rec.st_mode & stat.S_IFREG else 0 # log.debug('{} mode={:5o} attr={} perms={}'.format(rec.name, rec.mode, attr, rec.perms)) # datetime.datetime.fromtimestamp(rec.time).strftime('%Y-%m-%d %H:%M:%S') item = self.setName(i, rec.st_name, attr, rec.st_size) item.dwUnixMode = rec.st_mode t = ( - int(time.mktime(rec.st_mtime.timetuple())) + EPOCH_DIFFERENCE - ) * TICKS_PER_SECOND + int(time.mktime(rec.st_mtime.timetuple())) + self.ffic.EPOCH_DIFFERENCE + ) * self.ffic.TICKS_PER_SECOND item.ftLastWriteTime.dwHighDateTime = t >> 32 item.ftLastWriteTime.dwLowDateTime = t & 0xFFFFFFFF i += 1 @@ -166,58 +148,23 @@ def deleteNames(self, names): self.info.Control(self.hplugin, self.ffic.FCTL_REDRAWPANEL, 0, 0) return True - def Message(self, lines): - _MsgItems = [ - self.s2f("Docker"), - self.s2f(""), - ] - for line in lines: - _MsgItems.append(self.s2f(line)) - _MsgItems.extend( - [ - self.s2f(""), - self.s2f("\x01"), - self.s2f("&Ok"), - ] - ) - # log.debug('_msgItems: %s', _MsgItems) - MsgItems = self.ffi.new("wchar_t *[]", _MsgItems) - self.info.Message( - self.info.ModuleNumber, # GUID - self.ffic.FMSG_WARNING | self.ffic.FMSG_LEFTALIGN, # Flags - self.s2f("Contents"), # HelpTopic - MsgItems, # Items - len(MsgItems), # ItemsNumber - 1, # ButtonsNumber - ) - - def ConfirmDialog(self, title, lines): - _MsgItems = [ - self.s2f(title), - self.s2f(""), - ] - for line in lines: - _MsgItems.append(self.s2f(line)) - _MsgItems.extend( - [ - self.s2f(""), - self.s2f("\x01"), - self.s2f("&Cancel"), - self.s2f("&Ok"), - ] - ) - # log.debug('_msgItems: %s', _MsgItems) - MsgItems = self.ffi.new("wchar_t *[]", _MsgItems) + def Message(self, body, title="Docker", flags=0): + items = [] + if title: + items.extend([ + title, + ]) + items.extend([s for s in body.split('\n')]) + items = [self.s2f(s) for s in items] + MsgItems = self.ffi.new("wchar_t *[]", items) rc = self.info.Message( self.info.ModuleNumber, # GUID - self.ffic.FMSG_WARNING | self.ffic.FMSG_LEFTALIGN, # Flags - self.s2f("Contents"), # HelpTopic + flags, # Flags + self.ffi.NULL, # HelpTopic MsgItems, # Items len(MsgItems), # ItemsNumber - 2, # ButtonsNumber + 1, # ButtonsNumber ) - # 0 = Cancel, 1 = OK - # log.debug('confirm={}'.format(rc)) return rc def GetOpenPluginInfo(self, OpenInfo): @@ -268,18 +215,14 @@ def GetFindData(self, PanelItem, ItemsNumber, OpMode): self.devLoadDevices() except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False else: try: self.loadDirectory() except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False PanelItem = self.ffi.cast("struct PluginPanelItem **", PanelItem) ItemsNumber = self.ffi.cast("int *", ItemsNumber) @@ -319,9 +262,7 @@ def SetDirectory(self, Dir, OpMode): except Exception as ex: self.device = None log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False else: self.devicepath = os.path.join(self.devicepath, name) @@ -357,13 +298,25 @@ def GetFiles(self, PanelItem, ItemsNumber, Move, DestPath, OpMode): # super().GetFiles(PanelItem, ItemsNumber, Move, DestPath, OpMode) if ItemsNumber == 0 or Move: return False + items = self.ffi.cast("struct PluginPanelItem *", PanelItem) if self.device is None: - self.Message(["GetFiles allowed only inside device."]) + name = self.f2s(items[ItemsNumber-1].FindData.lpwszFileName) + yesno = self.Message(f"Device '{name}' is not started.\nStart it ?", flags=self.ffic.FMSG_MB_YESNO) + if yesno == 0: + # yes + log.debug(f'Start device: {name}') + try: + self.devStart(name) + except Exception as ex: + self.device = None + log.exception("start device:") + self.Message(str(ex), f"Start device '{name}' failed", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) + return False + return True return True # TODO dialog with copy parameters # TODO progress dialog # TODO copy in background - items = self.ffi.cast("struct PluginPanelItem *", PanelItem) DestPath = self.ffi.cast("wchar_t **", DestPath) dpath = self.ffi.string(DestPath[0]) # log.debug('GetFiles: {} {} OpMode={}'.format(ItemsNumber, OpMode, dpath)) @@ -378,9 +331,7 @@ def GetFiles(self, PanelItem, ItemsNumber, Move, DestPath, OpMode): self.devGetFile(sqname, dqname) except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False return True @@ -389,7 +340,7 @@ def PutFiles(self, PanelItem, ItemsNumber, Move, SrcPath, OpMode): if ItemsNumber == 0 or Move: return False if self.device is None: - self.Message(["PetFiles allowed only inside device."]) + self.Message("PutFiles allowed only inside device.", flags=self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return True items = self.ffi.cast("struct PluginPanelItem *", PanelItem) spath = self.f2s(SrcPath) @@ -404,9 +355,7 @@ def PutFiles(self, PanelItem, ItemsNumber, Move, SrcPath, OpMode): self.devPutFile(sqname, dqname) except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False return True @@ -414,16 +363,29 @@ def DeleteFiles(self, PanelItem, ItemsNumber, OpMode): # super().DeleteFiles(PanelItem, ItemsNumber, OpMode) if ItemsNumber == 0: return False + items = self.ffi.cast("struct PluginPanelItem *", PanelItem) if self.device is None: - self.Message(["DeleteFiles allowed only inside device."]) + name = self.f2s(items[ItemsNumber-1].FindData.lpwszFileName) + yesno = self.Message(f"Device '{name}' is started.\nStop it ?", flags=self.ffic.FMSG_MB_YESNO) + if yesno == 0: + # yes + log.debug(f'Stop device: {name}') + try: + self.devStop(name) + except Exception as ex: + self.device = None + log.exception("stopt device:") + self.Message(str(ex), f"Stop device '{name}' failed", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) + return False + return True return True - items = self.ffi.cast("struct PluginPanelItem *", PanelItem) if ItemsNumber > 1: - rc = self.ConfirmDialog("Delete", ["Do you wish to delete the files"]) + yesno = self.Message("Do you wish to delete the files ?", flags=self.ffic.FMSG_MB_YESNO) else: name = self.f2s(items[0].FindData.lpwszFileName) - rc = self.ConfirmDialog("Delete", ["Do you wish to delete the file", name]) - if rc != 1: + yesno = self.Message(f"Do you wish to delete the file:\n{name}", flags=self.ffic.FMSG_MB_YESNO) + if yesno == 1: + # no return True for i in range(ItemsNumber): name = self.f2s(items[i].FindData.lpwszFileName) @@ -435,16 +397,14 @@ def DeleteFiles(self, PanelItem, ItemsNumber, OpMode): self.devDelete(dqname) except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False return True def MakeDirectory(self, Name, OpMode): # super().DMakeDirectory(Name, OpMode) if self.device is None: - self.Message(["Make directory allowed only inside device."]) + self.Message("Make directory allowed only inside device.", flags=self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return True name = self.ffi.cast("wchar_t **", Name) name = self.ffi.string(name[0]) @@ -508,9 +468,7 @@ def DialogProc(hDlg, Msg, Param1, Param2): self.devMakeDirectory(dqname) except Exception as ex: log.exception("unknown exception:") - msg = str(ex).split("\n") - msg.insert(0, "Unknown exception.") - self.Message(msg) + self.Message(str(ex), "Unknown exception.", self.ffic.FMSG_MB_OK|self.ffic.FMSG_WARNING) return False self.info.DialogFree(dlg.hDlg) diff --git a/python/configs/plug/plugins/udockerio.py b/python/configs/plug/plugins/udockerio.py index 245a535e0..d7f9e5d94 100644 --- a/python/configs/plug/plugins/udockerio.py +++ b/python/configs/plug/plugins/udockerio.py @@ -98,16 +98,22 @@ def __str__(self): class Docker(object): - def __init__(self): - pass + def __init__(self, dockerexecutable="/usr/bin/docker"): + self.dockerexecutable = dockerexecutable - def run(self, *args, timeout=2): - cmd = ["/usr/bin/docker"] + def run(self, *args, timeout=2, stderr=False): + cmd = [self.dockerexecutable] cmd.extend(args) - # log.debug('docker.run: {}'.format(cmd)) + log.debug(f"docker.run: {cmd}") res = subprocess.run(cmd, capture_output=True, timeout=timeout) - log.debug("rc={} stderr={}".format(res.returncode, res.stderr.decode())) + log.debug(f"docker.run: rc={res.returncode}") res.check_returncode() + if stderr: + fp = io.BytesIO(res.stdout) + lines1 = fp.readlines() + fp = io.BytesIO(res.stderr) + lines2 = fp.readlines() + return lines1, lines2 assert res.stderr == b"" fp = io.BytesIO(res.stdout) lines = fp.readlines() @@ -131,6 +137,15 @@ def list(self): devices.append(info) return devices + def start(self, name): + self.run("container", "start", name) + + def stop(self, name): + self.run("container", "stop", name) + + def logs(self, name): + return self.run("container", "logs", name, stderr=True) + ls = "/bin/ls -anL --full-time {}" date_re = "%Y-%m-%d %H:%M:%S" file_re1 = r""" @@ -203,3 +218,6 @@ def remove(self, deviceid, dqname): result = cls.ls(info[0][0], "/") for e in result: print(e) + cls.stop('redmine') + cls.start('redmine') + cls.logs('redmine') diff --git a/python/configs/plug/plugins/ugtkhello.py b/python/configs/plug/plugins/ugtkhello.py index d5d49b765..1a47464c7 100644 --- a/python/configs/plug/plugins/ugtkhello.py +++ b/python/configs/plug/plugins/ugtkhello.py @@ -1,3 +1,4 @@ +import threading from far2l.plugin import PluginBase import gi @@ -33,6 +34,10 @@ class Plugin(PluginBase): def OpenPlugin(self, OpenFrom): if OpenFrom == 5: # EDITOR - win = MyWindow() - Gtk.main() + def proc(): + win = MyWindow() + Gtk.main() + t = threading.Thread(target=proc) + t.daemon = True + t.start() return -1 diff --git a/python/configs/plug/plugins/usizerflow.py b/python/configs/plug/plugins/usizerflow.py new file mode 100644 index 000000000..6b446a153 --- /dev/null +++ b/python/configs/plug/plugins/usizerflow.py @@ -0,0 +1,157 @@ +if 0: + import debugpy + + debugpy.listen(("127.0.0.1", 5678)) + debugpy.wait_for_client() + +import logging +from far2l.plugin import PluginBase +from far2l.fardialogbuilder import ( + Spacer, + TEXT, + EDIT, + PASSWORD, + MASKED, + MEMOEDIT, + BUTTON, + CHECKBOX, + RADIOBUTTON, + COMBOBOX, + LISTBOX, + USERCONTROL, + HLine, + HSizer, + VSizer, + FlowSizer, + DialogBuilder, +) + +log = logging.getLogger(__name__) + + +class Plugin(PluginBase): + label = "Python Dialog Demo" + openFrom = ["PLUGINSMENU", "COMMANDLINE", "EDITOR", "VIEWER"] + + def OpenPlugin(self, OpenFrom): + @self.ffi.callback("FARWINDOWPROC") + def DialogProc(hDlg, Msg, Param1, Param2): + if Msg == self.ffic.DN_INITDIALOG: + try: + dlg.SetText(dlg.ID_vapath, "vapath initial") + dlg.SetText(dlg.ID_vbpath, "vbpath initial") + dlg.Disable(dlg.ID_vbpath) + dlg.SetCheck(dlg.ID_vallow, 1) + dlg.SetFocus(dlg.ID_vseconds) + # override value from constructor + dlg.SetCheck(dlg.ID_vr1, self.ffic.BSTATE_CHECKED) + dlg.SetCheck(dlg.ID_vc3, self.ffic.BSTATE_CHECKED) + except: + log.exception("bang") + elif Msg == self.ffic.DN_BTNCLICK: + pass + elif Msg == self.ffic.DN_KEY: + if Param2 == self.ffic.KEY_LEFT: + pass + elif Param2 == self.ffic.KEY_UP: + pass + elif Param2 == self.ffic.KEY_RIGHT: + pass + elif Param2 == self.ffic.KEY_DOWN: + pass + elif Param2 == self.ffic.KEY_ENTER: + pass + elif Param2 == self.ffic.KEY_ESC: + pass + elif Msg == self.ffic.DN_MOUSECLICK: + pass + return self.info.DefDlgProc(hDlg, Msg, Param1, Param2) + + b = DialogBuilder( + self, + DialogProc, + "Python dialog", + "helptopic", + 0, + VSizer( + FlowSizer(3, + HSizer( + TEXT(None, "a path"), + EDIT("vapath", 33, maxlength=40), + ), + HSizer( + TEXT(None, "b path"), + EDIT("vbpath", 20), + ), + CHECKBOX("vallow", "Allow"), + HSizer( + TEXT(None, "Password"), + PASSWORD("vuserpass", 8, maxlength=15), + ), + HSizer( + TEXT(None, "Seconds"), + MASKED("vseconds", "9999"), + ), + VSizer( + RADIOBUTTON("vr1", "p1", flags=self.ffic.DIF_GROUP), + RADIOBUTTON("vr2", "p2"), + RADIOBUTTON("vr3", "p3", flags=self.ffic.BSTATE_CHECKED), + ), + LISTBOX( + "vlist", 1, "element A", "element B", "element C", "element D" + ), + COMBOBOX( + "vcombo", 2, "element A", "element B", "element C", "element D" + ), + VSizer( + CHECKBOX("vc1", "c1"), + CHECKBOX("vc2", "c2"), + CHECKBOX("vc3", "c3", flags=self.ffic.BSTATE_CHECKED), + ), + # TEXT(None, "X"), + ), + HLine(), + HSizer( + BUTTON("vok", "OK", default=True, flags=self.ffic.DIF_CENTERGROUP), + BUTTON("vcancel", "Cancel", flags=self.ffic.DIF_CENTERGROUP), + ), + ), + ) + # debugpy.breakpoint() + dlg = b.build(-1, -1) + + res = self.info.DialogRun(dlg.hDlg) + log.debug( + """\ +ok={} \ +a path=[{}] \ +b path=[{}] \ +allow={} \ +pass=[{}] \ +seconds=[{}] \ +radio1={} \ +radio2={} \ +radio3={} \ +checkbox1={} \ +checkbox2={} \ +checkbox3={} \ +vlist={} \ +vcombo={} \ +""".format( + res == dlg.ID_vok, + dlg.GetText(dlg.ID_vapath), + dlg.GetText(dlg.ID_vbpath), + dlg.GetCheck(dlg.ID_vallow), + dlg.GetText(dlg.ID_vuserpass), + dlg.GetText(dlg.ID_vseconds), + dlg.GetCheck(dlg.ID_vr1), + dlg.GetCheck(dlg.ID_vr2), + dlg.GetCheck(dlg.ID_vr3), + dlg.GetCheck(dlg.ID_vc1), + dlg.GetCheck(dlg.ID_vc2), + dlg.GetCheck(dlg.ID_vc3), + dlg.GetCurPos(dlg.ID_vlist), + dlg.GetCurPos(dlg.ID_vcombo), + ) + ) + self.info.DialogFree(dlg.hDlg) diff --git a/python/configs/plug/plugins/usqlite.py b/python/configs/plug/plugins/usqlite.py index 4d5076650..16aefdd5a 100644 --- a/python/configs/plug/plugins/usqlite.py +++ b/python/configs/plug/plugins/usqlite.py @@ -108,17 +108,19 @@ def GetOpenPluginInfo(self, OpenInfo): ColumnTypes = ','.join(ColumnTypes) ColumnWidths = ','.join(ColumnWidths) self.py_pm_titles = self.ffi.new("wchar_t *[]", py_pm_py_titles) + self.py_ColumnTypes = self.s2f(ColumnTypes) + self.py_ColumnWidths = self.s2f(ColumnWidths) py_pm = [ - self.s2f(ColumnTypes), # ColumnTypes - self.s2f(ColumnWidths), # ColumnWidths - self.py_pm_titles, # ColumnTitles - 0, # FullScreen - 0, # DetailedStatus - 0, # AlignExtensions - 0, # CaseConversion - self.ffi.NULL, # StatusColumnTypes - self.ffi.NULL, # StatusColumnWidths - [0,0], # Reserved + self.py_ColumnTypes, # ColumnTypes + self.py_ColumnWidths, # ColumnWidths + self.py_pm_titles, # ColumnTitles + 0, # FullScreen + 0, # DetailedStatus + 0, # AlignExtensions + 0, # CaseConversion + self.ffi.NULL, # StatusColumnTypes + self.ffi.NULL, # StatusColumnWidths + [0,0], # Reserved ] self.pm = self.ffi.new("struct PanelMode *", py_pm) @@ -144,6 +146,9 @@ def GetOpenPluginInfo(self, OpenInfo): ] self.kbt = self.ffi.new("struct KeyBarTitles *", self.py_kbt) + self.py_curdir = self.s2f(self.parent.dbname.split('/')[-1]) + self.py_paneltitle = self.s2f(self.paneltitle) + Info = self.ffi.cast("struct OpenPluginInfo *", OpenInfo) Info.Flags = ( self.ffic.OPIF_USEFILTER @@ -151,9 +156,9 @@ def GetOpenPluginInfo(self, OpenInfo): | self.ffic.OPIF_SHOWNAMESONLY ) Info.HostFile = self.ffi.NULL - Info.CurDir = self.s2f(self.parent.dbname.split('/')[-1]) - Info.Format = self.s2f(self.paneltitle) - Info.PanelTitle = self.s2f(self.paneltitle) + Info.CurDir = self.py_curdir + Info.Format = self.py_paneltitle + Info.PanelTitle = self.py_paneltitle #InfoLines #InfoLinesNumber Info.PanelModesArray = self.pm @@ -347,6 +352,9 @@ def GetOpenPluginInfo(self, OpenInfo): ] self.kbt = self.ffi.new("struct KeyBarTitles *", self.py_kbt) + self.py_curdir = self.s2f(self.parent.dbname.split('/')[-1]) + self.py_paneltitle = self.s2f(self.parent.label) + Info = self.ffi.cast("struct OpenPluginInfo *", OpenInfo) Info.Flags = ( self.ffic.OPIF_USEFILTER @@ -354,9 +362,9 @@ def GetOpenPluginInfo(self, OpenInfo): | self.ffic.OPIF_SHOWNAMESONLY ) Info.HostFile = self.ffi.NULL - Info.CurDir = self.s2f(self.parent.dbname.split('/')[-1]) - Info.Format = self.s2f(self.parent.label) - Info.PanelTitle = self.s2f(self.parent.label) + Info.CurDir = self.py_curdir + Info.Format = self.py_paneltitle + Info.PanelTitle = self.py_paneltitle #InfoLines #InfoLinesNumber Info.PanelModesArray = self.pm diff --git a/python/configs/plug/plugins/uvtlog.py b/python/configs/plug/plugins/uvtlog.py index 0d0495c8c..04586d4eb 100644 --- a/python/configs/plug/plugins/uvtlog.py +++ b/python/configs/plug/plugins/uvtlog.py @@ -15,34 +15,35 @@ def Perform(self): eur.Command = self.ffic.EUR_BEGIN self.info.EditorControl(self.ffic.ECTL_UNDOREDO, eur) - count = self.info.FSF.VTEnumBackground(self.ffi.NULL, 0) - if count > 0: - # why is it always equal to 0 ? - log.debug(f'VTEnumBackground={count}') - con_hnds = self.ffi.new("HANDLE []", count) - vtssize = self.info.FSF.VTEnumBackground(con_hnds, count) + if 0: + # get screen from background task + count = self.info.FSF.VTEnumBackground(self.ffi.NULL, 0) + if count > 0: + log.debug(f'VTEnumBackground={count}') + con_hnds = self.ffi.new("HANDLE []", count) + vtssize = self.info.FSF.VTEnumBackground(con_hnds, count) else: + # get screen from background like ctrl+o and F4 con_hnds = self.ffi.new("HANDLE []", 1) con_hnds[0] = self.ffi.NULL block = None with tempfile.NamedTemporaryFile(delete=False) as fp: fp.close() - os.unlink(fp.name) - try: - flags = self.ffic.VT_LOGEXPORT_COLORED - flags = self.ffic.VT_LOGEXPORT_WITH_SCREENLINES - except: - flags = 0 - vtssize = self.info.FSF.VTLogExport(con_hnds[0], flags, self.s2f(fp.name)) + #os.unlink(fp.name) + # what to include in screen dump ? + #flags = self.ffic.VT_LOGEXPORT_COLORED | self.ffic.VT_LOGEXPORT_WITH_SCREENLINES + flags = self.ffic.VT_LOGEXPORT_WITH_SCREENLINES + ok = self.info.FSF.VTLogExport(con_hnds[0], flags, self.s2f(fp.name)) with open(fp.name, mode='rb') as f: block = f.read() + block=block.replace(b'\x0a', b'\x0d') os.unlink(fp.name) try: block = block.decode('utf-8') except: - log.exception() + log.exception('block.decode') return s = self.s2f(block) self.info.EditorControl(self.ffic.ECTL_INSERTTEXT, s)