__init__.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #! /usr/bin/python3
  2. #
  3. ## LICENSE
  4. # This file is part of DigiLib.
  5. #
  6. # DigiLib is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # DigiLib is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with DigiLib. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. ## DOC
  20. # DigiLib provides widgets based on Gtk3. It doesn't create own widgets, it
  21. # uses Gtk3 widgets.
  22. # This Module defines following classes:
  23. # |-LabelName
  24. # | |-displas a name/label for something
  25. # |-LabelValue
  26. # | |-to display the value of something
  27. # |-InfoFrame
  28. # | lists informations in the format 'Label:Value [Unit] [Widget]', where
  29. # | Widget is a Gtk Widget to visualize the Value. A widget_update_func can
  30. # | be passed to add_line for easy updating.
  31. # |-ChildConsoleBase
  32. # TODO
  33. #
  34. ## Imports
  35. # Python Libraries
  36. import gi
  37. gi.require_version('Gtk', '3.0')
  38. from gi.repository import Gtk
  39. from gi.repository import Gdk
  40. import logging
  41. import logging.config
  42. import os
  43. import pprint
  44. import random
  45. import string
  46. import sys
  47. import time
  48. import yaml
  49. # My libraries
  50. import digilib.misc
  51. ## Logging
  52. log = logging.getLogger(__name__+".gui")
  53. ## Global Variables
  54. ## Classes
  55. class LabelName(Gtk.Label):
  56. def __init__(self, *args,**kwargs):
  57. super(LabelName, self).__init__(*args,**kwargs)
  58. self.set_css_name("namelabel")
  59. self.set_halign(Gtk.Align(2))
  60. class LabelValue(Gtk.Label):
  61. """docstring for LabelValue"""
  62. def __init__(self, *args,**kwargs):
  63. super(LabelValue, self).__init__(*args,**kwargs)
  64. self.set_css_name("valuelabel")
  65. self.set_halign(Gtk.Align(1))
  66. class InfoFrame(Gtk.Frame):
  67. """docstring for InfoFrame."""
  68. def __init__(self,**kwargs):
  69. super(InfoFrame, self).__init__(**kwargs)
  70. self.lines = {
  71. # id:{
  72. # "layout": layout,
  73. # "widgets": [label_name,label_value,widget],
  74. # "update_func":widget_update_func
  75. # }
  76. }
  77. self.current_line_no = 0
  78. # self.layout = Gtk.Grid(halign=Gtk.Align(1))
  79. self.layout = Gtk.Grid()
  80. self.layout.set_row_spacing(10)
  81. self.layout.set_column_spacing(5)
  82. self.layout.set_column_homogeneous(False)
  83. self.layout.set_hexpand(True)
  84. self.add(self.layout)
  85. def add_line(
  86. self,
  87. identifier,
  88. name,
  89. value,
  90. unit=None,
  91. widget=None,
  92. widget_update_func=None
  93. ):
  94. if id in self.lines.keys():
  95. raise ValueError(
  96. "Identifiers must be uniqe, but '"
  97. +identifier
  98. +"' already exists!"
  99. )
  100. self.lines[identifier] = {
  101. "layout":None,
  102. "wname":None,
  103. "wvalue":None,
  104. "wunit":None,
  105. "wextra":None,
  106. "update_func":None
  107. }
  108. self.lines[identifier]["update_func"] = widget_update_func
  109. # if there is a widget and an update function was passed then update it
  110. if widget_update_func == True:
  111. self.lines[identifier]["update_func"] = widget.set_value
  112. if self.lines[identifier]["update_func"]:
  113. self.lines[identifier]["update_func"](value)
  114. layout = Gtk.Box()
  115. layout.set_spacing(5)
  116. layout.set_homogeneous(False)
  117. self.lines[identifier]["layout"] = layout
  118. # create the labels for the name and value field and also for the unit
  119. # field if an unit was specified
  120. label_name = LabelName(name)
  121. self.lines[identifier]["wname"] = label_name
  122. self.layout.attach(label_name,0,self.current_line_no,1,1)
  123. label_value = LabelValue(value)
  124. self.lines[identifier]["wvalue"] = label_value
  125. layout.add(label_value)
  126. if unit:
  127. label_unit = LabelValue(unit)
  128. self.lines[identifier]["wunit"] = label_unit
  129. layout.add(label_unit)
  130. if widget:
  131. self.lines[identifier]["wextra"] = widget
  132. layout.add(widget)
  133. self.layout.attach(layout,1,self.current_line_no,1,1)
  134. self.current_line_no += 1
  135. def update_name(self,identifier,name):
  136. self.lines[identifier]["wname"].set_label(name)
  137. def update_unit(self,identifier,unit):
  138. self.lines[identifier]["wunit"].set_label(unit)
  139. def update_value(self,identifier,value):
  140. self.lines[identifier]["wvalue"].set_label(str(value))
  141. if self.lines[identifier]["update_func"]:
  142. self.lines[identifier]["update_func"](value)
  143. print(1)
  144. # class ChildGrid(Gtk.Grid):
  145. # def __init__(self):
  146. # super(ChildGrid,self).__init__()
  147. # self.prepare()
  148. # def prepare(self):
  149. # pass
  150. #
  151. # class ChildScrollBase(Gtk.ScrolledWindow):
  152. # def __init__(self):
  153. # super(ChildScroll,self).__init__()
  154. # self.prepare()
  155. # def prepare(self):
  156. # pass
  157. class ChildConsole(Gtk.Grid):
  158. scroll = True
  159. history_list = []
  160. history_position = -1
  161. def __init__(self,get_client):
  162. super(ChildConsole,self).__init__()
  163. self.get_client = get_client
  164. self.set_css_name("tab_console")
  165. self.prepare()
  166. self.button_send.connect("clicked",self.on_entry_activated)
  167. self.entry_cmd.connect("activate",self.on_entry_activated)
  168. self.entry_cmd.connect("key-press-event",self.on_keypress)
  169. def prepare(self):
  170. self.scroll_mark = Gtk.TextMark(name="scroll_mark")
  171. self.text_buffer_log = Gtk.TextBuffer()
  172. self.text_view_log = Gtk.TextView(hexpand=True,vexpand=True)
  173. self.text_view_log.set_buffer(self.text_buffer_log)
  174. self.text_view_log.set_editable(False)
  175. self.text_view_log.set_cursor_visible(False)
  176. self.text_view_log.props.pixels_above_lines = 2
  177. self.text_view_log.props.pixels_below_lines = 2
  178. self.text_view_log.props.right_margin = 2
  179. self.text_view_log.props.left_margin = 6
  180. # self.text_view_log.set_hexpand(True)
  181. # self.text_view_log.set_vexpand(True)
  182. self.scrolled_window = Gtk.ScrolledWindow()
  183. self.entry_cmd = Gtk.Entry(hexpand=True)
  184. # self.entry_cmd.set_cursor_hadjustment(Gtk.Align(2))
  185. # self.entry_cmd.set_hexpand(True)
  186. self.button_send = Gtk.Button(label="send")
  187. # self.button_send.set_label("send")
  188. self.scrolled_window.add(self.text_view_log)
  189. self.attach(self.scrolled_window,0,1,2,1)
  190. self.attach(self.entry_cmd,0,2,1,1)
  191. self.attach(self.button_send,1,2,1,1)
  192. def add_msg(self,text,sender_name="Server"):
  193. for line in text.splitlines():
  194. if sender_name:
  195. line = sender_name+":"+line
  196. self.text_buffer_log.insert(
  197. self.text_buffer_log.get_end_iter(),
  198. "\n"+line.rstrip()
  199. )
  200. self.scroll_down(None)
  201. if self.scroll:
  202. self.scroll_down(None)
  203. def add_msg_threadsafe(self,*args,**kwargs):
  204. Gdk.threads_enter()
  205. self.add_msg(*args,**kwargs)
  206. Gdk.threads_leave()
  207. def send(self,text):
  208. client = self.get_client()
  209. if client:
  210. if client.is_connected:
  211. client.send(text)
  212. def scroll_down(self,*args):
  213. self.scroll = True
  214. self.text_buffer_log.add_mark(
  215. self.scroll_mark,
  216. self.text_buffer_log.get_end_iter()
  217. )
  218. self.text_view_log.scroll_to_mark(
  219. mark=self.scroll_mark,
  220. # No idea what these arguments do, but they work.
  221. within_margin=0.0,
  222. use_align=True,
  223. xalign=0.5,
  224. yalign=0.5
  225. )
  226. self.text_buffer_log.delete_mark(self.scroll_mark)
  227. def toggle_scroll(self,*args):
  228. self.scroll = not self.scroll
  229. def get_entry_text(self):
  230. text = self.entry_cmd.get_text()
  231. self.entry_cmd.set_text("")
  232. return text
  233. def on_entry_activated(self,widget):
  234. text = self.get_entry_text()
  235. if text.strip():
  236. self.history_position = -1
  237. if len(self.history_list) == 0:
  238. self.history_list.insert(0,text)
  239. else:
  240. if self.history_list[0] != text:
  241. self.history_list.insert(0,text)
  242. self.add_msg(text,"you")
  243. self.send(text)
  244. def on_keypress(self,widget,event):
  245. if not widget == self.entry_cmd:
  246. lgui.debug("exiting keypress event function because the widget was \
  247. not self.entry_cmd")
  248. return True
  249. if event.keyval == Gdk.KEY_Up: # Up
  250. if self.history_position < len(self.history_list)-1:
  251. self.history_position += 1
  252. text = self.history_list[self.history_position]
  253. self.entry_cmd.set_text(text)
  254. self.entry_cmd.set_position(len(text))
  255. return True
  256. elif event.keyval == Gdk.KEY_Down: # Down
  257. text = self.entry_cmd.get_text()
  258. if self.history_position == -1 and text != "":
  259. self.entry_cmd.set_text("")
  260. elif self.history_position == 0:
  261. self.history_position = -1
  262. self.entry_cmd.set_text("")
  263. elif self.history_position > 0:
  264. self.history_position -= 1
  265. text = self.history_list[self.history_position]
  266. self.entry_cmd.set_text(text)
  267. self.entry_cmd.set_position(len(text))
  268. return True
  269. class ChildOverview(Gtk.ScrolledWindow):
  270. def __init__(self):
  271. super(ChildOverview,self).__init__()
  272. self.set_css_name("tab_overview")
  273. self.layout = Gtk.Grid()
  274. self.layout.set_column_homogeneous(True)
  275. self.add(self.layout)
  276. class ChildControl(Gtk.Grid):
  277. def __init__(self):
  278. super(ChildControl,self).__init__()
  279. self.label = Gtk.Label()
  280. self.label.set_markup("<big>Another fancy self.label</big>")
  281. self.add(self.label)
  282. class ChildSettings(Gtk.Grid):
  283. def __init__(self):
  284. super(ChildSettings,self).__init__()
  285. self.label = Gtk.Label()
  286. self.label.set_markup("<big>Another fancy self.label</big>")
  287. self.add(self.label)
  288. class WindowBase(Gtk.Window):
  289. def __init__(self,title="Don't Panic!"):
  290. super(Gtk.Window,self).__init__(title=title)
  291. self.pressed_keys = []
  292. self.key_shortcuts = []
  293. self.connect("delete-event",self.on_delete_event)
  294. self.connect("key-press-event",self.on_key_press_event)
  295. self.connect("key-release-event",self.on_key_release_event)
  296. def keystring_to_gkd(self, keys):
  297. key_list = keys.split(" ")
  298. known_keys = []
  299. unknown_keys = []
  300. for k in key_list:
  301. if "KEY_"+k in dir(Gdk):
  302. known_keys.append(eval("Gdk.KEY_"+k))
  303. else:
  304. unknown_keys.append(k)
  305. if unknown_keys:
  306. raise ValueError("Unknown Keys: "+", ".join(unknown_keys))
  307. else:
  308. return known_keys
  309. def add_key_shortcut(self,keys,func=None,args=[],kwargs={}):
  310. key_list = self.keystring_to_gkd(keys)
  311. for ks in self.key_shortcuts:
  312. if key_list == ks[0]:
  313. self.key_shortcuts.remove(ks)
  314. break
  315. self.key_shortcuts.append([key_list,func,args,kwargs])
  316. def remove_key_shortcut(self,keys):
  317. key_list = self.keystring_to_gkd(keys)
  318. for ks in self.key_shortcuts:
  319. if key_list == ks[0]:
  320. self.key_shortcuts.remove(ks)
  321. break
  322. def on_delete_event(self,*args):
  323. print(args)
  324. Gtk.main_quit()
  325. def on_key_release_event(self,widget,event):
  326. if event.keyval in self.pressed_keys:
  327. self.pressed_keys.remove(event.keyval)
  328. def on_key_press_event(self,widget,event):
  329. self.pressed_keys.append(event.keyval)
  330. for keys,func,args,kwargs in self.key_shortcuts:
  331. if keys == self.pressed_keys:
  332. func(*args,**kwargs)
  333. break
  334. def hello_world(self,*args):
  335. print("hello world")
  336. #