Skip to content

Commit 1fa9757

Browse files
authored
Merge pull request #26 from sysprog21/improve-gui
Enhance guiconfig experience
2 parents 7bbdb83 + b228109 commit 1fa9757

File tree

1 file changed

+164
-43
lines changed

1 file changed

+164
-43
lines changed

guiconfig.py

Lines changed: 164 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ def _main():
139139
# Label with status text shown at the bottom of the main window
140140
# ("Modified", "Saved to ...", etc.)
141141
#
142+
# _stats_label:
143+
# Label showing statistics (symbol count, changed count) in the status bar
144+
#
142145
# _id_to_node:
143146
# We can't use Node objects directly as Treeview item IDs, so we use their
144147
# id()s instead. This dictionary maps Node id()s back to Nodes. (The keys
@@ -182,10 +185,12 @@ def menuconfig(kconf):
182185
global _minconf_filename
183186
global _jump_to_tree
184187
global _cur_menu
188+
global _tree_row_index
185189

186190
_kconf = kconf
187191

188192
_jump_to_tree = None
193+
_tree_row_index = 0
189194

190195
_create_id_to_node()
191196

@@ -315,6 +320,7 @@ def _create_ui():
315320
_fix_treeview_issues()
316321

317322
_create_top_widgets()
323+
_create_menubar()
318324
# Create the pane with the Kconfig tree and description text
319325
panedwindow, _tree = _create_kconfig_tree_and_desc(_root)
320326
panedwindow.grid(column=0, row=1, sticky="nsew")
@@ -482,45 +488,109 @@ def _init_misc_ui():
482488
style.theme_use("clam")
483489

484490

491+
def _create_menubar():
492+
# Creates the menu bar at the top of the window
493+
# Note: This is called after _create_top_widgets() initializes the variables
494+
495+
menubar = Menu(_root)
496+
_root.config(menu=menubar)
497+
498+
# File menu
499+
file_menu = Menu(menubar, tearoff=0)
500+
menubar.add_cascade(label="File", menu=file_menu)
501+
file_menu.add_command(label="Save", command=_save)
502+
file_menu.add_command(label="Save As...", command=_save_as)
503+
file_menu.add_command(label="Save Minimal...", command=_save_minimal)
504+
file_menu.add_separator()
505+
file_menu.add_command(label="Open...", command=_open)
506+
file_menu.add_separator()
507+
file_menu.add_command(label="Quit", command=_on_quit)
508+
509+
# Options menu
510+
options_menu = Menu(menubar, tearoff=0)
511+
menubar.add_cascade(label="Options", menu=options_menu)
512+
options_menu.add_checkbutton(
513+
label="Show Name",
514+
variable=_show_name_var,
515+
command=_do_showname,
516+
)
517+
options_menu.add_checkbutton(
518+
label="Show All",
519+
variable=_show_all_var,
520+
command=_do_showall,
521+
)
522+
options_menu.add_checkbutton(
523+
label="Single-Menu Mode",
524+
variable=_single_menu_var,
525+
command=_do_tree_mode,
526+
)
527+
528+
485529
def _create_top_widgets():
486530
# Creates the controls above the Kconfig tree in the main window
531+
# Also initializes the option variables used by the menu bar
487532

488533
global _show_all_var
489534
global _show_name_var
490535
global _single_menu_var
491536
global _menupath
492537
global _backbutton
493538

539+
# Initialize option variables first (needed by menubar)
540+
_show_name_var = BooleanVar()
541+
_show_all_var = BooleanVar()
542+
_single_menu_var = BooleanVar()
543+
494544
topframe = ttk.Frame(_root)
495-
topframe.grid(column=0, row=0, sticky="ew")
545+
topframe.grid(column=0, row=0, sticky="ew", padx=".1c", pady=".1c")
546+
547+
# Create button groups with separators
548+
# File operations group
549+
file_group = ttk.LabelFrame(topframe, text="File Operations", padding="5")
550+
file_group.grid(column=0, row=0, sticky="ew", padx="0 .1c")
496551

497-
ttk.Button(topframe, text="Save", command=_save).grid(
498-
column=0, row=0, sticky="ew", padx=".05c", pady=".05c"
552+
ttk.Button(file_group, text="Save", command=_save, width=12).grid(
553+
column=0, row=0, sticky="ew", padx="2", pady="2"
499554
)
500555

501-
ttk.Button(topframe, text="Save as...", command=_save_as).grid(
502-
column=1, row=0, sticky="ew"
556+
ttk.Button(file_group, text="Save as...", command=_save_as, width=12).grid(
557+
column=1, row=0, sticky="ew", padx="2", pady="2"
503558
)
504559

505-
ttk.Button(topframe, text="Save minimal (advanced)...", command=_save_minimal).grid(
506-
column=2, row=0, sticky="ew", padx=".05c"
560+
ttk.Button(
561+
file_group, text="Save minimal...", command=_save_minimal, width=12
562+
).grid(column=2, row=0, sticky="ew", padx="2", pady="2")
563+
564+
ttk.Button(file_group, text="Open...", command=_open, width=12).grid(
565+
column=3, row=0, sticky="ew", padx="2", pady="2"
507566
)
508567

509-
ttk.Button(topframe, text="Open...", command=_open).grid(column=3, row=0)
568+
# Navigation group
569+
nav_group = ttk.LabelFrame(topframe, text="Navigation", padding="5")
570+
nav_group.grid(column=1, row=0, sticky="ew")
510571

511-
ttk.Button(topframe, text="Jump to...", command=_jump_to_dialog).grid(
512-
column=4, row=0, padx=".05c"
572+
ttk.Button(nav_group, text="Jump to...", command=_jump_to_dialog, width=12).grid(
573+
column=0, row=0, sticky="ew", padx="2", pady="2"
513574
)
514575

515-
_show_name_var = BooleanVar()
576+
# View options group
577+
options_group = ttk.LabelFrame(topframe, text="View Options", padding="5")
578+
options_group.grid(column=0, row=1, columnspan=2, sticky="ew", pady=".1c 0")
579+
516580
ttk.Checkbutton(
517-
topframe, text="Show name", command=_do_showname, variable=_show_name_var
518-
).grid(column=0, row=1, sticky="nsew", padx=".05c", pady="0 .05c", ipady=".2c")
581+
options_group, text="Show name", command=_do_showname, variable=_show_name_var
582+
).grid(column=0, row=0, sticky="w", padx="5", pady="2")
583+
584+
ttk.Checkbutton(
585+
options_group, text="Show all", command=_do_showall, variable=_show_all_var
586+
).grid(column=1, row=0, sticky="w", padx="5", pady="2")
519587

520-
_show_all_var = BooleanVar()
521588
ttk.Checkbutton(
522-
topframe, text="Show all", command=_do_showall, variable=_show_all_var
523-
).grid(column=1, row=1, sticky="nsew", pady="0 .05c")
589+
options_group,
590+
text="Single-menu mode",
591+
command=_do_tree_mode,
592+
variable=_single_menu_var,
593+
).grid(column=2, row=0, sticky="w", padx="5", pady="2")
524594

525595
# Allow the show-all and single-menu status to be queried via plain global
526596
# Python variables, which is faster and simpler
@@ -532,40 +602,37 @@ def show_all_updated(*_):
532602
_trace_write(_show_all_var, show_all_updated)
533603
_show_all_var.set(False)
534604

535-
_single_menu_var = BooleanVar()
536-
ttk.Checkbutton(
537-
topframe,
538-
text="Single-menu mode",
539-
command=_do_tree_mode,
540-
variable=_single_menu_var,
541-
).grid(column=2, row=1, sticky="nsew", padx=".05c", pady="0 .05c")
605+
# Create integrated menu path bar with back button
606+
path_frame = ttk.Frame(topframe, relief="groove", borderwidth=1)
607+
path_frame.grid(column=0, row=2, columnspan=2, sticky="ew", pady=".1c 0")
542608

543609
_backbutton = ttk.Button(
544-
topframe, text="<--", command=_leave_menu, state="disabled"
610+
path_frame, text="\u25c0 Back", command=_leave_menu, state="disabled", width=8
545611
)
546-
_backbutton.grid(column=0, row=4, sticky="nsew", padx=".05c", pady="0 .05c")
612+
_backbutton.pack(side="left", padx=2, pady=2)
613+
_backbutton.pack_forget() # Initially hidden
547614

548615
def tree_mode_updated(*_):
549616
global _single_menu
550617
_single_menu = _single_menu_var.get()
551618

552619
if _single_menu:
553-
_backbutton.grid()
620+
_backbutton.pack(
621+
side="left", padx=2, pady=2, before=path_frame.winfo_children()[1]
622+
)
554623
else:
555-
_backbutton.grid_remove()
624+
_backbutton.pack_forget()
556625

557626
_trace_write(_single_menu_var, tree_mode_updated)
558627
_single_menu_var.set(False)
559628

560-
# Column to the right of the buttons that the menu path extends into, so
561-
# that it can grow wider than the buttons
562-
topframe.columnconfigure(5, weight=1)
563-
564-
_menupath = ttk.Label(topframe)
565-
_menupath.grid(
566-
column=0, row=3, columnspan=6, sticky="w", padx="0.05c", pady="0 .05c"
629+
ttk.Label(path_frame, text="Path:", font=("TkDefaultFont", 9, "bold")).pack(
630+
side="left", padx=(10, 2)
567631
)
568632

633+
_menupath = ttk.Label(path_frame, anchor="w", relief="flat", padding="2 4")
634+
_menupath.pack(side="left", fill="x", expand=True, padx=2, pady=2)
635+
569636

570637
def _create_kconfig_tree_and_desc(parent):
571638
# Creates a Panedwindow with a Treeview that shows Kconfig nodes and a Text
@@ -617,6 +684,11 @@ def _create_kconfig_tree(parent):
617684
frame = ttk.Frame(parent)
618685

619686
tree = ttk.Treeview(frame, selectmode="browse", height=20, columns=("name",))
687+
688+
# Configure column widths and headers
689+
tree.column("#0", width=400, minwidth=200, stretch=True)
690+
tree.column("name", width=200, minwidth=100, stretch=True)
691+
620692
tree.heading("#0", text="Option", anchor="w")
621693
tree.heading("name", text="Name", anchor="w")
622694

@@ -634,7 +706,17 @@ def _create_kconfig_tree(parent):
634706
tree.tag_configure("not-selected", image=_not_selected_img)
635707
tree.tag_configure("selected", image=_selected_img)
636708
tree.tag_configure("edit", image=_edit_img)
637-
tree.tag_configure("invisible", foreground="red")
709+
710+
# Enhanced semantic color tags
711+
tree.tag_configure("invisible", foreground="#cc0000") # Red for invisible items
712+
tree.tag_configure("new-item", foreground="#0066cc") # Blue for NEW items
713+
tree.tag_configure(
714+
"menu-item", foreground="#006600"
715+
) # Dark green for menu/choice items
716+
717+
# Alternating row colors (zebra striping) for better readability
718+
tree.tag_configure("oddrow", background="#f0f0f0")
719+
tree.tag_configure("evenrow", background="#ffffff")
638720

639721
tree.grid(column=0, row=0, sticky="nsew")
640722

@@ -700,12 +782,23 @@ def yscrollcommand(first, last):
700782

701783

702784
def _create_status_bar():
703-
# Creates the status bar at the bottom of the main window
785+
# Creates an enhanced status bar at the bottom of the main window
704786

705787
global _status_label
788+
global _stats_label
789+
790+
status_frame = ttk.Frame(_root, relief="sunken", borderwidth=1)
791+
status_frame.grid(column=0, row=3, sticky="ew")
706792

707-
_status_label = ttk.Label(_root, anchor="e", padding="0 0 0.4c 0")
708-
_status_label.grid(column=0, row=3, sticky="ew")
793+
# Left side: Status message
794+
_status_label = ttk.Label(status_frame, anchor="w", padding="2 2")
795+
_status_label.pack(side="left", fill="x", expand=True)
796+
797+
# Right side: Statistics
798+
_stats_label = ttk.Label(status_frame, anchor="e", padding="2 2")
799+
_stats_label.pack(side="right")
800+
801+
_update_stats()
709802

710803

711804
def _set_status(s):
@@ -714,6 +807,19 @@ def _set_status(s):
714807
_status_label["text"] = s
715808

716809

810+
def _update_stats():
811+
# Updates the statistics label in the status bar
812+
813+
if not _kconf:
814+
return
815+
816+
total_syms = len(_kconf.unique_defined_syms)
817+
changed_syms = sum(
818+
1 for sym in _kconf.unique_defined_syms if sym.user_value is not None
819+
)
820+
_stats_label["text"] = "Symbols: {} | Changed: {}".format(total_syms, changed_syms)
821+
822+
717823
def _set_conf_changed(changed):
718824
# Updates the status re. whether there are unsaved changes
719825

@@ -722,6 +828,7 @@ def _set_conf_changed(changed):
722828
_conf_changed = changed
723829
if changed:
724830
_set_status("Modified")
831+
_update_stats()
725832

726833

727834
def _update_tree():
@@ -740,6 +847,10 @@ def _update_tree():
740847
# luckily.
741848
_tree.detach(*_id_to_node.keys())
742849

850+
# Reset row counter for alternating colors
851+
global _tree_row_index
852+
_tree_row_index = 0
853+
743854
if _single_menu:
744855
_build_menu_tree()
745856
else:
@@ -855,22 +966,32 @@ def _add_to_tree(node, top):
855966
# the nodes linearly to get the correct order. 'top' holds the menu that
856967
# corresponds to the top-level menu, and can vary in single-menu mode.
857968

969+
global _tree_row_index
970+
858971
parent = node.parent
859972
_tree.move(id(node), "" if parent is top else id(parent), "end")
973+
974+
# Build tags: base tags + row color + optional invisible
975+
base_tags = _img_tag(node)
976+
row_tag = "oddrow" if _tree_row_index % 2 else "evenrow"
977+
978+
if _visible(node) or not _show_all:
979+
tags = base_tags + " " + row_tag
980+
else:
981+
tags = base_tags + " invisible " + row_tag
982+
860983
_tree.item(
861984
id(node),
862985
text=_node_str(node),
863986
# The _show_all test avoids showing invisible items in red outside
864987
# show-all mode, which could look confusing/broken. Invisible symbols
865988
# are shown outside show-all mode if an invisible symbol has visible
866989
# children in an implicit menu.
867-
tags=(
868-
_img_tag(node)
869-
if _visible(node) or not _show_all
870-
else _img_tag(node) + " invisible"
871-
),
990+
tags=tags,
872991
)
873992

993+
_tree_row_index += 1
994+
874995

875996
def _get_force_info(sym):
876997
# Returns a string indicating what's forcing a symbol's value, or None

0 commit comments

Comments
 (0)