Coverage for src/plotly_gtk/widgets/updatemenus.py: 16%

67 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-08 21:22 +0000

1import gi 

2 

3gi.require_version("Gdk", "4.0") 

4gi.require_version("Gtk", "4.0") 

5from typing import TYPE_CHECKING 

6 

7import numpy as np 

8from gi.repository import Gdk, Gtk # noqa: E402 

9 

10from plotly_gtk.utils import update_dict 

11from plotly_gtk.widgets.base import Base 

12 

13if TYPE_CHECKING: 

14 from plotly_gtk.chart import PlotlyGtk 

15 

16 

17class UpdateMenu(Base): 

18 def __init__(self, plot: "PlotlyGtk", _updatemenu: dict): 

19 super().__init__() 

20 default = dict( 

21 active=0, 

22 bgcolor="transparent", 

23 bordercolor="#BEC8D9", 

24 borderwidth=1, 

25 direction="down", 

26 font=plot.layout["font"], 

27 showactive=True, 

28 type="dropdown", 

29 x=-0.05, 

30 xanchor="right", 

31 y=1, 

32 yanchor="top", 

33 ) 

34 updatemenu = update_dict(default, _updatemenu) 

35 self.spec = updatemenu 

36 

37 if updatemenu["direction"] in ["up", "down"]: 

38 self.set_orientation(Gtk.Orientation.VERTICAL) 

39 

40 buttons = updatemenu["buttons"] 

41 

42 font = updatemenu["font"] 

43 custom_css = Gtk.CssProvider() 

44 custom_css.load_from_string( 

45 f""" 

46 .plotly-button button { 

47 background-color: {updatemenu["bgcolor"]}; 

48 border: {updatemenu["borderwidth"]}px solid {updatemenu["bordercolor"]}; 

49 box-shadow: none; 

50 } 

51 .plotly-button label { 

52 color: {updatemenu["font"]["color"]}; 

53 font-family: {font["family"]}; 

54 font-size: {font["size"]}px; 

55 font-style: {font["style"]}; 

56 font-variant: {font["variant"]}; 

57 font-weight: {font["weight"]}; 

58 } 

59 """ 

60 ) 

61 Gtk.StyleContext().add_provider_for_display( 

62 Gdk.Display().get_default(), 

63 custom_css, 

64 Gtk.STYLE_PROVIDER_PRIORITY_USER, 

65 ) 

66 

67 self.add_css_class("plotly-button") 

68 

69 def on_button_selected(button): 

70 args = button.button["args"] 

71 if button.button["method"] == "update": 

72 for arg in args: 

73 plot.layout.update(arg) 

74 for k, v in arg.items(): 

75 if isinstance(v, list | np.ndarray) and len(v) == len( 

76 plot.data 

77 ): 

78 for trace, val in zip(plot.data, v): 

79 trace[k] = val 

80 _updatemenu["active"] = buttons.index(button.button) 

81 plot.update(dict(data=plot.data, layout=plot.layout)) 

82 

83 if updatemenu["type"] == "dropdown": 

84 _buttons = [] 

85 

86 def top_button_clicked(button): 

87 if button == top_button: 

88 top_button.open = not top_button.open 

89 for _button in _buttons: 

90 _button.set_visible(button == top_button and top_button.open) 

91 

92 top_button = Gtk.Button(label=buttons[updatemenu["active"]]["label"]) 

93 top_button.get_child().set_halign(Gtk.Align.START) 

94 top_button.open = False 

95 top_button.connect("clicked", top_button_clicked) 

96 self.append(top_button) 

97 

98 width = 0 

99 

100 for button in buttons: 

101 _button = Gtk.Button(label=button["label"], visible=True) 

102 _buttons.append(_button) 

103 _button.get_child().set_halign(Gtk.Align.START) 

104 _button.button = button 

105 _button.connect("clicked", on_button_selected) 

106 _button.connect("clicked", top_button_clicked) 

107 width = max( 

108 width, 

109 _button.measure(Gtk.Orientation.HORIZONTAL, -1)[0], 

110 ) 

111 _button.set_visible(False) 

112 self.append(_button) 

113 top_button.set_size_request(width, -1) 

114 

115 elif updatemenu["type"] == "buttons": 

116 for button in buttons: 

117 _button = Gtk.Button(label=button["label"]) 

118 _button.get_child().set_halign(Gtk.Align.START) 

119 _button.button = button 

120 _button.connect("clicked", on_button_selected) 

121 self.append(_button) 

122 else: 

123 raise ValueError(f"Unknown updatemenu.type: {updatemenu["type"]}")