diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e6acf98a192763563c8ad340db87fd9df7aa31d9 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# GUI для конфигов + +## Как запустить? + +`pip install dearpygui` + +`git clone http://tesla.parallel.ru/kuzmichovamary/gui.git` + +`cd gui` + +`python run prerun.py` -- один раз (тут собирается `config-parser` ;) + +`python run app.py` + diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..604dbaf3c9978f378ef4a38c600b101af582fd55 --- /dev/null +++ b/app.py @@ -0,0 +1,212 @@ +import re +import ctypes + +import dearpygui.dearpygui as dpg + +from styles import GuiStyle, INDENT, SPACE, FONT_SIZE, ICON_PATH +from config import load_config, dump_config + +ctypes.windll.shcore.SetProcessDpiAwareness(1) + + +class ConfigEditor: + def __init__(self): + dpg.create_context() + + self.styles = GuiStyle() + self.config = dict() + self.config_file_path = "" + + self.construct_main_window() + + def delete_config_window_and_clear_aliases(self, file_path): + if dpg.does_item_exist(file_path): + dpg.delete_item(file_path) + if dpg.does_item_exist(f"{file_path}_tab_bar"): + dpg.delete_item(f"{file_path}_tab_bar") + if dpg.does_item_exist(f"{file_path}_tab"): + dpg.delete_item(f"{file_path}_tab") + + if dpg.does_alias_exist(file_path): + dpg.remove_alias(file_path) + if dpg.does_alias_exist(f"{file_path}_tab_bar"): + dpg.remove_alias(f"{file_path}_tab_bar") + if dpg.does_alias_exist(f"{file_path}_tab"): + dpg.remove_alias(f"{file_path}_tab") + for path in self.config: + namespaces = path.split('.') + for i in range(len(namespaces)): + path = self.config_file_path + '.' + '.'.join(namespaces[:i+1]) + if dpg.does_alias_exist(path): + dpg.remove_alias(path) + if dpg.does_alias_exist(f"{path}_tab_bar"): + dpg.remove_alias(f"{path}_tab_bar") + if dpg.does_alias_exist(f"{path}_tab"): + dpg.remove_alias(f"{path}_tab") + if dpg.does_alias_exist(f"{path}_text"): + dpg.remove_alias(f"{path}_text") + + def update_config(self): + for path in self.config: + self.config[path].value = dpg.get_value(f"{self.config_file_path}.{path}") + + def manage_file(self, sender, sender_data, user_data): + if user_data == "save": + if not self.config_file_path: + return + self.update_config() + dump_config(self.config, self.config_file_path) + dpg.show_item("file_save_popup") + return + + file_path = sender_data['file_path_name'] + + if user_data == "open": + self.delete_config_window_and_clear_aliases(self.config_file_path) + self.config_file_path = file_path + self.config = load_config(file_path) + self.construct_config_ui() + elif user_data == "save_as": + if not self.config_file_path: + return + self.update_config() + dump_config(config, file_path) + dpg.show_item("file_save_popup") + + def set_file_path(self, sender, sender_data, user_data): + file_path = sender_data['file_path_name'] + dpg.set_value(user_data, file_path) + + def open_file_dialog(self, sender, sender_data, user_data): + dpg.show_item("file_dialog") + dpg.set_item_user_data("file_dialog", user_data) + + def open_folder_dialog(self, sender, sender_data, user_data): + dpg.show_item("folder_dialog") + dpg.set_item_user_data("folder_dialog", user_data) + + def construct_config_ui(self): + self.delete_config_window_and_clear_aliases(self.config_file_path) + if dpg.get_value("use_tabs_ui"): + self.construct_config_ui_tabs() + else: + self.construct_config_ui_collapsing_headers() + + def construct_main_window(self): + dpg.bind_font(self.styles.montserrat_font) + dpg.bind_theme(self.styles.main_theme) + + with dpg.window(label="config file editor", pos=(10, 10), width=800, height=600, tag="main", menubar=True): + with dpg.menu_bar(): + with dpg.menu(label="file"): + dpg.add_menu_item(label="open", callback=self.open_file_dialog, tag="open_btn", user_data="open") + dpg.add_menu_item(label="save", callback=self.manage_file, tag="save_btn", user_data="save") + dpg.add_menu_item(label="save as", callback=self.open_file_dialog, tag="save_as_btn", user_data="save_as") + + with dpg.menu(label="view"): + dpg.add_menu_item(label="use default theme", check=True, callback=lambda _, v: dpg.bind_theme(None if v else self.styles.main_theme), default_value=False) + dpg.add_menu_item(label="use default font", check=True, callback=lambda _, v: dpg.bind_font(None if v else self.styles.montserrat_font), default_value=False) + dpg.add_menu_item(label="use tabs [all entered data will be lost]", check=True, callback=lambda: self.construct_config_ui(), default_value=False, tag="use_tabs_ui") + dpg.add_menu_item(label="show theme editor", callback=dpg.show_style_editor) + + with dpg.menu(label="settings"): + dpg.add_menu_item(label="auto save [not impl]", check=True, callback=lambda: print("TODO"), default_value=False) + + with dpg.file_dialog(directory_selector=False, show=False, callback=self.manage_file, tag="file_dialog", width=600, height=400): + dpg.add_file_extension(".txt", color=(0, 255, 0, 255)) + dpg.add_file_extension(".*", color=(255, 255, 255, 255)) + + with dpg.file_dialog(directory_selector=True, show=False, callback=self.set_file_path, tag="folder_dialog", width=500, height=400): + dpg.add_file_extension(".*", color=(255, 255, 255, 255)) + + with dpg.window(label="", autosize=True, no_resize=True, modal=True, tag="file_save_popup", show=False, pos=(40, 40)): + dpg.add_text("file saved successfully:)") + + def construct_config_ui_collapsing_headers(self): + dpg.add_collapsing_header(label=self.config_file_path, parent="main", tag=self.config_file_path, indent=0, default_open=True) + + for full_path in self.config: + namespaces = full_path.split('.') + parent = self.config_file_path + for level in range(len(namespaces) - 1): + path = self.config_file_path + '.' + '.'.join(namespaces[:level+1]) + + if not dpg.does_item_exist(path): + dpg.add_collapsing_header(label=namespaces[level], parent=parent, tag=path, indent=INDENT) + + parent = path + + self.create_widget(full_path) + + def check_tabview(self, root): + for uuid in dpg.get_item_children(root, 1): + if dpg.get_item_type(uuid) == "mvAppItemType::mvTabBar": + return True, uuid + return False, None + + def construct_config_ui_tabs(self): + tab_bar_exists, tab_bar_uuid = self.check_tabview("main") + if not tab_bar_exists: + tab_bar_uuid = dpg.add_tab_bar(parent="main", tag=f"{self.config_file_path}_tab_bar") + dpg.add_tab(label=self.config_file_path, parent=tab_bar_uuid, tag=f"{self.config_file_path}_tab") + dpg.add_child_window(parent=f"{self.config_file_path}_tab", tag=self.config_file_path, border=True, autosize_y=True, autosize_x=True) + + for full_path in self.config: + namespaces = full_path.split('.') + parent = self.config_file_path + for level in range(len(namespaces) - 1): + path = self.config_file_path + '.' + '.'.join(namespaces[:level+1]) + + tab_bar_exists, tab_bar_uuid = self.check_tabview(parent) + + if not tab_bar_exists: + tab_bar_uuid = dpg.add_tab_bar(parent=parent, tag=f"{path}_tab_bar") + dpg.set_item_height(parent, dpg.get_item_height(parent) + 4 * SPACE + FONT_SIZE) + + if not dpg.does_item_exist(path): + dpg.add_tab(label=namespaces[level], parent=tab_bar_uuid, tag=f"{path}_tab") + dpg.add_child_window(parent=f"{path}_tab", tag=path, border=True, autosize_y=False, autosize_x=True, height=2 * SPACE) + + parent = path + + self.create_widget(full_path) + + def create_widget(self, full_path): + tag = self.config_file_path + '.' + full_path + parent = '.'.join([self.config_file_path] + full_path.split('.')[:-1]) + + if dpg.get_value("use_tabs_ui") and parent != self.config_file_path: + dpg.set_item_height(parent, dpg.get_item_height(parent) + 2 * SPACE + FONT_SIZE + SPACE) + + value = self.config[full_path].value + value_type = self.config[full_path].value_type + key = self.config[full_path].key + comment = self.config[full_path].comment + + with dpg.group(horizontal=True, parent=parent, indent=INDENT): + dpg.add_text(key, tag=f"{tag}_text") + if value_type == 'BOOLEAN': + dpg.add_checkbox(default_value=value, tag=tag) + elif value_type == 'DOUBLE': + dpg.add_input_double(default_value=value, tag=tag, format="%.10f") + elif value_type == 'INT': + dpg.add_input_int(default_value=value, tag=tag) + elif "dir" in key.lower(): + dpg.add_input_text(default_value=value, tag=tag) + dpg.add_button(label="...", callback=self.open_folder_dialog, user_data=tag) + else: + dpg.add_input_text(default_value=value, tag=tag) + if comment: + dpg.add_text(comment, parent=dpg.add_tooltip(parent=f"{tag}_text")) + + def run(self): + dpg.create_viewport(title='config file editor', width=800, height=600, small_icon=ICON_PATH) + dpg.setup_dearpygui() + dpg.show_viewport() + dpg.set_primary_window("main", True) + dpg.start_dearpygui() + dpg.destroy_context() + +if __name__ == "__main__": + app = ConfigEditor() + app.run() diff --git a/config-parser/cfg-var.o b/config-parser/cfg-var.o deleted file mode 100644 index 20eaa8dd91d4f24f5c227ebb0ca3bcefe6afe9e6..0000000000000000000000000000000000000000 Binary files a/config-parser/cfg-var.o and /dev/null differ diff --git a/config-parser/config-parser.o b/config-parser/config-parser.o deleted file mode 100644 index eb2c5d6b0a801b85f6ce64cf6cd0d996adb3bfa9..0000000000000000000000000000000000000000 Binary files a/config-parser/config-parser.o and /dev/null differ diff --git a/config-parser/mem-stx.o b/config-parser/mem-stx.o deleted file mode 100644 index 55c9bcc9447178b8fc5a061ebb5c477a27115342..0000000000000000000000000000000000000000 Binary files a/config-parser/mem-stx.o and /dev/null differ diff --git a/config-parser/parser-cli b/config-parser/parser-cli deleted file mode 100644 index 38c03d5d9b3c9e7f11d7a2d5bd1334c9736bfc55..0000000000000000000000000000000000000000 Binary files a/config-parser/parser-cli and /dev/null differ diff --git a/config-parser/parser-cli.cpp b/config-parser/parser-cli.cpp index 0b0044e4d7f5d4641c6a26942ef8dd1f236a0303..c732307f443308688b211b5a6a0bedbdec800115 100644 --- a/config-parser/parser-cli.cpp +++ b/config-parser/parser-cli.cpp @@ -3,11 +3,11 @@ #include "config-parser.h" void print_usage(const char* prog_name) { - std::cout << "Usage: " << prog_name << " <filename> <variable_name>" << std::endl; + std::cout << "usage: " << prog_name << " <filename>\n"; } int main(int argc, char* argv[]) { - if (argc < 2) { + if (argc != 2) { print_usage(argv[0]); return 1; } @@ -16,54 +16,12 @@ int main(int argc, char* argv[]) { const char* filename = argv[1]; nse::ConfigParser parser; if (!parser.run(filename)) { - std::cerr << "failed to parse the configuration file: " << filename << std::endl; + std::cerr << "failed to parse the configuration file: " << filename << "\n"; return 1; } parser.print(); return 0; } - const char* filename = argv[1]; - const char* varname = argv[2]; - - nse::ConfigParser parser; - - if (!parser.run(filename)) { - std::cerr << "failed to parse the configuration file: " << filename << std::endl; - return 1; - } - - if (!parser.is_varname(varname)) { - std::cerr << "variable " << varname << " not found in the configuration file." << std::endl; - return 1; - } - - parser.print(); - - nse::cfgVariable variable = parser.get_variable(varname); - - variable.print(); - - // int int_val; - // float float_val; - // double double_val; - // std::string string_val; - // bool bool_val; - - // if (parser.get_value(varname, &int_val)) { - // std::cout << "Value: " << int_val << std::endl; - // } else if (parser.get_value(varname, &float_val)) { - // std::cout << "Value: " << float_val << std::endl; - // } else if (parser.get_value(varname, &double_val)) { - // std::cout << "Value: " << double_val << std::endl; - // } else if (parser.get_value(varname, string_val)) { - // std::cout << "Value: " << string_val << std::endl; - // } else if (parser.get_value(varname, &bool_val)) { - // std::cout << "Value: " << (bool_val ? "true" : "false") << std::endl; - // } else { - // std::cerr << "Failed to get the value for variable " << varname << "." << std::endl; - // return 1; - // } - return 0; } diff --git a/config-parser/parser-cli.exe b/config-parser/parser-cli.exe deleted file mode 100644 index 55c8e34fa0a08e91616caab205c747882ed83a71..0000000000000000000000000000000000000000 Binary files a/config-parser/parser-cli.exe and /dev/null differ diff --git a/config-parser/parser-cli.o b/config-parser/parser-cli.o deleted file mode 100644 index 631a48ca271ca50a2d8e025204928afa2f6a9722..0000000000000000000000000000000000000000 Binary files a/config-parser/parser-cli.o and /dev/null differ diff --git a/config-parser/str-com.o b/config-parser/str-com.o deleted file mode 100644 index 8c2c3763be9e28d7bbfb6851e5e90bc9dddaad2f..0000000000000000000000000000000000000000 Binary files a/config-parser/str-com.o and /dev/null differ diff --git a/config.py b/config.py new file mode 100644 index 0000000000000000000000000000000000000000..e910835ea7f135174d59c63c0da322e71e29ca86 --- /dev/null +++ b/config.py @@ -0,0 +1,238 @@ +import re +import subprocess +import os +from enum import Enum + + +class CfgVar: + def __init__(self, key, value=None, value_type='STRING', comment=""): + self.key = key + self.value = value + self.value_type = value_type + self.comment = comment + + def __repr__(self): + return f"CfgVar(key={self.key}, value={self.value}, comment={self.comment})" + + +TokenType = Enum('TokenType', ['BRACE_OPEN', 'BRACE_CLOSE', 'VARIABLE', 'NAMESPACE']) + + +class Token: + def __init__(self, type): + self.type = type + + def __repr__(self): + return str(self.type) + + +class Variable(Token): + def __init__(self, name, comment=""): + super().__init__(TokenType.VARIABLE) + self.name = name + self.comment = comment + + def __repr__(self): + return f"VAR {self.name} [{self.comment}]" + + +class Namespace(Token): + def __init__(self, name): + super().__init__(TokenType.NAMESPACE) + self.name = name + + def __repr__(self): + return f"NAMESPACE {self.name}" + + +def tokenize(file_path): + text = "" + if os.path.exists(file_path): + text = open(file_path, "r", encoding="utf-8").read() + + tokens = [] + it = text.__iter__() + + try: + char = it.__next__() + while True: + if char == "{": + tokens.append(Token(TokenType.BRACE_OPEN)) + char = it.__next__() + elif char == "}": + tokens.append(Token(TokenType.BRACE_CLOSE)) + char = it.__next__() + elif char.isalpha(): + name = char + + char = it.__next__() + while char.isalnum() or char == "_" or char == ".": + name += char + char = it.__next__() + + char = it.__next__() + while char in (" ", "\t"): + char = it.__next__() + + if char == "=": + tokens.append(Variable(name)) + + char = it.__next__() + while char != ";": + char = it.__next__() + + char = it.__next__() + while char in (" ", "\t"): + char = it.__next__() + + if char == "#": + + char = it.__next__() + + while char in (" ", "\t"): + char = it.__next__() + + comment = "" + + while char != "\n": + comment += char + char = it.__next__() + + if tokens[-1].type == TokenType.VARIABLE: + tokens[-1].comment = comment + + char = it.__next__() + else: + tokens.append(Namespace(name)) + elif char == "#": + while char != "\n": + char = it.__next__() + char = it.__next__() + else: + char = it.__next__() + except StopIteration as e: + return tokens + + +def parse(file_path): + stack = [] + + data = dict() + + tokens = tokenize(file_path) + it = tokens.__iter__() + + try: + while True: + token = it.__next__() + if token.type == TokenType.NAMESPACE: + stack.append(token.name) + + if token.type == TokenType.BRACE_CLOSE: + stack.pop() + + if token.type == TokenType.VARIABLE: + if stack: + path = '.'.join(stack) + f'.{token.name}' + else: + path = token.name + data[path] = CfgVar(token.name, comment=token.comment) + except StopIteration as e: + return data + + +def load_config(file_path): + config = parse(file_path) + + output = subprocess.run(["config-parser/parser-cli", file_path], capture_output=True, text=True) + + for line in output.stdout.split("\n"): + match = re.match(r" > (\w+) '(.*)' = *(.*)", line) + if match: + value_type, path, value = match.groups() + config[path].value = get_value_from_str(value, value_type) + config[path].value_type = value_type + + return config + +def construct_nested_dict(config): + config_nested = dict() + for path in config: + nss = path.split(".") + + cur_ns = config_nested + + for ns in nss[:-1]: + if ns not in cur_ns: + cur_ns[ns] = {} + + cur_ns = cur_ns[ns] + + cur_ns[nss[-1]] = config[path] + return config_nested + +def get_str_from_value(value, value_type): + if not value: + if value_type == 'STRING': + return '""' + elif value_type == 'INT': + return '0' + elif value_type == 'DOUBLE': + return '0.0' + elif value_type == 'BOOLEAN': + return 'false' + else: + if value_type == 'STRING': + return f'"{value}"' + elif value_type == 'BOOLEAN': + return str(value).lower() + elif value_type == 'DOUBLE': + return "{:.7f}".format(float(value)) + return str(value) + +def get_value_from_str(string, value_type): + if not string: + if value_type == 'STRING': + return "" + elif value_type == 'INT': + return 0 + elif value_type == 'DOUBLE': + return 0.0 + elif value_type == 'BOOLEAN': + return False + else: + if value_type == 'STRING': + return string + elif value_type == 'BOOLEAN': + return string == 'true' + elif value_type == 'DOUBLE': + return float(string) + elif value_type == 'INT': + return int(string) + +def write_namespace(file, ns, ns_name, indent): + file.write("\n") + file.write(" " * indent + ns_name + "\n") + file.write(" " * indent + "{\n") + for key in ns: + if isinstance(ns[key], dict): + write_namespace(file, ns[key], key, indent + 4) + else: + file.write(" " * (indent + 4) + f"{key} = {get_str_from_value(ns[key].value, ns[key].value_type)};\n") + file.write(" " * indent + "}\n") + file.write("\n") + +def dump_config(config, file_path): + config_nested = construct_nested_dict(config) + + indent = 0 + with open(file_path, "w", encoding="utf-8") as file: + for key in config_nested: + if isinstance(config_nested[key], dict): + write_namespace(file, config_nested[key], key, indent) + else: + file.write(f"{key} = {get_str_from_value(config_nested[key].value, config_nested[key].value_type)};\n") + + +if __name__ == '__main__': + print(load_config('config.txt')) \ No newline at end of file diff --git a/config_manager.py b/config_manager.py deleted file mode 100644 index 567d99ff25b26cc1ebb34245d87fac4cc7d2c225..0000000000000000000000000000000000000000 --- a/config_manager.py +++ /dev/null @@ -1,91 +0,0 @@ -import re -import subprocess - -class ConfigManager: - def __init__(self, func): - self.file_path = "" - self.get_value_func = func - self.lines = [] - self.config_data = {} - - def is_initialized(self): - return self.file_path != "" - - def init(self, file_path): - self.lines = [] - self.config_data = {} - self.file_path = file_path - - output = subprocess.run(["config-parser/parser-cli", self.file_path], capture_output=True, text=True) - - for line in output.stdout.split("\n"): - match = re.match(r" > (\w+) '(.*)' = *(.*)", line) - if match: - self.lines.append(match.groups()) - - def construct_dict(self): - if self.config_data: - return - - for value_type, path, value in self.lines: - nss = path.split(".") - - cur_ns = self.config_data - - for ns in nss[:-1]: - if ns not in cur_ns: - cur_ns[ns] = {} - - cur_ns = cur_ns[ns] - - cur_ns[nss[-1]] = (path, value_type) - - def get_value_str(self, path, value_type): - value = self.get_value_func(path, value_type) - if not value: - if value_type == 'STRING': - return '""' - elif value_type == 'INT': - return '0' - elif value_type == 'DOUBLE': - return '0.0' - elif value_type == 'BOOLEAN': - return 'false' - else: - if value_type == 'STRING': - return f'"{value}"' - elif value_type == 'BOOLEAN': - return str(value).lower() - elif value_type == 'DOUBLE': - return "{:.7f}".format(value) - return str(value) - - def write_namespace(self, file, ns, ns_name, indent): - file.write("\n") - file.write(" " * indent + ns_name + "\n") - file.write(" " * indent + "{\n") - for key in ns: - if isinstance(ns[key], dict): - self.write_namespace(file, ns[key], key, indent + 4) - else: - file.write(" " * (indent + 4) + f"{key} = {self.get_value_str(*ns[key])};\n") - file.write(" " * indent + "}\n") - file.write("\n") - - def save(self): - self.save_as(self.file_path) - - def save_as(self, file_path): - self.construct_dict() - - indent = 0 - with open(file_path, "w", encoding="utf-8") as file: - for key in self.config_data: - if isinstance(self.config_data[key], dict): - self.write_namespace(file, self.config_data[key], key, indent) - else: - file.write(f"{key} = {self.get_value_str(*self.config_data[key])};\n") - -# file_path = "config.txt" -# cfg_manager = ConfigManager(file_path, lambda p, t: t[0]) -# cfg_manager.save_config("config_my.txt") \ No newline at end of file diff --git a/dpg_gui_tabs.py b/dpg_gui_tabs.py deleted file mode 100644 index 8c7712179cf8361802c1f2aab0160d97f3994657..0000000000000000000000000000000000000000 --- a/dpg_gui_tabs.py +++ /dev/null @@ -1,129 +0,0 @@ -import dearpygui.dearpygui as dpg -import re -import ctypes -from dpg_gui_styles import GuiStyle, INDENT -from config_manager import ConfigManager - -ctypes.windll.shcore.SetProcessDpiAwareness(1) - -class ConfigEditor: - def __init__(self): - dpg.create_context() - - self.styles = GuiStyle() - - self.cfg_manager = ConfigManager(self.get_value) - - self.construct_main_window() - - dpg.bind_font(self.styles.montserrat_font) - dpg.bind_theme(self.styles.main_theme) - - dpg.create_viewport(title='config file editor', width=800, height=600, small_icon='icon.ico') - dpg.setup_dearpygui() - dpg.show_viewport() - dpg.set_primary_window("main", True) - - def manage_file(self, sender, app_data, user_data): - file_path = app_data['file_path_name'] - - if user_data == "open": - if self.cfg_manager.is_initialized(): - dpg.delete_item(self.cfg_manager.file_path) - if dpg.does_alias_exist(self.cfg_manager.file_path): - dpg.remove_alias(self.cfg_manager.file_path) - for _, path, _ in self.cfg_manager.lines: - namespaces = path.split('.') - for i in range(len(namespaces)): - path = '.'.join(namespaces[:i+1]) - if dpg.does_alias_exist(path): - dpg.remove_alias(path) - - self.cfg_manager.init(file_path) - self.construct_config_window() - elif user_data == "save_as": - self.cfg_manager.save_as(file_path) - - def set_file_path(self, sender, app_data, user_data): - file_path = app_data['file_path_name'] - dpg.set_value(user_data, file_path) - - def get_value(self, path, value_type): - return dpg.get_value(path) - - def open_file_dialog(self, sender, app_data, user_data): - dpg.show_item("file_dialog") - dpg.set_item_user_data("file_dialog", user_data) - - def open_folder_dialog(self, sender, app_data, user_data): - dpg.show_item("folder_dialog") - dpg.set_item_user_data("folder_dialog", user_data) - - def construct_main_window(self): - with dpg.window(label="config file editor", width=800, height=600, tag="main", menubar=True, no_resize=False, no_close=False, no_move=False, no_collapse=False): - with dpg.menu_bar(): - with dpg.menu(label="file"): - dpg.add_menu_item(label="open", callback=self.open_file_dialog, tag="open_btn", user_data="open") - dpg.add_menu_item(label="save", callback=self.cfg_manager.save, tag="save_btn") - dpg.add_menu_item(label="save as", callback=self.open_file_dialog, tag="save_as_btn", user_data="save_as") - - with dpg.menu(label="view"): - dpg.add_menu_item(label="use default theme", check=True, callback=lambda _, v: dpg.bind_theme(None if v else self.styles.main_theme), default_value=False) - dpg.add_menu_item(label="use default font", check=True, callback=lambda _, v: dpg.bind_font(None if v else self.styles.montserrat_font), default_value=False) - dpg.add_menu_item(label="show theme editor", callback=dpg.show_style_editor) - - with dpg.menu(label="settings"): - dpg.add_menu_item(label="auto save [not impl]", check=True, callback=lambda: print("TODO"), default_value=False) - - with dpg.file_dialog(directory_selector=False, show=False, callback=self.manage_file, tag="file_dialog", width=500, height=400): - dpg.add_file_extension(".txt", color=(0, 255, 0, 255)) - dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - - with dpg.file_dialog(directory_selector=True, show=False, callback=self.set_file_path, tag="folder_dialog", width=500, height=400): - dpg.add_file_extension(".*", color=(255, 255, 255, 255)) - - def construct_config_window(self): - dpg.add_collapsing_header(label=self.cfg_manager.file_path, parent="main", tag=self.cfg_manager.file_path, indent=0, default_open=True) - - for var_type, full_path, value in self.cfg_manager.lines: - namespaces = full_path.split('.') - parent = self.cfg_manager.file_path - for level in range(len(namespaces) - 1): - path = '.'.join(namespaces[:level+1]) - - if not dpg.does_item_exist(path): - dpg.add_collapsing_header(label=namespaces[level], parent=parent, tag=path, indent=INDENT) - - parent = path - - self.create_widget('.'.join(namespaces[:-1]), namespaces[-1], value, var_type) - - def create_widget(self, path, key, value, value_type): - if path: - parent = path - tag = f"{path}.{key}" - else: - parent = self.cfg_manager.file_path - tag = key - - with dpg.group(horizontal=True, parent=parent, indent=INDENT): - dpg.add_text(key) - if value_type == 'BOOLEAN': - dpg.add_checkbox(default_value=(value.lower() == "true"), tag=tag) - elif value_type == 'DOUBLE': - dpg.add_input_double(default_value=float(value), tag=tag, format="%.10f") - elif value_type == 'INT': - dpg.add_input_int(default_value=int(value), tag=tag) - elif "dir" in key.lower(): - dpg.add_input_text(default_value=value, tag=tag) - dpg.add_button(label="...", callback=self.open_folder_dialog, user_data=tag) - else: - dpg.add_input_text(default_value=value, tag=tag) - - def run(self): - dpg.start_dearpygui() - dpg.destroy_context() - -if __name__ == "__main__": - app = ConfigEditor() - app.run() diff --git a/dpygui.py b/dpygui.py deleted file mode 100644 index d8ea5b36bbfd4313b817b94a78b632a5274b6823..0000000000000000000000000000000000000000 --- a/dpygui.py +++ /dev/null @@ -1,100 +0,0 @@ -import dearpygui.dearpygui as dpg -import dearpygui.demo as demo - -dpg.create_context() -dpg.create_viewport(title='Custom Title', width=600, height=600) - -demo.show_demo() - -dpg.setup_dearpygui() -dpg.show_viewport() -dpg.set_primary_window("__demo_id", True) -dpg.start_dearpygui() -dpg.destroy_context() - -# List of default style items in Dear PyGui -style_items = [ - dpg.mvStyleVar_Alpha, - dpg.mvStyleVar_WindowPadding, - dpg.mvStyleVar_WindowRounding, - dpg.mvStyleVar_WindowBorderSize, - dpg.mvStyleVar_WindowMinSize, - dpg.mvStyleVar_WindowTitleAlign, - dpg.mvStyleVar_ChildRounding, - dpg.mvStyleVar_ChildBorderSize, - dpg.mvStyleVar_PopupRounding, - dpg.mvStyleVar_PopupBorderSize, - dpg.mvStyleVar_FramePadding, - dpg.mvStyleVar_FrameRounding, - dpg.mvStyleVar_FrameBorderSize, - dpg.mvStyleVar_ItemSpacing, - dpg.mvStyleVar_ItemInnerSpacing, - dpg.mvStyleVar_IndentSpacing, - dpg.mvStyleVar_CellPadding, - dpg.mvStyleVar_ScrollbarSize, - dpg.mvStyleVar_ScrollbarRounding, - dpg.mvStyleVar_GrabMinSize, - dpg.mvStyleVar_GrabRounding, - dpg.mvStyleVar_TabRounding, - dpg.mvStyleVar_ButtonTextAlign, - dpg.mvStyleVar_SelectableTextAlign -] - -# # Function to print default styles -# def print_default_styles(): -# for item in dpg.get_all_items(): -# print(dpg.get_item_info(item)) -# print(dpg.get_item_theme(item)) - - - -# import dearpygui.dearpygui as dpg - -# dpg.create_context() - -# with dpg.window(label="Tutorial", pos=(20, 50), width=275, height=225) as win1: -# t1 = dpg.add_input_text(default_value="some text") -# t2 = dpg.add_input_text(default_value="some text") -# with dpg.tab_bar(reorderable=True): -# with dpg.tab(label="Tab 1"): -# dpg.add_text("This is Tab 1") -# with dpg.tab(label="Tab 2"): -# dpg.add_text("This is Tab 2") -# with dpg.tab(label="Tab 3"): -# dpg.add_text("This is Tab 3") -# dpg.add_input_text(default_value="some text") - -# with dpg.window(label="Tutorial", pos=(320, 50), width=275, height=225) as win2: -# dpg.add_input_text(default_value="some text") -# dpg.add_input_int() - -# with dpg.theme() as container_theme: - -# with dpg.theme_component(dpg.mvAll): -# dpg.add_theme_color(dpg.mvThemeCol_Tab, (150, 100, 100), category=dpg.mvThemeCat_Core) -# dpg.add_theme_style(dpg.dpg.mvStyleVar_FrameRounding, 5, category=dpg.mvThemeCat_Core) - -# with dpg.theme_component(dpg.mvInputInt): -# dpg.add_theme_color(dpg.mvThemeCol_FrameBg, (100, 150, 100), category=dpg.mvThemeCat_Core) -# dpg.add_theme_style(dpg.dpg.mvStyleVar_FrameRounding, 5, category=dpg.mvThemeCat_Core) - -# dpg.bind_item_theme(win1, container_theme) -# dpg.bind_theme(container_theme) - -# dpg.create_viewport(title='Custom Title', width=800, height=600) -# dpg.setup_dearpygui() -# dpg.show_viewport() -# dpg.start_dearpygui() -# dpg.destroy_context() - -# import dearpygui.dearpygui as dpg - -# dpg.create_context() -# dpg.create_viewport() -# dpg.setup_dearpygui() - -# dpg.show_font_manager() - -# dpg.show_viewport() -# dpg.start_dearpygui() -# dpg.destroy_context() \ No newline at end of file diff --git a/fonts/Montserrat-Medium.ttf b/fonts/Montserrat-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dfc7e2fc59dfbfaf577dc2777f6bb910a6d04d1f Binary files /dev/null and b/fonts/Montserrat-Medium.ttf differ diff --git a/icon.ico b/icons/icon.ico similarity index 100% rename from icon.ico rename to icons/icon.ico diff --git a/prerun.py b/prerun.py new file mode 100644 index 0000000000000000000000000000000000000000..ad253af620e7981a9c14737483ba14132382754e --- /dev/null +++ b/prerun.py @@ -0,0 +1,10 @@ +import os +import subprocess + +os.chdir(os.path.join(os.getcwd(), 'config-parser')) +subprocess.run(['g++', '-std=c++11', '-Wall', '-DEXCLUDE_GPU_BRANCH', '-c', 'parser-cli.cpp', '-o', 'parser-cli.o']) +subprocess.run(['g++', '-std=c++11', '-Wall', '-DEXCLUDE_GPU_BRANCH', '-c', 'config-parser.cpp', '-o', 'config-parser.o']) +subprocess.run(['g++', '-std=c++11', '-Wall', '-DEXCLUDE_GPU_BRANCH', '-c', 'cfg-var.cpp', '-o', 'cfg-var.o']) +subprocess.run(['g++', '-std=c++11', '-Wall', '-DEXCLUDE_GPU_BRANCH', '-c', 'str-com.cpp', '-o', 'str-com.o']) +subprocess.run(['g++', '-std=c++11', '-Wall', '-DEXCLUDE_GPU_BRANCH', '-o', 'parser-cli', 'parser-cli.o', 'config-parser.o', 'cfg-var.o', 'str-com.o']) +os.chdir('..') \ No newline at end of file diff --git a/dpg_gui_styles.py b/styles.py similarity index 87% rename from dpg_gui_styles.py rename to styles.py index c449d189a47f14778f832fbfbb0dfed80463c5b1..adbc8bd92d5c0257f08f5c1156b9b17189c4ce8f 100644 --- a/dpg_gui_styles.py +++ b/styles.py @@ -1,15 +1,17 @@ import dearpygui.dearpygui as dpg -FONT_PATH = "D:\\fonts\\Montserrat\\static\\Montserrat-Medium.ttf" +FONT_PATH = "fonts\\Montserrat-Medium.ttf" +FONT_SIZE = 24 ACCENT_COLOR = (0, 119, 200, 100) ROUNDING = 10 SPACE = 10 INDENT = 40 +ICON_PATH = "icons\\icon.ico" class GuiStyle: def __init__(self): self.font_registry = dpg.add_font_registry() - self.montserrat_font = dpg.add_font(FONT_PATH, 24, parent=self.font_registry) + self.montserrat_font = dpg.add_font(FONT_PATH, FONT_SIZE, parent=self.font_registry) self.main_theme = dpg.add_theme() theme_all = dpg.add_theme_component(dpg.mvAll, parent=self.main_theme, tag="theme_all") @@ -59,4 +61,5 @@ class GuiStyle: dpg.add_theme_style(dpg.mvStyleVar_IndentSpacing, 30, category=dpg.mvThemeCat_Core, parent=theme_all) dpg.add_theme_style(dpg.mvStyleVar_ChildBorderSize, 3, category=dpg.mvThemeCat_Core, parent=theme_all) dpg.add_theme_style(dpg.mvStyleVar_WindowBorderSize, 0, category=dpg.mvThemeCat_Core, parent=theme_all) - dpg.add_theme_style(dpg.mvStyleVar_FrameBorderSize, 0, category=dpg.mvThemeCat_Core, parent=theme_all) \ No newline at end of file + dpg.add_theme_style(dpg.mvStyleVar_FrameBorderSize, 0, category=dpg.mvThemeCat_Core, parent=theme_all) + dpg.add_theme_style(dpg.mvStyleVar_WindowMinSize, 200, 200, category=dpg.mvThemeCat_Core, parent=theme_all) \ No newline at end of file