Skip to content

Commit 604f650

Browse files
authored
Allow hiding controls (#23)
* Allow hiding controls * refact
1 parent 4054829 commit 604f650

File tree

1 file changed

+60
-27
lines changed

1 file changed

+60
-27
lines changed

src/graphviz_anywidget/__init__.py

+60-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import importlib.metadata
22
from pathlib import Path
3-
from typing import Any
3+
from typing import Any, Literal, get_args
44

55
import anywidget
66
import ipywidgets
@@ -40,8 +40,12 @@ class GraphvizAnyWidget(anywidget.AnyWidget):
4040
freeze_scroll = traitlets.Bool(False).tag(sync=True) # noqa: FBT003
4141

4242

43+
Controls = Literal["zoom", "search", "direction"]
44+
45+
4346
def graphviz_widget(
4447
dot_source: str = "digraph { a -> b; b -> c; c -> a; }",
48+
controls: bool | Controls | list[Controls] = True,
4549
) -> ipywidgets.VBox:
4650
"""Create a full-featured interactive Graphviz visualization widget.
4751
@@ -50,6 +54,17 @@ def graphviz_widget(
5054
dot_source
5155
The DOT language string representing the graph.
5256
Default is a simple cyclic graph: "digraph { a -> b; b -> c; c -> a; }"
57+
controls
58+
Controls to display above the graph. Can be:
59+
60+
- ``True``: show all controls
61+
- ``False``: hide all controls
62+
- ``"zoom"``: show only zoom-related controls (reset and freeze scroll)
63+
- ``"search"``: show only search-related controls (search box, type selector, case toggle)
64+
- ``"direction"``: show only direction selector
65+
- list of the above strings to show multiple control groups
66+
67+
Default is True (show all controls).
5368
5469
Returns
5570
-------
@@ -124,6 +139,15 @@ def graphviz_widget(
124139
def reset_graph(_: Any) -> None:
125140
widget.send({"action": "reset_zoom"})
126141

142+
def toggle_freeze_scroll(change: dict) -> None:
143+
widget.freeze_scroll = change["new"]
144+
if widget.freeze_scroll:
145+
freeze_toggle.description = "Unfreeze Scroll"
146+
freeze_toggle.button_style = "danger"
147+
else:
148+
freeze_toggle.description = "Freeze Scroll"
149+
freeze_toggle.button_style = "primary"
150+
127151
def update_direction(change: dict) -> None:
128152
widget.selected_direction = change["new"]
129153

@@ -136,40 +160,49 @@ def update_search_type(change: dict) -> None:
136160
def toggle_case_sensitive(change: dict) -> None:
137161
widget.case_sensitive = change["new"]
138162

139-
def toggle_freeze_scroll(change: dict) -> None:
140-
widget.freeze_scroll = change["new"]
141-
if widget.freeze_scroll:
142-
freeze_toggle.description = "Unfreeze Scroll"
143-
freeze_toggle.button_style = "danger"
144-
else:
145-
freeze_toggle.description = "Freeze Scroll"
146-
freeze_toggle.button_style = "primary"
147-
148163
reset_button.on_click(reset_graph)
164+
freeze_toggle.observe(toggle_freeze_scroll, names="value")
149165
direction_selector.observe(update_direction, names="value")
150166
search_input.observe(perform_search, names="value")
151167
search_type_selector.observe(update_search_type, names="value")
152168
case_toggle.observe(toggle_case_sensitive, names="value")
153-
freeze_toggle.observe(toggle_freeze_scroll, names="value")
154169

155-
# Display ipywidgets
156-
return ipywidgets.VBox(
157-
[
158-
ipywidgets.HBox(
159-
[
160-
reset_button,
161-
freeze_toggle,
162-
direction_selector,
163-
search_input,
164-
search_type_selector,
165-
case_toggle,
166-
],
167-
layout=ipywidgets.Layout(gap="8px"),
168-
),
169-
widget,
170-
],
170+
zoom_widgets = [reset_button, freeze_toggle]
171+
search_widgets = [search_input, search_type_selector, case_toggle]
172+
173+
controls_box = ipywidgets.HBox(
174+
[*zoom_widgets, direction_selector, *search_widgets],
175+
layout=ipywidgets.Layout(gap="8px"),
171176
)
172177

178+
# Set visibility of controls based on the `controls` parameter
179+
if isinstance(controls, bool):
180+
if not controls:
181+
controls_box.layout.visibility = "hidden"
182+
else:
183+
if isinstance(controls, str):
184+
controls = [controls]
185+
for w in controls_box.children:
186+
w.layout.visibility = "hidden"
187+
for control in controls:
188+
if control == "search":
189+
for w in search_widgets:
190+
w.layout.visibility = "visible"
191+
elif control == "zoom":
192+
for w in zoom_widgets:
193+
w.layout.visibility = "visible"
194+
elif control == "direction":
195+
direction_selector.layout.visibility = "visible"
196+
else:
197+
options = get_args(Controls)
198+
msg = (
199+
f"Unknown control: `{control}`."
200+
f" Valid options are: {', '.join(options)} or lists of them."
201+
)
202+
raise ValueError(msg)
203+
204+
return ipywidgets.VBox([controls_box, widget])
205+
173206

174207
def graphviz_widget_simple(
175208
dot_source: str = "digraph { a -> b; b -> c; c -> a; }",

0 commit comments

Comments
 (0)