import gi gi.require_version('Clutter', '1.0') gi.require_version('GObject', '2.0') gi.require_version('Mx', '1.0') from gi.repository import Clutter, GObject, Mx GObject.threads_init() Clutter.init(None) class GUI: def __init__(self, tracks): self.application, args = Mx.Application.new([], 'AudioVox', 0) self.window = self.application.create_window() self.window.set_window_size(1360, 668) self.window.set_has_toolbar(False) self.stage = self.window.get_clutter_stage() self.viewport = Clutter.ScrollActor() Clutter.Container.add_actor(self.stage, self.viewport) self.library_view_area = Clutter.Rect() self.library_view_area.init(0, 0, 1360, 668) self.normal_view_area = Clutter.Rect() self.normal_view_area.init(620, 0, 1360, 668) self.voip_view_area = Clutter.Rect() self.voip_view_area.init(2280, 0, -1360, 668) self.viewport.scroll_to_rect(self.normal_view_area) self.viewport.set_easing_duration(500) playlist = Mx.Label.new_with_text('playlist') controls = Mx.Label.new_with_text('controls') voip = Mx.Label.new_with_text('voip') self.viewport.add_child(playlist) self.viewport.add_child(controls) self.viewport.add_child(voip) playlist.set_position(680, 0) controls.set_position(1360, 0) voip.set_position(2040, 0) bgcolor = Clutter.Color.new(76, 76, 255, 255) self.stage.set_color(bgcolor) self.library_view = LibraryView(tracks) self.viewport.add_child(self.library_view) self.library_view.set_position(0, 0) self.lp_toolbar = LibraryPlaylistToolbar() self.viewport.add_child(self.lp_toolbar) self.lp_toolbar.set_position(620, 0) self.lp_toolbar.connect('view-toggled', self.on_toggle_library) self.pv_toolbar = PlaylistVOIPToolbar() self.viewport.add_child(self.pv_toolbar) self.pv_toolbar.set_position(1920, 0) self.pv_toolbar.connect('view-toggled', self.on_toggle_voip) Mx.Style.get_default().load_from_file('assets/style.css') self.window.show() self.application.run() def on_toggle_library(self, actor, show_library): if show_library: self.viewport.scroll_to_rect(self.library_view_area) else: self.viewport.scroll_to_rect(self.normal_view_area) def on_toggle_voip(self, actor, show_voip): if show_voip: self.viewport.scroll_to_rect(self.voip_view_area) else: self.viewport.scroll_to_rect(self.normal_view_area) class LibraryPlaylistToolbar(Mx.BoxLayout): __gsignals__ = { "view-toggled": (GObject.SIGNAL_RUN_FIRST, None, (bool,)) } def __init__(self): super(Mx.BoxLayout, self).__init__() self.set_size(60, 668) self.set_orientation(Mx.Orientation.VERTICAL) self.set_style_class('LibraryPlaylistToolbar') toggle_library = Mx.Button() toggle_library.set_style_class('Toggle') toggle_library.set_size(60, 60) toggle_library.set_pivot_point(0.5, 0.5) toggle_library.set_is_toggle(True) toggle_library.connect('clicked', self.on_toggle_library) toggle_library.set_position(0, 300) self.add_actor(toggle_library, 1) #toggle_library.set_background_color(Clutter.Color.new(255, 0, 0, 255)) self.add_track_button = Mx.Button() self.add_track_button.set_size(60, 60) self.add_actor(self.add_track_button, 1) def on_toggle_library(self, button): self.emit('view-toggled', button.get_toggled()) button.set_easing_duration(500) if button.get_toggled(): button.set_rotation_angle(Clutter.RotateAxis.Z_AXIS, 180) else: button.set_rotation_angle(Clutter.RotateAxis.Z_AXIS, 360) class LibraryView(Mx.Widget): active_item = GObject.Property(type=Clutter.Actor, flags=GObject.PARAM_READWRITE) def __init__(self, tracks): super(Mx.Widget, self).__init__() self.set_style_class('LibraryView') self.set_size(620, 668) self.search = Mx.Entry.new_with_text('Search Song/Artist/Album') self.search.set_width(550) self.search.set_position(5, 5) self.add_child(self.search) self.scrollview = Mx.ScrollView() self.scrollview.set_size(620, 628) self.scrollview.set_position(0, 40) self.scrollview.set_scroll_policy(Mx.ScrollPolicy.VERTICAL) self.add_child(self.scrollview) self.view = Mx.ItemView() self.scrollview.set_child(self.view) types = [str, str, str, str, str, str, int] names = ['id', 'uri', 'Title', 'Artist', 'Album', 'Genre', 'Duration'] self.model = Clutter.ListModel.newv(types, names) self.view.set_homogenous_rows(True) self.view.set_homogenous_columns(True) self.view.set_row_spacing(20) self.view.set_column_spacing(20) self.view.set_model(self.model) self.view.add_attribute('oid', 0) self.view.add_attribute('uri', 1) self.view.add_attribute('title', 2) self.view.add_attribute('artist', 3) self.view.add_attribute('album', 4) self.view.add_attribute('genre', 5) self.view.add_attribute('duration', 6) self.view.connect('actor-added', self.on_new_item) self.highlight_effect = Clutter.ColorizeEffect.new(Clutter.Color.new(174, 143, 0, 255)) #self.view.set_item_type(LibraryViewGridItem) self.view.set_item_type(LibraryViewListItem) for track in tracks.find(): try: if track['artist'] == 'Epic Games': columns = [0, 1, 2, 3, 4, 5, 6] values = [str(track['_id']), track['uri'], track['title'], track['artist'], track['album'], track['genre'], track['duration']] self.model.appendv(columns, values) except KeyError: # TODO: Handle this. pass def do_paint(self): for child in self.get_children(): child.paint() def on_new_item(self, container, actor, *user_data): actor.connect('selected', self.on_item_selected) def on_item_selected(self, actor): if self.get_property('active-item'): self.get_property('active-item').remove_effect(self.highlight_effect) self.set_property('active-item', actor) actor.add_effect(self.highlight_effect) class LibraryViewGridItem(Mx.Stack): oid = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) uri = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) title = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) artist = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) album = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) genre = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) duration = GObject.Property(type=int, default=0, flags=GObject.PARAM_READWRITE) __gsignals__ = { "selected": (GObject.SIGNAL_RUN_FIRST, None, ()) } def __init__(self): super(Mx.Stack, self).__init__() self.set_size(175, 175) white = Clutter.Color.new(255, 255, 255, 255) self.set_background_color(white) art = Mx.Image() art.set_from_file_at_size('assets/blank_cd.svg', self.get_width(), self.get_height()) art.set_x_align(Clutter.ActorAlign.CENTER) art.set_y_align(Clutter.ActorAlign.CENTER) self.add_actor(art) label_layout = Mx.Table() label_layout.set_width(self.get_width()) label_layout.set_row_spacing(1) label_bg_color = Clutter.Color.new(0, 0, 0, 150) label_layout.set_background_color(label_bg_color) label_layout.set_y_align(Clutter.ActorAlign.END) self.add_actor(label_layout) self.label_title = Mx.Label() self.label_artist = Mx.Label() self.label_album = Mx.Label() self.label_genre = Mx.Label() self.label_duration = Mx.Label() self.label_title.set_line_wrap(False) self.label_artist.set_line_wrap(False) self.label_album.set_line_wrap(False) self.label_genre.set_line_wrap(False) self.label_duration.set_line_wrap(False) label_layout.add_actor(self.label_title, 1, 1) label_layout.add_actor(self.label_artist, 2, 1) label_layout.add_actor(self.label_album, 3, 1) label_layout.add_actor(self.label_genre, 4, 1) label_layout.add_actor(self.label_duration, 5, 1) click_action = Clutter.ClickAction.new() click_action.connect('clicked', self.on_clicked) self.add_action(click_action) self.set_reactive(True) self.bind_property('title', self.label_title, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('artist', self.label_artist, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('album', self.label_album, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('genre', self.label_genre, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('duration', self.label_duration, 'text', GObject.BindingFlags.DEFAULT) def on_clicked(self, action, actor, *user_data): self.emit('selected') class LibraryViewListItem(Mx.BoxLayout): oid = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) uri = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) title = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) artist = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) album = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) genre = GObject.Property(type=str, default='', flags=GObject.PARAM_READWRITE) duration = GObject.Property(type=int, default=0, flags=GObject.PARAM_READWRITE) __gsignals__ = { "selected": (GObject.SIGNAL_RUN_FIRST, None, ()) } def __init__(self): super(Mx.BoxLayout, self).__init__() self.set_size(600, 60) self.set_spacing(5) self.set_style_class('LibraryViewListItem') art = Mx.Image() art.set_from_file_at_size('assets/blank_cd.svg', self.get_height(), self.get_height()) art.set_x_align(Clutter.ActorAlign.CENTER) art.set_y_align(Clutter.ActorAlign.CENTER) self.add_actor(art, 0) self.label_title = Mx.Label() self.label_artist = Mx.Label() self.label_album = Mx.Label() self.label_genre = Mx.Label() self.label_duration = Mx.Label() # TODO: Is this default? Remove if so. self.label_title.set_line_wrap(True) self.label_artist.set_line_wrap(True) self.label_album.set_line_wrap(True) self.label_genre.set_line_wrap(True) self.label_duration.set_line_wrap(True) self.add_actor(self.label_title, 1) self.add_actor(self.label_artist, 2) self.add_actor(self.label_album, 3) self.add_actor(self.label_genre, 4) self.add_actor(self.label_duration, 5) click_action = Clutter.ClickAction.new() click_action.connect('clicked', self.on_clicked) self.add_action(click_action) self.set_reactive(True) self.bind_property('title', self.label_title, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('artist', self.label_artist, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('album', self.label_album, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('genre', self.label_genre, 'text', GObject.BindingFlags.DEFAULT) self.bind_property('duration', self.label_duration, 'text', GObject.BindingFlags.DEFAULT) def on_clicked(self, action, actor, *user_data): self.emit('selected') class PlaylistView(Clutter.Actor): def __init__(self): super(Clutter.Actor, self).__init__() self.model = types = [str, str, str, str, str, str, int] names = ['id', 'uri', 'Title', 'Artist', 'Album', 'Genre', 'Duration'] self.model = Clutter.ListModel.newv(types, names) class PlaylistVOIPToolbar(Mx.BoxLayout): #view_toggled = GObject.Signal(arg_types=(bool,), return_type=None, flags=GObject.SIGNAL_RUN_FIRST) __gsignals__ = { "view-toggled": (GObject.SIGNAL_RUN_FIRST, None, (bool,)) } def __init__(self): super(Mx.BoxLayout, self).__init__() self.set_size(60, 668) self.set_orientation(Mx.Orientation.VERTICAL) self.set_style_class('PlaylistVOIPToolbar') toggle_voip = Mx.Button() toggle_voip.set_style_class('Toggle') toggle_voip.set_size(60, 60) toggle_voip.set_pivot_point(0.5, 0.5) toggle_voip.set_is_toggle(True) toggle_voip.connect('clicked', self.on_toggle_voip) toggle_voip.set_position(0, 300) self.add_actor(toggle_voip, 1) def on_toggle_voip(self, button): self.emit('view-toggled', button.get_toggled()) button.set_easing_duration(500) if button.get_toggled(): button.set_rotation_angle(Clutter.RotateAxis.Z_AXIS, 180) else: button.set_rotation_angle(Clutter.RotateAxis.Z_AXIS, 360)