mirror of
https://github.com/dialect-app/dialect.git
synced 2026-04-04 13:46:24 +00:00
Initial port to GTK4+Adwaita
This commit is contained in:
parent
1a05970e43
commit
2fa1d125ce
15 changed files with 833 additions and 1148 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"app-id" : "com.github.gi_lom.dialect",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "40",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "dialect",
|
||||
"finish-args" : [
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<object class="GtkAboutDialog" id="about">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="program_name" translatable="yes">Dialect</property>
|
||||
<property name="copyright" translatable="yes">Copyright 2020–2021 The Dialect Authors</property>
|
||||
<property name="comments" translatable="yes">A translation app for GNOME.</property>
|
||||
<property name="website">https://github.com/dialect-app/dialect</property>
|
||||
<property name="website_label" translatable="yes">GitHub page</property>
|
||||
<property name="authors">gi-lom
|
||||
<property name="authors">
|
||||
Mufeed Ali
|
||||
Rafael Mardojai CM
|
||||
</property>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
<file>about.ui</file>
|
||||
<file>preferences.ui</file>
|
||||
<file>lang-selector.ui</file>
|
||||
<file>shortcuts-window.ui</file>
|
||||
<file>lang-row.ui</file>
|
||||
<file>shortcuts.ui</file>
|
||||
<file>style.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
|||
33
data/resources/lang-row.ui
Normal file
33
data/resources/lang-row.ui
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">6</property>
|
||||
<style>
|
||||
<class name="langselector"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="name" type="LangObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">object-select-symbolic</property>
|
||||
<binding name="visible">
|
||||
<lookup name="selected" type="LangObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -3,21 +3,13 @@
|
|||
<interface>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<template class="DialectLangSelector" parent="GtkPopover">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="height_request">250</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">8</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<property name="margin_top">8</property>
|
||||
<property name="margin_start">8</property>
|
||||
<property name="margin_end">8</property>
|
||||
|
|
@ -25,45 +17,31 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scroll">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="margin_bottom">8</property>
|
||||
<property name="margin_start">8</property>
|
||||
<property name="margin_end">8</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="revealer">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="reveal-child">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="recent_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<style>
|
||||
<class name="background"/>
|
||||
</style>
|
||||
<object class="GtkListView" id="recent_list">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin">8</property>
|
||||
<property name="margin-top">8</property>
|
||||
<property name="margin-bottom">8</property>
|
||||
<property name="margin-start">8</property>
|
||||
<property name="margin-end">8</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -71,13 +49,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="lang_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<style>
|
||||
<class name="background"/>
|
||||
</style>
|
||||
<object class="GtkListView" id="lang_list">
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -85,9 +57,6 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
|||
|
|
@ -1,28 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<requires lib="libhandy" version="1.0"/>
|
||||
<template class="DialectPreferencesWindow" parent="HdyPreferencesWindow">
|
||||
<template class="DialectPreferencesWindow" parent="AdwPreferencesWindow">
|
||||
<property name="default_height">420</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<child>
|
||||
<object class="HdyPreferencesPage">
|
||||
<property name="visible">True</property>
|
||||
<object class="AdwPreferencesPage">
|
||||
<child>
|
||||
<object class="HdyPreferencesGroup">
|
||||
<object class="AdwPreferencesGroup" id="appearance">
|
||||
<property name="title" translatable="yes">Appearance</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="visible">False</property>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Dark Mode</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="activatable_widget">dark_mode</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="dark_mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -31,155 +24,134 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyPreferencesGroup">
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Behavior</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Live Translation</property>
|
||||
<property name="subtitle" translatable="yes">Warning: Your IP address may get banned for API abuse.</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="activatable_widget">live_translation</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="live_translation">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyComboRow" id="translate_accel">
|
||||
<object class="AdwComboRow" id="translate_accel">
|
||||
<property name="title" translatable="yes">Translation Shortcut</property>
|
||||
<property name="subtitle" translatable="yes">The unselected choice will be used for line break.</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item>Ctrl + Enter</item>
|
||||
<item>Enter</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Default to Auto</property>
|
||||
<property name="subtitle" translatable="yes">Use "Auto" as the default language</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="activatable_widget">src_auto</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="src_auto">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyComboRow" id="backend">
|
||||
<object class="AdwComboRow" id="backend">
|
||||
<property name="title" translatable="yes">Translator</property>
|
||||
<property name="subtitle" translatable="yes">Choose from the available translation services.</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="expression">
|
||||
<lookup name="prettyname" type="BackendObject"></lookup>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="backend_instance_row">
|
||||
<object class="AdwActionRow" id="backend_instance_row">
|
||||
<property name="title" translatable="yes">Translator Instance</property>
|
||||
<property name="subtitle" translatable="yes">Enter a translation service URL.</property>
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="backend_instance_stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="transition-type">crossfade</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">end</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="backend_instance_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_edit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Edit</property>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">view</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">6</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">end</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
<object class="GtkLabel" id="backend_instance_label">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_edit">
|
||||
<property name="tooltip-text" translatable="yes">Edit</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">view</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="backend_instance_edit_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkEntry" id="backend_instance">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_reset">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Reset to default</property>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">edit</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox" id="backend_instance_edit_box">
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">view-refresh-symbolic</property>
|
||||
<object class="GtkEntry" id="backend_instance">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_reset">
|
||||
<property name="tooltip-text" translatable="yes">Reset to default</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">view-refresh-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_save">
|
||||
<property name="tooltip-text" translatable="yes">Save</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backend_instance_save">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Save</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">edit</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="tts_row">
|
||||
<object class="AdwActionRow" id="tts_row">
|
||||
<property name="title" translatable="yes">Text-to-Speech</property>
|
||||
<property name="subtitle" translatable="yes">Use Google for TTS.</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="activatable_widget">tts</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="tts">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -188,10 +160,9 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyPreferencesGroup" id="search_provider">
|
||||
<object class="AdwPreferencesGroup" id="search_provider">
|
||||
<property name="title" translatable="yes">Search Provider</property>
|
||||
<property name="description" translatable="yes">To reduce API abuse, the GNOME search provider in Dialect is turned off when Live translation is. Ensure the search provider is also turned on in the GNOME Settings.</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkShortcutsWindow" id="shortcuts">
|
||||
<object class="GtkShortcutsWindow" id="help_overlay">
|
||||
<property name="modal">True</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
|
|
@ -1,9 +1,19 @@
|
|||
.toolbox {
|
||||
|
||||
.main-box {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.translation-box {
|
||||
background: @theme_base_color;
|
||||
border: 1px solid @borders;
|
||||
border-bottom-left-radius: 9px;
|
||||
border-bottom-right-radius: 9px;
|
||||
border-top: 0;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.translation-box scrolledwindow {
|
||||
border-bottom: 1px solid @borders;
|
||||
}
|
||||
|
||||
.tools-box {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
|
|
@ -17,30 +27,6 @@
|
|||
border-top: 0;
|
||||
}
|
||||
|
||||
.translation-frame {
|
||||
background: @theme_base_color;
|
||||
border-top-left-radius: 9px;
|
||||
border-top-right-radius: 9px;
|
||||
}
|
||||
.translation-frame:disabled {
|
||||
background: @insensitive_bg_color;
|
||||
}
|
||||
.translation-frame:backdrop {
|
||||
background: @theme_unfocused_base_color;
|
||||
}
|
||||
|
||||
.translation-frame scrollbar {
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
.translation-frame scrollbar:dir(ltr) {
|
||||
border-top-right-radius: 9px;
|
||||
}
|
||||
|
||||
.translation-frame scrollbar:dir(rtl) {
|
||||
border-top-left-radius: 9px;
|
||||
}
|
||||
|
||||
.langselector {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import re
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
from gi.repository import Gio, GObject, Gtk
|
||||
|
||||
from dialect.define import RES_PATH
|
||||
from dialect.translators import get_lang_name
|
||||
|
|
@ -31,46 +31,56 @@ class DialectLangSelector(Gtk.Popover):
|
|||
# Connect popover closed signal
|
||||
self.connect('closed', self._closed)
|
||||
# Connect list signals
|
||||
self.recent_list.connect('row-activated', self._activated)
|
||||
self.lang_list.connect('row-activated', self._activated)
|
||||
# Set filter func to lang list
|
||||
self.lang_list.set_filter_func(self.filter_func, None, False)
|
||||
self.recent_list.connect('activate', self._activated)
|
||||
self.lang_list.connect('activate', self._activated)
|
||||
# Connect search entry changed signal
|
||||
self.search.connect('changed', self._update_search)
|
||||
|
||||
def filter_func(self, row, _data, _notify_destroy):
|
||||
search = self.search.get_text()
|
||||
return bool(re.search(search, row.name, re.IGNORECASE))
|
||||
self.factory = Gtk.BuilderListItemFactory.new_from_resource(
|
||||
None, f'{RES_PATH}/lang-row.ui'
|
||||
);
|
||||
|
||||
self.recent_model = Gio.ListStore.new(LangObject)
|
||||
selection_model = Gtk.SingleSelection.new(self.recent_model)
|
||||
selection_model.set_autoselect(False)
|
||||
self.recent_list.set_model(selection_model)
|
||||
self.recent_list.set_factory(self.factory)
|
||||
|
||||
self.lang_model = Gio.ListStore.new(LangObject)
|
||||
self.filter = Gtk.CustomFilter()
|
||||
self.filter.set_filter_func(self._filter_func)
|
||||
fitler_model = Gtk.FilterListModel.new(self.lang_model, self.filter)
|
||||
selection_model = Gtk.SingleSelection.new(fitler_model)
|
||||
selection_model.set_autoselect(False)
|
||||
self.lang_list.set_model(selection_model)
|
||||
self.lang_list.set_factory(self.factory)
|
||||
|
||||
def set_languages(self, languages):
|
||||
# Clear list
|
||||
children = self.lang_list.get_children()
|
||||
for child in children:
|
||||
self.lang_list.remove(child)
|
||||
self.lang_model.remove_all()
|
||||
|
||||
# Load langs list
|
||||
for code in languages:
|
||||
row_selected = (code == self.selected)
|
||||
self.lang_list.insert(LangRow(code, get_lang_name(code), row_selected), -1)
|
||||
self.lang_model.append(LangObject(code, get_lang_name(code)))
|
||||
|
||||
def insert_recent(self, code, name, position=-1):
|
||||
def insert_recent(self, code, name):
|
||||
row_selected = (code == self.selected)
|
||||
self.recent_list.insert(LangRow(code, name, row_selected), position)
|
||||
self.recent_model.append(LangObject(code, name, row_selected))
|
||||
|
||||
def clear_recent(self):
|
||||
children = self.recent_list.get_children()
|
||||
for child in children:
|
||||
self.recent_list.remove(child)
|
||||
self.recent_model.remove_all()
|
||||
|
||||
def refresh_selected(self):
|
||||
for lang in self.lang_list.get_children():
|
||||
lang.selected = (lang.code == self.selected)
|
||||
for item in self.lang_model:
|
||||
item.set_property('selected', (item.code == self.selected))
|
||||
|
||||
def _activated(self, _list, row):
|
||||
def _activated(self, list_view, index):
|
||||
# Close popover
|
||||
self.popdown()
|
||||
model = list_view.get_model()
|
||||
lang = model.get_selected_item()
|
||||
# Set selected property
|
||||
self.set_property('selected', row.code)
|
||||
self.set_property('selected', lang.code)
|
||||
|
||||
def _closed(self, _popover):
|
||||
# Reset scroll
|
||||
|
|
@ -79,39 +89,30 @@ class DialectLangSelector(Gtk.Popover):
|
|||
# Clear search
|
||||
self.search.set_text('')
|
||||
|
||||
def _filter_func(self, item):
|
||||
search = self.search.get_text()
|
||||
return bool(re.search(search, item.name, re.IGNORECASE))
|
||||
|
||||
def _update_search(self, _entry):
|
||||
search = self.search.get_text()
|
||||
if search != '':
|
||||
self.revealer.set_reveal_child(False)
|
||||
else:
|
||||
self.revealer.set_reveal_child(True)
|
||||
self.lang_list.invalidate_filter()
|
||||
|
||||
self.filter.emit('changed', Gtk.FilterChange.DIFFERENT)
|
||||
|
||||
|
||||
class LangRow(Gtk.ListBoxRow):
|
||||
class LangObject(GObject.Object):
|
||||
__gtype_name__ = 'LangObject'
|
||||
|
||||
def __init__(self, code, name, selected=False, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
code = GObject.Property(type=str)
|
||||
name = GObject.Property(type=str)
|
||||
selected = GObject.Property(type=bool, default=False)
|
||||
|
||||
self.code = code
|
||||
self.name = name
|
||||
def __init__(self, code, name, selected=False):
|
||||
super().__init__()
|
||||
|
||||
row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
|
||||
label = Gtk.Label(self.name,
|
||||
halign=Gtk.Align.START,
|
||||
margin_start=4)
|
||||
self.get_style_context().add_class('langselector')
|
||||
row_box.pack_start(label, False, True, 0)
|
||||
self.selected_icon = Gtk.Image.new_from_icon_name('object-select-symbolic', Gtk.IconSize.BUTTON)
|
||||
row_box.pack_start(self.selected_icon, False, True, 0)
|
||||
self.add(row_box)
|
||||
self.show_all()
|
||||
self.selected = selected
|
||||
|
||||
@property
|
||||
def selected(self):
|
||||
return self.selected_icon.get_visible()
|
||||
|
||||
@selected.setter
|
||||
def selected(self, value):
|
||||
self.selected_icon.set_visible(value)
|
||||
self.set_property('code', code)
|
||||
self.set_property('name', name)
|
||||
self.set_property('selected', selected)
|
||||
|
|
|
|||
133
dialect/main.py
133
dialect/main.py
|
|
@ -8,12 +8,12 @@ import sys
|
|||
from gettext import gettext as _
|
||||
|
||||
import gi
|
||||
gi.require_version('Gdk', '3.0')
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '4.0')
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Gst', '1.0')
|
||||
gi.require_version('Handy', '1')
|
||||
gi.require_version('Adw', '1')
|
||||
|
||||
from gi.repository import Gdk, Gio, GLib, Gst, Gtk, Handy
|
||||
from gi.repository import Adw, Gdk, Gio, GLib, Gst, Gtk
|
||||
|
||||
from dialect.define import APP_ID, RES_PATH
|
||||
from dialect.preferences import DialectPreferencesWindow
|
||||
|
|
@ -21,9 +21,9 @@ from dialect.settings import Settings
|
|||
from dialect.window import DialectWindow
|
||||
|
||||
|
||||
class Dialect(Gtk.Application):
|
||||
class Dialect(Adw.Application):
|
||||
def __init__(self, version):
|
||||
Gtk.Application.__init__(
|
||||
Adw.Application.__init__(
|
||||
self,
|
||||
application_id=APP_ID,
|
||||
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE
|
||||
|
|
@ -59,7 +59,6 @@ class Dialect(Gtk.Application):
|
|||
text=self.launch_text,
|
||||
langs=self.launch_langs
|
||||
)
|
||||
self.setup_actions_signals()
|
||||
|
||||
self.window.present()
|
||||
|
||||
|
|
@ -89,95 +88,50 @@ class Dialect(Gtk.Application):
|
|||
return 0
|
||||
|
||||
def do_startup(self):
|
||||
Gtk.Application.do_startup(self)
|
||||
GLib.set_application_name(_('Dialect'))
|
||||
GLib.set_prgname('com.github.gi_lom.dialect')
|
||||
Adw.Application.do_startup(self)
|
||||
|
||||
Handy.init() # Init Handy
|
||||
Gst.init(None) # Init Gst
|
||||
|
||||
# Load CSS
|
||||
css_provider = Gtk.CssProvider()
|
||||
css_provider.load_from_resource(f'{RES_PATH}/style.css')
|
||||
screen = Gdk.Screen.get_default()
|
||||
style_context = Gtk.StyleContext()
|
||||
style_context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def setup_actions(self):
|
||||
""" Setup menu actions """
|
||||
self.pronunciation_action = Gio.SimpleAction.new_stateful(
|
||||
|
||||
pronunciation = Gio.SimpleAction.new_stateful(
|
||||
'pronunciation', None, Settings.get().show_pronunciation_value
|
||||
)
|
||||
pronunciation.connect('change-state', self._on_pronunciation)
|
||||
self.add_action(pronunciation)
|
||||
|
||||
preferences = Gio.SimpleAction.new('preferences', None)
|
||||
preferences.connect('activate', self._on_preferences)
|
||||
self.add_action(preferences)
|
||||
|
||||
shortcuts = Gio.SimpleAction.new('shortcuts', None)
|
||||
shortcuts.connect('activate', self._on_shortcuts)
|
||||
self.add_action(shortcuts)
|
||||
|
||||
about = Gio.SimpleAction.new('about', None)
|
||||
about.connect('activate', self._on_about)
|
||||
self.add_action(about)
|
||||
|
||||
quit_action = Gio.SimpleAction.new('quit', None)
|
||||
quit_action.connect('activate', self._on_quit)
|
||||
self.add_action(quit_action)
|
||||
|
||||
self.set_accels_for_action('app.pronunciation', ['<Primary>P'])
|
||||
self.add_action(self.pronunciation_action)
|
||||
|
||||
self.preferences_action = Gio.SimpleAction.new('preferences', None)
|
||||
self.set_accels_for_action('app.preferences', ['<Primary>comma'])
|
||||
self.add_action(self.preferences_action)
|
||||
|
||||
self.shortcuts_action = Gio.SimpleAction.new('shortcuts', None)
|
||||
self.set_accels_for_action('app.shortcuts', ['<Primary>question'])
|
||||
self.add_action(self.shortcuts_action)
|
||||
|
||||
self.about_action = Gio.SimpleAction.new('about', None)
|
||||
self.add_action(self.about_action)
|
||||
|
||||
self.back_action = Gio.SimpleAction.new('back', None)
|
||||
self.back_action.set_enabled(False)
|
||||
self.set_accels_for_action('app.back', ['<Alt>Left'])
|
||||
self.add_action(self.back_action)
|
||||
|
||||
self.forward_action = Gio.SimpleAction.new('forward', None)
|
||||
self.forward_action.set_enabled(False)
|
||||
self.set_accels_for_action('app.forward', ['<Alt>Right'])
|
||||
self.add_action(self.forward_action)
|
||||
|
||||
self.switch_action = Gio.SimpleAction.new('switch', None)
|
||||
self.set_accels_for_action('app.switch', ['<Primary>S'])
|
||||
self.add_action(self.switch_action)
|
||||
|
||||
self.clear_action = Gio.SimpleAction.new('clear', None)
|
||||
self.clear_action.set_enabled(False)
|
||||
self.set_accels_for_action('app.clear', ['<Primary>D'])
|
||||
self.add_action(self.clear_action)
|
||||
|
||||
self.paste_action = Gio.SimpleAction.new('paste', None)
|
||||
self.set_accels_for_action('app.paste', ['<Primary><Shift>V'])
|
||||
self.add_action(self.paste_action)
|
||||
|
||||
self.copy_action = Gio.SimpleAction.new('copy', None)
|
||||
self.copy_action.set_enabled(False)
|
||||
self.set_accels_for_action('app.copy', ['<Primary><Shift>C'])
|
||||
self.add_action(self.copy_action)
|
||||
|
||||
self.listen_dest_action = Gio.SimpleAction.new('listen-dest', None)
|
||||
self.set_accels_for_action('app.listen-dest', ['<Primary>L'])
|
||||
self.add_action(self.listen_dest_action)
|
||||
|
||||
self.listen_src_action = Gio.SimpleAction.new('listen-src', None)
|
||||
self.set_accels_for_action('app.listen-src', ['<Primary><Shift>L'])
|
||||
self.add_action(self.listen_src_action)
|
||||
|
||||
self.quit_action = Gio.SimpleAction.new('quit', None)
|
||||
self.set_accels_for_action('app.quit', ['<Primary>Q'])
|
||||
self.add_action(self.quit_action)
|
||||
|
||||
def setup_actions_signals(self):
|
||||
self.pronunciation_action.connect('change-state', self.on_pronunciation)
|
||||
self.preferences_action.connect('activate', self.on_preferences)
|
||||
self.shortcuts_action.connect('activate', self.on_shortcuts)
|
||||
self.about_action.connect('activate', self.on_about)
|
||||
self.back_action.connect('activate', self.window.ui_return)
|
||||
self.forward_action.connect('activate', self.window.ui_forward)
|
||||
self.switch_action.connect('activate', self.window.ui_switch)
|
||||
self.clear_action.connect('activate', self.window.ui_clear)
|
||||
self.paste_action.connect('activate', self.window.ui_paste)
|
||||
self.copy_action.connect('activate', self.window.ui_copy)
|
||||
self.listen_dest_action.connect('activate', self.window.ui_dest_voice)
|
||||
self.listen_src_action.connect('activate', self.window.ui_src_voice)
|
||||
self.quit_action.connect('activate', self.on_quit)
|
||||
self.set_accels_for_action('win.back', ['<Alt>Left'])
|
||||
self.set_accels_for_action('win.forward', ['<Alt>Right'])
|
||||
self.set_accels_for_action('win.switch', ['<Primary>S'])
|
||||
self.set_accels_for_action('win.clear', ['<Primary>D'])
|
||||
self.set_accels_for_action('win.paste', ['<Primary><Shift>V'])
|
||||
self.set_accels_for_action('win.copy', ['<Primary><Shift>C'])
|
||||
self.set_accels_for_action('win.listen-dest', ['<Primary>L'])
|
||||
self.set_accels_for_action('win.listen-src', ['<Primary><Shift>L'])
|
||||
|
||||
def on_pronunciation(self, action, value):
|
||||
def _on_pronunciation(self, action, value):
|
||||
""" Update show pronunciation setting """
|
||||
action.set_state(value)
|
||||
Settings.get().show_pronunciation = value
|
||||
|
|
@ -188,33 +142,32 @@ class Dialect(Gtk.Application):
|
|||
if self.window.trans_dest_pron is not None:
|
||||
self.window.dest_pron_revealer.set_reveal_child(value)
|
||||
|
||||
def on_preferences(self, _action, _param):
|
||||
def _on_preferences(self, _action, _param):
|
||||
""" Show preferences window """
|
||||
window = DialectPreferencesWindow(self.window)
|
||||
window.set_transient_for(self.window)
|
||||
window.present()
|
||||
|
||||
def on_shortcuts(self, _action, _param):
|
||||
def _on_shortcuts(self, _action, _param):
|
||||
"""Launch the Keyboard Shortcuts window."""
|
||||
builder = Gtk.Builder.new_from_resource(f'{RES_PATH}/shortcuts-window.ui')
|
||||
builder = Gtk.Builder.new_from_resource(f'{RES_PATH}/shortcuts.ui')
|
||||
translate_shortcut = builder.get_object('translate_shortcut')
|
||||
translate_shortcut.set_visible(not Settings.get().live_translation)
|
||||
translate_shortcut.set_property('accelerator', Settings.get().translate_accel)
|
||||
shortcuts_window = builder.get_object('shortcuts')
|
||||
shortcuts_window = builder.get_object('help_overlay')
|
||||
shortcuts_window.set_transient_for(self.window)
|
||||
shortcuts_window.show()
|
||||
|
||||
def on_about(self, _action, _param):
|
||||
def _on_about(self, _action, _param):
|
||||
""" Show about dialog """
|
||||
builder = Gtk.Builder.new_from_resource(f'{RES_PATH}/about.ui')
|
||||
about = builder.get_object('about')
|
||||
about.set_transient_for(self.window)
|
||||
about.set_logo_icon_name(APP_ID)
|
||||
about.set_version(self.version)
|
||||
about.connect('response', lambda dialog, response: dialog.destroy())
|
||||
about.present()
|
||||
|
||||
def on_quit(self, _action, _param):
|
||||
def _on_quit(self, _action, _param):
|
||||
self.quit()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import re
|
|||
import threading
|
||||
from gettext import gettext as _
|
||||
|
||||
from gi.repository import Gio, GLib, GObject, Gtk, Handy
|
||||
from gi.repository import Adw, Gio, GLib, GObject, Gtk
|
||||
|
||||
from dialect.define import RES_PATH
|
||||
from dialect.settings import Settings
|
||||
|
|
@ -16,12 +16,13 @@ from dialect.tts import TTS
|
|||
|
||||
|
||||
@Gtk.Template(resource_path=f'{RES_PATH}/preferences.ui')
|
||||
class DialectPreferencesWindow(Handy.PreferencesWindow):
|
||||
class DialectPreferencesWindow(Adw.PreferencesWindow):
|
||||
__gtype_name__ = 'DialectPreferencesWindow'
|
||||
|
||||
parent = NotImplemented
|
||||
|
||||
# Get preferences widgets
|
||||
appearance = Gtk.Template.Child()
|
||||
dark_mode = Gtk.Template.Child()
|
||||
live_translation = Gtk.Template.Child()
|
||||
translate_accel = Gtk.Template.Child()
|
||||
|
|
@ -49,17 +50,12 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
def setup(self):
|
||||
# Disable search, we have few preferences
|
||||
self.set_search_enabled(False)
|
||||
# Temporal fix for crash
|
||||
self.connect('destroy', self._unbind_settings)
|
||||
|
||||
# Setup translate accel combo row
|
||||
model = Gio.ListStore.new(Handy.ValueObject)
|
||||
options = ['Ctrl + Enter', 'Enter']
|
||||
for index, value in enumerate(options):
|
||||
model.insert(index, Handy.ValueObject.new(value))
|
||||
self.translate_accel.bind_name_model(model,
|
||||
Handy.ValueObject.dup_string)
|
||||
|
||||
# Show dark mode preference
|
||||
self.style_manager = self.parent.app.get_style_manager()
|
||||
if not self.style_manager.get_system_supports_color_schemes():
|
||||
self.appearance.set_visible(True)
|
||||
|
||||
# Setup backends combo row
|
||||
self.backend_model = Gio.ListStore.new(BackendObject)
|
||||
backend_options = [
|
||||
|
|
@ -70,8 +66,7 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
self.backend_model.insert(index, value)
|
||||
if value.name == Settings.get().backend:
|
||||
selected_backend_index = index
|
||||
self.backend.bind_name_model(self.backend_model,
|
||||
BackendObject.get_name)
|
||||
self.backend.set_model(self.backend_model)
|
||||
|
||||
# Bind preferences with GSettings
|
||||
Settings.get().bind('dark-mode', self.dark_mode, 'active',
|
||||
|
|
@ -79,7 +74,7 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
Settings.get().bind('live-translation', self.live_translation, 'active',
|
||||
Gio.SettingsBindFlags.DEFAULT)
|
||||
Settings.get().bind('translate-accel', self.translate_accel,
|
||||
'selected-index', Gio.SettingsBindFlags.DEFAULT)
|
||||
'selected', Gio.SettingsBindFlags.DEFAULT)
|
||||
Settings.get().bind('src-auto', self.src_auto, 'active',
|
||||
Gio.SettingsBindFlags.DEFAULT)
|
||||
|
||||
|
|
@ -95,8 +90,8 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
self.live_translation.connect('notify::active', self._toggle_accel_pref)
|
||||
|
||||
# Switch backends
|
||||
self.backend.set_selected_index(selected_backend_index)
|
||||
self.backend.connect('notify::selected-index', self._switch_backends)
|
||||
self.backend.set_selected(selected_backend_index)
|
||||
self.backend.connect('notify::selected', self._switch_backends)
|
||||
self.parent.connect('notify::backend-loading', self._on_backend_loading)
|
||||
|
||||
# Toggle TTS
|
||||
|
|
@ -109,24 +104,30 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
self.backend_instance_reset.connect('clicked', self._on_reset_backend_instance)
|
||||
self.__check_instance_support()
|
||||
|
||||
self.instance_save_image = Gtk.Image.new_from_icon_name(
|
||||
'emblem-ok-symbolic', Gtk.IconSize.BUTTON)
|
||||
self.backend_instance_save.add(self.instance_save_image)
|
||||
self.instance_save_image = Gtk.Image.new_from_icon_name('emblem-ok-symbolic')
|
||||
self.backend_instance_save.set_child(self.instance_save_image)
|
||||
self.instance_save_spinner = Gtk.Spinner()
|
||||
self.instance_save_image.show()
|
||||
self.instance_save_spinner.show()
|
||||
|
||||
self.error_popover = Gtk.Popover(
|
||||
relative_to=self.backend_instance, can_focus=False, modal=False)
|
||||
pointing_to=self.backend_instance.get_allocation(),
|
||||
can_focus=False,
|
||||
)
|
||||
self.error_label = Gtk.Label(label='Not a valid instance')
|
||||
error_icon = Gtk.Image.new_from_icon_name(
|
||||
'dialog-error-symbolic', Gtk.IconSize.LARGE_TOOLBAR)
|
||||
error_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, margin=8, spacing=8)
|
||||
error_box.pack_start(error_icon, False, False, 0)
|
||||
error_box.pack_start(self.error_label, False, False, 0)
|
||||
self.error_popover.add(error_box)
|
||||
error_icon = Gtk.Image.new_from_icon_name('dialog-error-symbolic')
|
||||
error_box = Gtk.Box(
|
||||
orientation=Gtk.Orientation.HORIZONTAL,
|
||||
margin_start=8,
|
||||
margin_end=8,
|
||||
margin_top=8,
|
||||
margin_bottom=8,
|
||||
spacing=8
|
||||
)
|
||||
error_box.prepend(error_icon)
|
||||
error_box.prepend(self.error_label)
|
||||
self.error_popover.set_child(error_box)
|
||||
self.error_popover.set_position(Gtk.PositionType.BOTTOM)
|
||||
error_box.show_all()
|
||||
self.error_popover.hide()
|
||||
|
||||
# Search Provider
|
||||
|
|
@ -148,9 +149,12 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
self.parent.change_backends(backend)
|
||||
|
||||
def _toggle_dark_mode(self, switch, _active):
|
||||
gtk_settings = Gtk.Settings.get_default()
|
||||
active = switch.get_active()
|
||||
gtk_settings.set_property('gtk-application-prefer-dark-theme', active)
|
||||
if not self.style_manager.get_system_supports_color_schemes():
|
||||
active = switch.get_active()
|
||||
if active:
|
||||
self.style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK)
|
||||
else:
|
||||
self.style_manager.set_color_scheme(Adw.ColorScheme.DEFAULT)
|
||||
|
||||
def _toggle_accel_pref(self, switch, _active):
|
||||
self.translate_accel.set_sensitive(not switch.get_active())
|
||||
|
|
@ -175,7 +179,7 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
).start()
|
||||
|
||||
def _switch_backends(self, row, _value):
|
||||
backend = self.backend_model[row.get_selected_index()].name
|
||||
backend = self.backend_model[row.get_selected()].name
|
||||
Settings.get().backend = backend
|
||||
self.__check_instance_support()
|
||||
self.parent.change_backends(backend)
|
||||
|
|
@ -257,13 +261,13 @@ class DialectPreferencesWindow(Handy.PreferencesWindow):
|
|||
|
||||
|
||||
class BackendObject(GObject.Object):
|
||||
name = None
|
||||
prettyname = None
|
||||
__gtype_name__ = 'BackendObject'
|
||||
|
||||
name = GObject.Property(type=str)
|
||||
prettyname = GObject.Property(type=str)
|
||||
|
||||
def __init__(self, name, prettyname):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self.prettyname = prettyname
|
||||
|
||||
def get_name(self):
|
||||
return self.prettyname
|
||||
self.set_property('name', name)
|
||||
self.set_property('prettyname', prettyname)
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ class Settings(Gio.Settings):
|
|||
if settings is not None and settings.get('src-langs'):
|
||||
return settings.get('src-langs')
|
||||
|
||||
return TRANSLATORS[backend].src_langs
|
||||
return TRANSLATORS[backend].src_langsP
|
||||
|
||||
def set_src_langs(self, backend, langs):
|
||||
self._delete_arr_key(f'{backend}-src-langs') # Set deprecated key to unused state.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import threading
|
|||
from gettext import gettext as _
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from gi.repository import Gdk, GLib, GObject, Gst, Gtk, Handy
|
||||
from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gst, Gtk
|
||||
|
||||
from dialect.define import APP_ID, MAX_LENGTH, RES_PATH, TRANS_NUMBER
|
||||
from dialect.lang_selector import DialectLangSelector
|
||||
|
|
@ -17,7 +17,7 @@ from dialect.tts import TTS
|
|||
|
||||
|
||||
@Gtk.Template(resource_path=f'{RES_PATH}/window.ui')
|
||||
class DialectWindow(Handy.ApplicationWindow):
|
||||
class DialectWindow(Adw.ApplicationWindow):
|
||||
__gtype_name__ = 'DialectWindow'
|
||||
|
||||
# Get widgets
|
||||
|
|
@ -67,8 +67,10 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
notification_revealer = Gtk.Template.Child()
|
||||
notification_label = Gtk.Template.Child()
|
||||
|
||||
translator = None # Translator object
|
||||
src_key_ctrlr = Gtk.Template.Child()
|
||||
|
||||
# Translator
|
||||
translator = None # Translator object
|
||||
# Text to speech
|
||||
tts = None
|
||||
tts_langs = None
|
||||
|
|
@ -112,29 +114,27 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
bus.connect('message', self.on_gst_message)
|
||||
self.player_event = threading.Event() # An event for letting us know when Gst is done playing
|
||||
|
||||
# Clipboard
|
||||
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) # This is only for the Clipboard button
|
||||
|
||||
# Setup window
|
||||
self.setup_actions()
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
self.set_default_icon_name(APP_ID)
|
||||
|
||||
# Load saved dark mode
|
||||
gtk_settings = Gtk.Settings.get_default()
|
||||
gtk_settings.set_property('gtk-application-prefer-dark-theme',
|
||||
Settings.get().dark_mode)
|
||||
style_manager = self.app.get_style_manager()
|
||||
if not style_manager.get_system_supports_color_schemes() and Settings.get().dark_mode:
|
||||
style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK)
|
||||
|
||||
# Connect responsive design function
|
||||
self.connect('check-resize', self.responsive_listener)
|
||||
self.connect('notify::default-width', self.responsive_listener)
|
||||
self.connect('notify::maximized', self.responsive_listener)
|
||||
# Save settings on close
|
||||
self.connect('delete-event', self.save_settings)
|
||||
self.connect('unrealize', self.save_settings)
|
||||
|
||||
self.setup_headerbar()
|
||||
self.setup_actionbar()
|
||||
self.setup_translation()
|
||||
self.toggle_mobile_mode()
|
||||
self.responsive_listener(launch=True)
|
||||
|
||||
# Load translator
|
||||
self.retry_backend_btn.connect('clicked', self.retry_load_translator)
|
||||
|
|
@ -147,6 +147,43 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
if Settings.get().tts != '':
|
||||
threading.Thread(target=self.load_lang_speech, daemon=True).start()
|
||||
|
||||
def setup_actions(self):
|
||||
back = Gio.SimpleAction.new('back', None)
|
||||
back.set_enabled(False)
|
||||
back.connect('activate', self.ui_return)
|
||||
self.add_action(back)
|
||||
|
||||
forward_action = Gio.SimpleAction.new('forward', None)
|
||||
forward_action.set_enabled(False)
|
||||
forward_action.connect('activate', self.ui_forward)
|
||||
self.add_action(forward_action)
|
||||
|
||||
switch_action = Gio.SimpleAction.new('switch', None)
|
||||
switch_action.connect('activate', self.ui_switch)
|
||||
self.add_action(switch_action)
|
||||
|
||||
clear_action = Gio.SimpleAction.new('clear', None)
|
||||
clear_action.set_enabled(False)
|
||||
clear_action.connect('activate', self.ui_clear)
|
||||
self.add_action(clear_action)
|
||||
|
||||
paste_action = Gio.SimpleAction.new('paste', None)
|
||||
paste_action.connect('activate', self.ui_paste)
|
||||
self.add_action(paste_action)
|
||||
|
||||
copy_action = Gio.SimpleAction.new('copy', None)
|
||||
copy_action.set_enabled(False)
|
||||
copy_action.connect('activate', self.ui_copy)
|
||||
self.add_action(copy_action)
|
||||
|
||||
listen_dest_action = Gio.SimpleAction.new('listen-dest', None)
|
||||
listen_dest_action.connect('activate', self.ui_dest_voice)
|
||||
self.add_action(listen_dest_action)
|
||||
|
||||
listen_src_action = Gio.SimpleAction.new('listen-src', None)
|
||||
listen_src_action.connect('activate', self.ui_src_voice)
|
||||
self.add_action(listen_src_action)
|
||||
|
||||
def load_translator(self, backend, launch=False):
|
||||
def update_ui():
|
||||
# Supported features
|
||||
|
|
@ -156,9 +193,9 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
if not self.translator.supported_features['pronunciation']:
|
||||
self.src_pron_revealer.set_reveal_child(False)
|
||||
self.dest_pron_revealer.set_reveal_child(False)
|
||||
self.app.pronunciation_action.set_enabled(False)
|
||||
self.app.lookup_action('pronunciation').set_enabled(False)
|
||||
else:
|
||||
self.app.pronunciation_action.set_enabled(True)
|
||||
self.app.lookup_action('pronunciation').set_enabled(True)
|
||||
|
||||
self.no_retranslate = True
|
||||
# Update langs list
|
||||
|
|
@ -225,10 +262,10 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
).start()
|
||||
|
||||
def on_listen_failed(self):
|
||||
self.src_voice_btn.set_image(self.src_voice_warning)
|
||||
self.src_voice_btn.set_child(self.src_voice_warning)
|
||||
self.src_voice_spinner.stop()
|
||||
|
||||
self.dest_voice_btn.set_image(self.dest_voice_warning)
|
||||
self.dest_voice_btn.set_child(self.dest_voice_warning)
|
||||
self.dest_voice_spinner.stop()
|
||||
|
||||
tooltip_text = _('A network issue has occured. Retry?')
|
||||
|
|
@ -249,17 +286,17 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
)
|
||||
|
||||
if self.tts_langs:
|
||||
self.app.listen_src_action.set_enabled(
|
||||
self.lookup_action('listen-src').set_enabled(
|
||||
self.src_lang_selector.get_property('selected') in self.tts_langs
|
||||
and src_text != ''
|
||||
)
|
||||
self.app.listen_dest_action.set_enabled(
|
||||
self.lookup_action('listen-dest').set_enabled(
|
||||
self.dest_lang_selector.get_property('selected') in self.tts_langs
|
||||
and dest_text != ''
|
||||
)
|
||||
else:
|
||||
self.app.listen_src_action.set_enabled(src_text != '')
|
||||
self.app.listen_dest_action.set_enabled(dest_text != '')
|
||||
self.lookup_action('listen-src').set_enabled(src_text != '')
|
||||
self.lookup_action('listen-dest').set_enabled(dest_text != '')
|
||||
|
||||
def load_lang_speech(self, listen=False, text=None, language=None):
|
||||
"""
|
||||
|
|
@ -290,7 +327,6 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.on_src_lang_changed)
|
||||
# Set popover selector to button
|
||||
self.src_lang_btn.set_popover(self.src_lang_selector)
|
||||
self.src_lang_selector.set_relative_to(self.src_lang_btn)
|
||||
|
||||
# Right lang selector
|
||||
self.dest_lang_selector = DialectLangSelector()
|
||||
|
|
@ -298,28 +334,23 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.on_dest_lang_changed)
|
||||
# Set popover selector to button
|
||||
self.dest_lang_btn.set_popover(self.dest_lang_selector)
|
||||
self.dest_lang_selector.set_relative_to(self.dest_lang_btn)
|
||||
|
||||
self.langs_button_box.set_homogeneous(False)
|
||||
|
||||
# Add menu to menu button
|
||||
builder = Gtk.Builder.new_from_resource(f'{RES_PATH}/menu.ui')
|
||||
menu = builder.get_object('app-menu')
|
||||
menu_popover = Gtk.Popover.new_from_model(self.menu_btn, menu)
|
||||
menu_popover = Gtk.PopoverMenu.new_from_model(menu)
|
||||
self.menu_btn.set_popover(menu_popover)
|
||||
|
||||
def setup_actionbar(self):
|
||||
# Set popovers to lang buttons
|
||||
self.src_lang_btn2.set_popover(self.src_lang_selector)
|
||||
self.dest_lang_btn2.set_popover(self.dest_lang_selector)
|
||||
|
||||
def setup_translation(self):
|
||||
# Left buffer
|
||||
self.src_buffer = self.src_text.get_buffer()
|
||||
self.src_buffer.set_text(self.launch_text)
|
||||
self.src_buffer.connect('changed', self.on_src_text_changed)
|
||||
self.src_buffer.connect('end-user-action', self.user_action_ended)
|
||||
self.connect('key-press-event', self.update_trans_button)
|
||||
# Detect typing
|
||||
self.src_key_ctrlr.connect('key-pressed', self.update_trans_button)
|
||||
# Translate button
|
||||
self.translate_btn.connect('clicked', self.translation)
|
||||
# "Did you mean" links
|
||||
|
|
@ -334,16 +365,12 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.trans_warning.hide()
|
||||
|
||||
# Voice buttons prep-work
|
||||
self.src_voice_warning = Gtk.Image.new_from_icon_name(
|
||||
'dialog-warning-symbolic', Gtk.IconSize.BUTTON)
|
||||
self.src_voice_image = Gtk.Image.new_from_icon_name(
|
||||
'audio-speakers-symbolic', Gtk.IconSize.BUTTON)
|
||||
self.src_voice_warning = Gtk.Image.new_from_icon_name('dialog-warning-symbolic')
|
||||
self.src_voice_image = Gtk.Image.new_from_icon_name('audio-speakers-symbolic')
|
||||
self.src_voice_spinner = Gtk.Spinner() # For use while audio is running or still loading.
|
||||
|
||||
self.dest_voice_warning = Gtk.Image.new_from_icon_name(
|
||||
'dialog-warning-symbolic', Gtk.IconSize.BUTTON)
|
||||
self.dest_voice_image = Gtk.Image.new_from_icon_name(
|
||||
'audio-speakers-symbolic', Gtk.IconSize.BUTTON)
|
||||
self.dest_voice_warning = Gtk.Image.new_from_icon_name('dialog-warning-symbolic')
|
||||
self.dest_voice_image = Gtk.Image.new_from_icon_name('audio-speakers-symbolic')
|
||||
self.dest_voice_spinner = Gtk.Spinner()
|
||||
|
||||
self.toggle_voice_spinner(True)
|
||||
|
|
@ -351,10 +378,15 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.src_voice_btn.set_visible(Settings.get().tts != '')
|
||||
self.dest_voice_btn.set_visible(Settings.get().tts != '')
|
||||
|
||||
def responsive_listener(self, _window):
|
||||
size = self.get_size()
|
||||
def responsive_listener(self, _window=None, _param=None, launch=False):
|
||||
if launch:
|
||||
width, height = Settings.get().window_size
|
||||
else:
|
||||
size = self.get_default_size()
|
||||
width = size.width
|
||||
height = size.height
|
||||
|
||||
if size.width < 680:
|
||||
if width < 680 and not self.is_maximized():
|
||||
if self.mobile_mode is False:
|
||||
self.mobile_mode = True
|
||||
self.toggle_mobile_mode()
|
||||
|
|
@ -363,6 +395,9 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.mobile_mode = False
|
||||
self.toggle_mobile_mode()
|
||||
|
||||
if launch:
|
||||
self.set_default_size(width, height)
|
||||
|
||||
def toggle_mobile_mode(self):
|
||||
if self.mobile_mode:
|
||||
# Show actionbar
|
||||
|
|
@ -372,8 +407,10 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
# Change translation box orientation
|
||||
self.translator_box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
# Change lang selectors position
|
||||
self.src_lang_selector.set_relative_to(self.src_lang_btn2)
|
||||
self.dest_lang_selector.set_relative_to(self.dest_lang_btn2)
|
||||
self.src_lang_btn.set_popover(None)
|
||||
self.src_lang_btn2.set_popover(self.src_lang_selector)
|
||||
self.dest_lang_btn.set_popover(None)
|
||||
self.dest_lang_btn2.set_popover(self.dest_lang_selector)
|
||||
else:
|
||||
# Hide actionbar
|
||||
self.actionbar.set_reveal_child(False)
|
||||
|
|
@ -382,8 +419,10 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
# Reset translation box orientation
|
||||
self.translator_box.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
# Reset lang selectors position
|
||||
self.src_lang_selector.set_relative_to(self.src_lang_btn)
|
||||
self.dest_lang_selector.set_relative_to(self.dest_lang_btn)
|
||||
self.src_lang_btn2.set_popover(None)
|
||||
self.src_lang_btn.set_popover(self.src_lang_selector)
|
||||
self.dest_lang_btn2.set_popover(None)
|
||||
self.dest_lang_btn.set_popover(self.dest_lang_selector)
|
||||
|
||||
def translate(self, text, src_lang, dest_lang):
|
||||
"""
|
||||
|
|
@ -404,7 +443,7 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
|
||||
def save_settings(self, *args, **kwargs):
|
||||
if not self.is_maximized():
|
||||
size = self.get_size()
|
||||
size = self.get_default_size()
|
||||
Settings.get().window_size = (size.width, size.height)
|
||||
if self.translator is not None:
|
||||
Settings.get().set_src_langs(self.translator.name, self.src_langs)
|
||||
|
|
@ -430,12 +469,12 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
|
||||
def toggle_voice_spinner(self, active=True):
|
||||
if active:
|
||||
self.app.listen_src_action.set_enabled(False)
|
||||
self.src_voice_btn.set_image(self.src_voice_spinner)
|
||||
self.lookup_action('listen-src').set_enabled(False)
|
||||
self.src_voice_btn.set_child(self.src_voice_spinner)
|
||||
self.src_voice_spinner.start()
|
||||
|
||||
self.app.listen_dest_action.set_enabled(False)
|
||||
self.dest_voice_btn.set_image(self.dest_voice_spinner)
|
||||
self.lookup_action('listen-dest').set_enabled(False)
|
||||
self.dest_voice_btn.set_child(self.dest_voice_spinner)
|
||||
self.dest_voice_spinner.start()
|
||||
else:
|
||||
src_text = self.src_buffer.get_text(
|
||||
|
|
@ -443,11 +482,11 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.src_buffer.get_end_iter(),
|
||||
True
|
||||
)
|
||||
self.app.listen_src_action.set_enabled(
|
||||
self.lookup_action('listen-src').set_enabled(
|
||||
self.src_lang_selector.get_property('selected') in self.tts_langs
|
||||
and src_text != ''
|
||||
)
|
||||
self.src_voice_btn.set_image(self.src_voice_image)
|
||||
self.src_voice_btn.set_child(self.src_voice_image)
|
||||
self.src_voice_spinner.stop()
|
||||
|
||||
dest_text = self.dest_buffer.get_text(
|
||||
|
|
@ -455,11 +494,11 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.dest_buffer.get_end_iter(),
|
||||
True
|
||||
)
|
||||
self.app.listen_dest_action.set_enabled(
|
||||
self.lookup_action('listen-dest').set_enabled(
|
||||
self.dest_lang_selector.get_property('selected') in self.tts_langs
|
||||
and dest_text != ''
|
||||
)
|
||||
self.dest_voice_btn.set_image(self.dest_voice_image)
|
||||
self.dest_voice_btn.set_child(self.dest_voice_image)
|
||||
self.dest_voice_spinner.stop()
|
||||
|
||||
def on_src_lang_changed(self, _obj, _param):
|
||||
|
|
@ -479,8 +518,9 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
|
||||
# Disable or enable listen function.
|
||||
if self.tts_langs and Settings.get().tts != '':
|
||||
self.app.listen_src_action.set_enabled(code in self.tts_langs
|
||||
and src_text != '')
|
||||
self.lookup_action('listen-src').set_enabled(
|
||||
code in self.tts_langs and src_text != ''
|
||||
)
|
||||
|
||||
if code in self.translator.languages:
|
||||
self.src_lang_label.set_label(get_lang_name(code))
|
||||
|
|
@ -526,8 +566,9 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
|
||||
# Disable or enable listen function.
|
||||
if self.tts_langs and Settings.get().tts != '':
|
||||
self.app.listen_dest_action.set_enabled(code in self.tts_langs
|
||||
and dest_text != '')
|
||||
self.lookup_action('listen-dest').set_enabled(
|
||||
code in self.tts_langs and dest_text != ''
|
||||
)
|
||||
|
||||
self.dest_lang_label.set_label(get_lang_name(code))
|
||||
# Update saved dest langs list
|
||||
|
|
@ -642,14 +683,20 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.dest_buffer.get_end_iter(),
|
||||
True
|
||||
)
|
||||
self.clipboard.set_text(dest_text, -1)
|
||||
self.clipboard.store()
|
||||
clipboard = Gdk.Display.get_default().get_clipboard()
|
||||
clipboard.set(dest_text)
|
||||
|
||||
def ui_paste(self, _action, _param):
|
||||
text = self.clipboard.wait_for_text()
|
||||
if text is not None:
|
||||
end_iter = self.src_buffer.get_end_iter()
|
||||
self.src_buffer.insert(end_iter, text)
|
||||
clipboard = Gdk.Display.get_default().get_clipboard()
|
||||
|
||||
def on_paste(_clipboard, result):
|
||||
text = clipboard.read_text_finish(result)
|
||||
if text is not None:
|
||||
end_iter = self.src_buffer.get_end_iter()
|
||||
self.src_buffer.insert(end_iter, text)
|
||||
|
||||
cancellable = Gio.Cancellable()
|
||||
clipboard.read_text_async(cancellable, on_paste)
|
||||
|
||||
def ui_src_voice(self, _action, _param):
|
||||
src_text = self.src_buffer.get_text(
|
||||
|
|
@ -713,27 +760,28 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
self.voice_loading = False
|
||||
|
||||
# This starts the translation if Ctrl+Enter button is pressed
|
||||
def update_trans_button(self, button, keyboard):
|
||||
modifiers = keyboard.get_state() & Gtk.accelerator_get_default_mod_mask()
|
||||
def update_trans_button(self, _button, keyval, _keycode, state):
|
||||
modifiers = state & Gtk.accelerator_get_default_mod_mask()
|
||||
|
||||
control_mask = Gdk.ModifierType.CONTROL_MASK
|
||||
shift_mask = Gdk.ModifierType.SHIFT_MASK
|
||||
unicode_key_val = Gdk.keyval_to_unicode(keyboard.keyval)
|
||||
enter_keys = (Gdk.KEY_Return, Gdk.KEY_KP_Enter)
|
||||
if (GLib.unichar_isgraph(chr(unicode_key_val)) and
|
||||
modifiers in (shift_mask, 0) and not self.src_text.is_focus()):
|
||||
self.src_text.grab_focus()
|
||||
# Disabled until I find better ways to make it work.
|
||||
# shift_mask = Gdk.ModifierType.SHIFT_MASK
|
||||
# unicode_key_val = Gdk.keyval_to_unicode(keyval)
|
||||
# if (GLib.unichar_isgraph(chr(unicode_key_val)) and
|
||||
# modifiers in (shift_mask, 0) and not self.src_text.is_focus()):
|
||||
# self.src_text.grab_focus()
|
||||
|
||||
if not Settings.get().live_translation:
|
||||
if control_mask == modifiers:
|
||||
if keyboard.keyval in enter_keys:
|
||||
if keyval in enter_keys:
|
||||
if not Settings.get().translate_accel_value:
|
||||
self.translation(button)
|
||||
self.translation(None)
|
||||
return Gdk.EVENT_STOP
|
||||
return Gdk.EVENT_PROPAGATE
|
||||
elif keyboard.keyval in enter_keys:
|
||||
elif keyval in enter_keys:
|
||||
if Settings.get().translate_accel_value:
|
||||
self.translation(button)
|
||||
self.translation(None)
|
||||
return Gdk.EVENT_STOP
|
||||
return Gdk.EVENT_PROPAGATE
|
||||
|
||||
|
|
@ -748,25 +796,25 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
def on_src_text_changed(self, buffer):
|
||||
sensitive = buffer.get_char_count() != 0
|
||||
self.translate_btn.set_sensitive(sensitive)
|
||||
self.app.clear_action.set_enabled(sensitive)
|
||||
self.lookup_action('clear').set_enabled(sensitive)
|
||||
if not self.voice_loading and self.tts_langs:
|
||||
self.app.listen_src_action.set_enabled(
|
||||
self.lookup_action('listen-src').set_enabled(
|
||||
self.src_lang_selector.get_property('selected') in self.tts_langs
|
||||
and sensitive
|
||||
)
|
||||
elif not self.voice_loading and not self.tts_langs:
|
||||
self.app.listen_src_action.set_enabled(sensitive)
|
||||
self.lookup_action('listen-src').set_enabled(sensitive)
|
||||
|
||||
def on_dest_text_changed(self, buffer):
|
||||
sensitive = buffer.get_char_count() != 0
|
||||
self.app.copy_action.set_enabled(sensitive)
|
||||
self.lookup_action('copy').set_enabled(sensitive)
|
||||
if not self.voice_loading and self.tts_langs:
|
||||
self.app.listen_dest_action.set_enabled(
|
||||
self.lookup_action('listen-dest').set_enabled(
|
||||
self.dest_lang_selector.get_property('selected') in self.tts_langs
|
||||
and sensitive
|
||||
)
|
||||
elif not self.voice_loading and not self.tts_langs:
|
||||
self.app.listen_dest_action.set_enabled(sensitive)
|
||||
self.lookup_action('listen-dest').set_enabled(sensitive)
|
||||
|
||||
def user_action_ended(self, buffer):
|
||||
# If the text is over the highest number of characters allowed, it is truncated.
|
||||
|
|
@ -785,8 +833,8 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
|
||||
# The history part
|
||||
def reset_return_forward_btns(self):
|
||||
self.app.back_action.set_enabled(self.current_history < len(self.translator.history) - 1)
|
||||
self.app.forward_action.set_enabled(self.current_history > 0)
|
||||
self.lookup_action('back').set_enabled(self.current_history < len(self.translator.history) - 1)
|
||||
self.lookup_action('forward').set_enabled(self.current_history > 0)
|
||||
|
||||
# Retrieve translation history
|
||||
def history_update(self):
|
||||
|
|
@ -875,9 +923,9 @@ class DialectWindow(Handy.ApplicationWindow):
|
|||
def on_trans_failed():
|
||||
self.trans_warning.show()
|
||||
self.send_notification(_('Translation failed.\nPlease check for network issues.'))
|
||||
self.app.copy_action.set_enabled(False)
|
||||
self.app.listen_src_action.set_enabled(False)
|
||||
self.app.listen_dest_action.set_enabled(False)
|
||||
self.lookup_action('copy').set_enabled(False)
|
||||
self.lookup_action('listen-src').set_enabled(False)
|
||||
self.lookup_action('listen-dest').set_enabled(False)
|
||||
|
||||
def on_trans_success():
|
||||
self.trans_warning.hide()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
project('dialect',
|
||||
version: '1.4.1',
|
||||
version: '2.0.0',
|
||||
meson_version: '>= 0.50.0',
|
||||
default_options: [ 'warning_level=2',
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue