Stanislav N. aka pztrn
bd04870aa3
Splitted sidebar's list into two separate lists - one for general server's info (hostname, players, etc.) and one for players list. Also, moved CVars list to separate window which can be shown by clicking approriate button under player's list.
751 lines
29 KiB
Go
751 lines
29 KiB
Go
package ui
|
|
|
|
import (
|
|
// stdlib
|
|
"encoding/base64"
|
|
"fmt"
|
|
"runtime"
|
|
"strconv"
|
|
|
|
// local
|
|
"github.com/pztrn/urtrator/common"
|
|
|
|
// Other
|
|
"github.com/mattn/go-gtk/gdkpixbuf"
|
|
"github.com/mattn/go-gtk/glib"
|
|
"github.com/mattn/go-gtk/gtk"
|
|
)
|
|
|
|
// Main window initialization.
|
|
func (m *MainWindow) Initialize() {
|
|
|
|
gtk.Init(nil)
|
|
|
|
m.initializeStorages()
|
|
ctx.InitializeClipboardWatcher()
|
|
|
|
m.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
|
|
m.window.SetTitle("URTrator")
|
|
m.window.Connect("destroy", m.Close)
|
|
m.vbox = gtk.NewVBox(false, 0)
|
|
|
|
// Load program icon from base64.
|
|
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
|
|
icon_pixbuf := gdkpixbuf.NewLoader()
|
|
icon_pixbuf.Write(icon_bytes)
|
|
logo = icon_pixbuf.GetPixbuf()
|
|
m.window.SetIcon(logo)
|
|
|
|
m.window.Connect("configure-event", m.checkPositionAndSize)
|
|
|
|
// Additional OS-specific initialization.
|
|
if runtime.GOOS == "windows" {
|
|
m.initializeWin()
|
|
}
|
|
if runtime.GOOS == "darwin" {
|
|
m.initializeMac()
|
|
}
|
|
|
|
// Restoring window position.
|
|
var win_pos_x_str string = "0"
|
|
var win_pos_y_str string = "0"
|
|
saved_win_pos_x_str, ok := ctx.Cfg.Cfg["/mainwindow/position_x"]
|
|
if ok {
|
|
win_pos_x_str = saved_win_pos_x_str
|
|
}
|
|
saved_win_pos_y_str, ok := ctx.Cfg.Cfg["/mainwindow/position_y"]
|
|
if ok {
|
|
win_pos_y_str = saved_win_pos_y_str
|
|
}
|
|
win_pos_x, _ := strconv.Atoi(win_pos_x_str)
|
|
win_pos_y, _ := strconv.Atoi(win_pos_y_str)
|
|
m.window.Move(win_pos_x, win_pos_y)
|
|
|
|
// Restoring window size.
|
|
var win_size_width_str string = "1000"
|
|
var win_size_height_str string = "600"
|
|
saved_win_size_width_str, ok := ctx.Cfg.Cfg["/mainwindow/width"]
|
|
if ok {
|
|
win_size_width_str = saved_win_size_width_str
|
|
}
|
|
saved_win_size_height_str, ok := ctx.Cfg.Cfg["/mainwindow/height"]
|
|
if ok {
|
|
win_size_height_str = saved_win_size_height_str
|
|
}
|
|
|
|
m.window_width, _ = strconv.Atoi(win_size_width_str)
|
|
m.window_height, _ = strconv.Atoi(win_size_height_str)
|
|
m.window.SetDefaultSize(m.window_width, m.window_height)
|
|
|
|
// Set some GTK options for this window.
|
|
gtk_opts_raw := gtk.SettingsGetDefault()
|
|
gtk_opts := gtk_opts_raw.ToGObject()
|
|
gtk_opts.Set("gtk-button-images", true)
|
|
|
|
// Dialogs initialization.
|
|
m.options_dialog = &OptionsDialog{}
|
|
m.server_cvars_dialog = &ServerCVarsDialog{}
|
|
|
|
// Main menu.
|
|
if runtime.GOOS == "darwin" {
|
|
m.initializeMacMenu()
|
|
} else {
|
|
m.InitializeMainMenu()
|
|
}
|
|
|
|
// Toolbar.
|
|
m.InitializeToolbar()
|
|
|
|
m.hpane = gtk.NewHPaned()
|
|
m.vbox.PackStart(m.hpane, true, true, 5)
|
|
m.hpane.Connect("event", m.checkMainPanePosition)
|
|
|
|
// Restore pane position.
|
|
// We will restore saved thing, or will use "window_width - 150".
|
|
saved_pane_pos, ok := ctx.Cfg.Cfg["/mainwindow/pane_negative_position"]
|
|
if ok {
|
|
pane_negative_pos, _ := strconv.Atoi(saved_pane_pos)
|
|
m.hpane.SetPosition(m.window_width - pane_negative_pos)
|
|
} else {
|
|
var w, h int = 0, 0
|
|
m.window.GetSize(&w, &h)
|
|
m.hpane.SetPosition(w - 150)
|
|
}
|
|
|
|
// Tabs initialization.
|
|
m.InitializeTabs()
|
|
|
|
// Sidebar initialization.
|
|
m.initializeSidebar()
|
|
|
|
// Tray icon.
|
|
if ctx.Cfg.Cfg["/general/show_tray_icon"] == "1" {
|
|
m.initializeTrayIcon()
|
|
}
|
|
|
|
// Events.
|
|
m.initializeEvents()
|
|
|
|
// Game profiles and launch button.
|
|
profile_and_launch_hbox := gtk.NewHBox(false, 0)
|
|
m.vbox.PackStart(profile_and_launch_hbox, false, true, 5)
|
|
|
|
// Separator
|
|
sep := gtk.NewHBox(false, 0)
|
|
profile_and_launch_hbox.PackStart(sep, true, true, 5)
|
|
|
|
// Profile selection.
|
|
profiles_label := gtk.NewLabel("Game profile:")
|
|
m.profiles = gtk.NewComboBoxText()
|
|
m.profiles.SetTooltipText("Profile which will be used for launching")
|
|
|
|
profile_and_launch_hbox.PackStart(profiles_label, false, true, 5)
|
|
profile_and_launch_hbox.PackStart(m.profiles, false, true, 5)
|
|
|
|
// One more separator.
|
|
sepp := gtk.NewVSeparator()
|
|
profile_and_launch_hbox.PackStart(sepp, false, true, 5)
|
|
|
|
// Game launching button.
|
|
m.launch_button = gtk.NewButtonWithLabel("Launch!")
|
|
m.launch_button.SetTooltipText("Launch Urban Terror")
|
|
m.launch_button.Clicked(m.launchGame)
|
|
launch_button_image := gtk.NewImageFromPixbuf(logo.ScaleSimple(24, 24, gdkpixbuf.INTERP_HYPER))
|
|
m.launch_button.SetImage(launch_button_image)
|
|
profile_and_launch_hbox.PackStart(m.launch_button, false, true, 5)
|
|
|
|
m.window.Add(m.vbox)
|
|
|
|
m.window.ShowAll()
|
|
|
|
// Launch events.
|
|
ctx.Eventer.LaunchEvent("loadProfiles", map[string]string{})
|
|
ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{})
|
|
ctx.Eventer.LaunchEvent("loadServersIntoCache", map[string]string{})
|
|
ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{})
|
|
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "URTrator is ready."})
|
|
|
|
// Set flag that shows to other parts that we're initialized.
|
|
m.initialized = true
|
|
|
|
gtk.Main()
|
|
}
|
|
|
|
// Events initialization.
|
|
func (m *MainWindow) initializeEvents() {
|
|
fmt.Println("Initializing events...")
|
|
ctx.Eventer.AddEventHandler("loadAllServers", m.loadAllServers)
|
|
ctx.Eventer.AddEventHandler("loadFavoriteServers", m.loadFavoriteServers)
|
|
ctx.Eventer.AddEventHandler("loadProfilesIntoMainWindow", m.loadProfiles)
|
|
ctx.Eventer.AddEventHandler("serversUpdateCompleted", m.serversUpdateCompleted)
|
|
ctx.Eventer.AddEventHandler("setQuickConnectDetails", m.setQuickConnectDetails)
|
|
ctx.Eventer.AddEventHandler("setToolbarLabelText", m.setToolbarLabelText)
|
|
}
|
|
|
|
// Main menu initialization.
|
|
func (m *MainWindow) InitializeMainMenu() {
|
|
m.menubar = gtk.NewMenuBar()
|
|
m.vbox.PackStart(m.menubar, false, false, 0)
|
|
|
|
// File menu.
|
|
fm := gtk.NewMenuItemWithMnemonic("File")
|
|
m.menubar.Append(fm)
|
|
file_menu := gtk.NewMenu()
|
|
fm.SetSubmenu(file_menu)
|
|
|
|
// Options.
|
|
options_menu_item := gtk.NewMenuItemWithMnemonic("_Options")
|
|
file_menu.Append(options_menu_item)
|
|
options_menu_item.Connect("activate", m.options_dialog.ShowOptionsDialog)
|
|
|
|
// Separator.
|
|
file_menu_sep1 := gtk.NewSeparatorMenuItem()
|
|
file_menu.Append(file_menu_sep1)
|
|
|
|
// Exit.
|
|
exit_menu_item := gtk.NewMenuItemWithMnemonic("E_xit")
|
|
file_menu.Append(exit_menu_item)
|
|
exit_menu_item.Connect("activate", m.Close)
|
|
|
|
// About menu.
|
|
am := gtk.NewMenuItemWithMnemonic("_About")
|
|
m.menubar.Append(am)
|
|
about_menu := gtk.NewMenu()
|
|
am.SetSubmenu(about_menu)
|
|
|
|
// About app item.
|
|
about_app_item := gtk.NewMenuItemWithMnemonic("About _URTrator...")
|
|
about_menu.Append(about_app_item)
|
|
about_app_item.Connect("activate", ShowAboutDialog)
|
|
|
|
// Separator.
|
|
about_menu_sep1 := gtk.NewSeparatorMenuItem()
|
|
about_menu.Append(about_menu_sep1)
|
|
|
|
// Drop databases thing.
|
|
about_menu_drop_database_data_item := gtk.NewMenuItemWithMnemonic("Drop database data...")
|
|
about_menu.Append(about_menu_drop_database_data_item)
|
|
about_menu_drop_database_data_item.Connect("activate", m.dropDatabasesData)
|
|
}
|
|
|
|
// Sidebar (with quick connect and server's information) initialization.
|
|
func (m *MainWindow) initializeSidebar() {
|
|
sidebar_vbox := gtk.NewVBox(false, 0)
|
|
|
|
server_info_frame := gtk.NewFrame("Server information")
|
|
sidebar_vbox.PackStart(server_info_frame, true, true, 5)
|
|
si_vbox := gtk.NewVBox(false, 0)
|
|
server_info_frame.Add(si_vbox)
|
|
|
|
// Scrolled thing.
|
|
si_scroll := gtk.NewScrolledWindow(nil, nil)
|
|
si_scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
si_vbox.PackStart(si_scroll, true, true, 5)
|
|
|
|
// Server's information.
|
|
m.server_info = gtk.NewTreeView()
|
|
m.server_info.SetModel(m.server_info_store)
|
|
|
|
key_column := gtk.NewTreeViewColumnWithAttributes("Key", gtk.NewCellRendererText(), "markup", 0)
|
|
m.server_info.AppendColumn(key_column)
|
|
|
|
value_column := gtk.NewTreeViewColumnWithAttributes("Value", gtk.NewCellRendererText(), "markup", 1)
|
|
m.server_info.AppendColumn(value_column)
|
|
|
|
si_scroll.Add(m.server_info)
|
|
|
|
// Players information.
|
|
players_info_frame := gtk.NewFrame("Players")
|
|
sidebar_vbox.PackStart(players_info_frame, true, true, 5)
|
|
|
|
pi_scroll := gtk.NewScrolledWindow(nil, nil)
|
|
pi_scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
players_info_frame.Add(pi_scroll)
|
|
|
|
m.players_info = gtk.NewTreeView()
|
|
m.players_info.SetModel(m.players_info_store)
|
|
pi_scroll.Add(m.players_info)
|
|
|
|
name_column := gtk.NewTreeViewColumnWithAttributes("Player name", gtk.NewCellRendererText(), "markup", 0)
|
|
m.players_info.AppendColumn(name_column)
|
|
|
|
frags_column := gtk.NewTreeViewColumnWithAttributes("Frags", gtk.NewCellRendererText(), "markup", 1)
|
|
m.players_info.AppendColumn(frags_column)
|
|
|
|
ping_column := gtk.NewTreeViewColumnWithAttributes("Ping", gtk.NewCellRendererText(), "markup", 2)
|
|
m.players_info.AppendColumn(ping_column)
|
|
|
|
// Show CVars button.
|
|
show_cvars_button := gtk.NewButtonWithLabel("Show CVars")
|
|
show_cvars_button.SetTooltipText("Show server's CVars")
|
|
show_cvars_button.Clicked(m.showServerCVars)
|
|
sidebar_vbox.PackStart(show_cvars_button, false, true, 5)
|
|
|
|
// Quick connect frame.
|
|
quick_connect_frame := gtk.NewFrame("Quick connect")
|
|
sidebar_vbox.PackStart(quick_connect_frame, false, true, 5)
|
|
qc_vbox := gtk.NewVBox(false, 0)
|
|
quick_connect_frame.Add(qc_vbox)
|
|
|
|
// Server address.
|
|
srv_tooltip := "Server address we will connect to"
|
|
srv_label := gtk.NewLabel("Server address:")
|
|
srv_label.SetTooltipText(srv_tooltip)
|
|
qc_vbox.PackStart(srv_label, false, true, 5)
|
|
|
|
m.qc_server_address = gtk.NewEntry()
|
|
m.qc_server_address.SetTooltipText(srv_tooltip)
|
|
qc_vbox.PackStart(m.qc_server_address, false, true, 5)
|
|
|
|
// Password.
|
|
pass_tooltip := "Password we will use for server"
|
|
pass_label := gtk.NewLabel("Password:")
|
|
pass_label.SetTooltipText(pass_tooltip)
|
|
qc_vbox.PackStart(pass_label, false, true, 5)
|
|
|
|
m.qc_password = gtk.NewEntry()
|
|
m.qc_password.SetTooltipText(pass_tooltip)
|
|
qc_vbox.PackStart(m.qc_password, false, true, 5)
|
|
|
|
// Nickname
|
|
nick_tooltip := "Nickname we will use"
|
|
nick_label := gtk.NewLabel("Nickname:")
|
|
nick_label.SetTooltipText(nick_tooltip)
|
|
qc_vbox.PackStart(nick_label, false, true, 5)
|
|
|
|
m.qc_nickname = gtk.NewEntry()
|
|
m.qc_nickname.SetTooltipText(nick_tooltip)
|
|
qc_vbox.PackStart(m.qc_nickname, false, true, 5)
|
|
|
|
m.hpane.Add2(sidebar_vbox)
|
|
}
|
|
|
|
// Initializes internal storages.
|
|
func (m *MainWindow) initializeStorages() {
|
|
// Application isn't initialized.
|
|
m.initialized = false
|
|
m.use_other_servers_tab = false
|
|
// Gamemodes.
|
|
m.gamemodes = make(map[string]string)
|
|
m.gamemodes = map[string]string{
|
|
"1": "Last Man Standing",
|
|
"2": "Free For All",
|
|
"3": "Team DM",
|
|
"4": "Team Survivor",
|
|
"5": "Follow The Leader",
|
|
"6": "Cap'n'Hold",
|
|
"7": "Capture The Flag",
|
|
"8": "Bomb",
|
|
"9": "Jump",
|
|
"10": "Freeze Tag",
|
|
"11": "Gun Game",
|
|
"12": "Instagib",
|
|
}
|
|
|
|
// Columns names.
|
|
// Key - default position in lists.
|
|
m.column_names = map[string]string{
|
|
"2": "Name",
|
|
"3": "Mode",
|
|
"4": "Map",
|
|
"5": "Players",
|
|
"6": "Ping",
|
|
"7": "Version",
|
|
"8": "IP",
|
|
}
|
|
// Real columns positions.
|
|
m.column_pos = make(map[string]map[string]int)
|
|
m.column_pos["Servers"] = make(map[string]int)
|
|
m.column_pos["Favorites"] = make(map[string]int)
|
|
|
|
// Frames storage.
|
|
m.tabs = make(map[string]*gtk.Frame)
|
|
m.tabs["dummy"] = gtk.NewFrame("dummy")
|
|
delete(m.tabs, "dummy")
|
|
|
|
// Servers tab list view storage.
|
|
// Structure:
|
|
// Server status icon|Server name|Mode|Map|Players|Ping|Version
|
|
m.all_servers_store = gtk.NewListStore(gdkpixbuf.GetType(), gdkpixbuf.GetType(), glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING)
|
|
m.all_servers_store_sortable = gtk.NewTreeSortable(m.all_servers_store)
|
|
|
|
// Same as above, but for favorite servers.
|
|
m.fav_servers_store = gtk.NewListStore(gdkpixbuf.GetType(), gdkpixbuf.GetType(), glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING)
|
|
|
|
// Server's information store. Used for quick preview in main window.
|
|
m.server_info_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING)
|
|
|
|
// Players information store. Used in sidebar for players list for
|
|
// currently selected server.
|
|
m.players_info_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING)
|
|
|
|
// Profiles count after filling combobox. Defaulting to 0.
|
|
m.old_profiles_count = 0
|
|
|
|
// Window hidden flag.
|
|
m.hidden = false
|
|
|
|
// Pixbufs.
|
|
// Offline server.
|
|
srv_offline_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_OFFLINE)
|
|
srv_offline_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
srv_offline_pixbuf.SetSize(24, 24)
|
|
srv_offline_pixbuf.Write(srv_offline_bytes)
|
|
m.server_offline_pic = srv_offline_pixbuf.GetPixbuf()
|
|
// Online server.
|
|
srv_online_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_ONLINE)
|
|
srv_online_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
srv_online_pixbuf.SetSize(24, 24)
|
|
srv_online_pixbuf.Write(srv_online_bytes)
|
|
m.server_online_pic = srv_online_pixbuf.GetPixbuf()
|
|
// Private server.
|
|
srv_private_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_PRIVATE)
|
|
srv_private_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
srv_private_pixbuf.SetSize(24, 24)
|
|
srv_private_pixbuf.Write(srv_private_bytes)
|
|
m.server_private_pic = srv_private_pixbuf.GetPixbuf()
|
|
// Public server.
|
|
srv_public_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_PUBLIC)
|
|
srv_public_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
srv_public_pixbuf.SetSize(24, 24)
|
|
srv_public_pixbuf.Write(srv_public_bytes)
|
|
m.server_public_pic = srv_public_pixbuf.GetPixbuf()
|
|
fmt.Println(srv_public_pixbuf.GetFormat().GetName())
|
|
}
|
|
|
|
// Tabs widget initialization, including all child widgets.
|
|
func (m *MainWindow) InitializeTabs() {
|
|
// Create tabs widget.
|
|
m.tab_widget = gtk.NewNotebook()
|
|
m.tab_widget.Connect("switch-page", m.tabChanged)
|
|
|
|
tab_allsrv_hbox := gtk.NewHBox(false, 0)
|
|
swin1 := gtk.NewScrolledWindow(nil, nil)
|
|
|
|
m.all_servers = gtk.NewTreeView()
|
|
swin1.Add(m.all_servers)
|
|
tab_allsrv_hbox.PackStart(swin1, true, true, 5)
|
|
m.tab_widget.AppendPage(tab_allsrv_hbox, gtk.NewLabel("Servers"))
|
|
|
|
m.all_servers.SetModel(m.all_servers_store)
|
|
// These columns are static.
|
|
m.all_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Status", gtk.NewCellRendererPixbuf(), "pixbuf", 0))
|
|
m.all_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Public", gtk.NewCellRendererPixbuf(), "pixbuf", 1))
|
|
|
|
// ...aand lets do dynamic generation :)
|
|
// +2 because we have 2 static columns.
|
|
all_servers_columns_to_append := make([]*gtk.TreeViewColumn, len(m.column_names) + 2)
|
|
for pos, name := range m.column_names {
|
|
// Check if we have column position saved. If so - use it.
|
|
// Otherwise use default position.
|
|
// Should be actual only for first launch.
|
|
position := ctx.Cfg.Cfg["/mainwindow/all_servers/" + name + "_position"]
|
|
if len(position) == 0 {
|
|
position = pos
|
|
}
|
|
position_int, _ := strconv.Atoi(position)
|
|
// Same for width.
|
|
width := ctx.Cfg.Cfg["/mainwindow/all_servers/" + name + "_width"]
|
|
if len(width) == 0 {
|
|
width = "-1"
|
|
}
|
|
width_int, _ := strconv.Atoi(width)
|
|
|
|
col := gtk.NewTreeViewColumnWithAttributes(name, gtk.NewCellRendererText(), "markup", position_int)
|
|
col.SetSortColumnId(position_int)
|
|
col.SetReorderable(true)
|
|
col.SetResizable(true)
|
|
// GtkTreeViewColumn.SetFixedWidth() accepts only positive integers.
|
|
if width_int > 1 {
|
|
col.SetSizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
|
col.SetFixedWidth(width_int)
|
|
}
|
|
m.column_pos["Servers"][name] = position_int
|
|
all_servers_columns_to_append[position_int] = col
|
|
}
|
|
|
|
for i := range all_servers_columns_to_append {
|
|
if i < 2 {
|
|
continue
|
|
}
|
|
m.all_servers.AppendColumn(all_servers_columns_to_append[i])
|
|
}
|
|
|
|
// Sorting.
|
|
// By default we are sorting by server name.
|
|
m.all_servers_store_sortable.SetSortColumnId(m.column_pos["Servers"]["Name"], gtk.SORT_ASCENDING)
|
|
|
|
// Sorting functions.
|
|
// Race conditions and GC crazyness appears when activated, so for
|
|
// now commenting it out.
|
|
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Name"], m.sortServersByName)
|
|
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Players"], m.sortServersByPlayers)
|
|
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Ping"], m.sortServersByPing)
|
|
|
|
// Selection changed signal, which will update server's short info pane.
|
|
m.all_servers.Connect("cursor-changed", m.showShortServerInformation)
|
|
|
|
// VBox for some servers list controllers.
|
|
tab_all_srv_ctl_vbox := gtk.NewVBox(false, 0)
|
|
tab_allsrv_hbox.PackStart(tab_all_srv_ctl_vbox, false, true, 5)
|
|
|
|
// Checkbox for hiding offline servers.
|
|
m.all_servers_hide_offline = gtk.NewCheckButtonWithLabel("Hide offline servers")
|
|
m.all_servers_hide_offline.SetTooltipText("Hide offline servers on Servers tab")
|
|
tab_all_srv_ctl_vbox.PackStart(m.all_servers_hide_offline, false, true, 5)
|
|
m.all_servers_hide_offline.Clicked(m.hideOfflineAllServers)
|
|
// Restore value of hide offline servers checkbox.
|
|
// Set to checked for new installations.
|
|
all_servers_hide_offline_cb_val, ok := ctx.Cfg.Cfg["/serverslist/all_servers/hide_offline"]
|
|
if !ok {
|
|
m.all_servers_hide_offline.SetActive(true)
|
|
} else {
|
|
if all_servers_hide_offline_cb_val == "1" {
|
|
m.all_servers_hide_offline.SetActive(true)
|
|
}
|
|
}
|
|
|
|
// Checkbox for hiding passworded servers.
|
|
m.all_servers_hide_private = gtk.NewCheckButtonWithLabel("Hide private servers")
|
|
m.all_servers_hide_private.SetTooltipText("Hide servers which requires password to enter")
|
|
tab_all_srv_ctl_vbox.PackStart(m.all_servers_hide_private, false, true, 5)
|
|
m.all_servers_hide_private.Clicked(m.hidePrivateAllServers)
|
|
// Restore checkbox value.
|
|
all_servers_hide_private_cb_val, ok := ctx.Cfg.Cfg["/serverslist/all_servers/hide_private"]
|
|
if !ok {
|
|
m.all_servers_hide_private.SetActive(true)
|
|
} else {
|
|
if all_servers_hide_private_cb_val == "1" {
|
|
m.all_servers_hide_private.SetActive(true)
|
|
}
|
|
}
|
|
|
|
// Final separator.
|
|
ctl_sep := gtk.NewVSeparator()
|
|
tab_all_srv_ctl_vbox.PackStart(ctl_sep, true, true, 5)
|
|
|
|
// Favorites servers
|
|
// ToDo: sorting as in all servers list.
|
|
tab_fav_srv_hbox := gtk.NewHBox(false, 0)
|
|
m.fav_servers = gtk.NewTreeView()
|
|
swin2 := gtk.NewScrolledWindow(nil, nil)
|
|
swin2.Add(m.fav_servers)
|
|
tab_fav_srv_hbox.PackStart(swin2, true, true, 5)
|
|
m.tab_widget.AppendPage(tab_fav_srv_hbox, gtk.NewLabel("Favorites"))
|
|
m.fav_servers.SetModel(m.fav_servers_store)
|
|
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Status", gtk.NewCellRendererPixbuf(), "pixbuf", 0))
|
|
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Public", gtk.NewCellRendererPixbuf(), "pixbuf", 1))
|
|
|
|
// +2 because we have 2 static columns.
|
|
fav_servers_columns_to_append := make([]*gtk.TreeViewColumn, len(m.column_names) + 2)
|
|
for pos, name := range m.column_names {
|
|
// Check if we have column position saved. If so - use it.
|
|
// Otherwise use default position.
|
|
// Should be actual only for first launch.
|
|
position := ctx.Cfg.Cfg["/mainwindow/fav_servers/" + name + "_position"]
|
|
if len(position) == 0 {
|
|
position = pos
|
|
}
|
|
position_int, _ := strconv.Atoi(position)
|
|
// Same for width.
|
|
width := ctx.Cfg.Cfg["/mainwindow/fav_servers/" + name + "_width"]
|
|
if len(width) == 0 {
|
|
width = "-1"
|
|
}
|
|
width_int, _ := strconv.Atoi(width)
|
|
|
|
col := gtk.NewTreeViewColumnWithAttributes(name, gtk.NewCellRendererText(), "markup", position_int)
|
|
// For some reason this cause panic on Windows, so disabling
|
|
// default sorting here.
|
|
if runtime.GOOS != "windows" {
|
|
col.SetSortColumnId(position_int)
|
|
}
|
|
col.SetReorderable(true)
|
|
col.SetResizable(true)
|
|
// GtkTreeViewColumn.SetFixedWidth() accepts only positive integers.
|
|
if width_int > 1 {
|
|
col.SetSizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
|
col.SetFixedWidth(width_int)
|
|
}
|
|
m.column_pos["Favorites"][name] = position_int
|
|
fav_servers_columns_to_append[position_int] = col
|
|
}
|
|
|
|
for i := range fav_servers_columns_to_append {
|
|
if i < 2 {
|
|
continue
|
|
}
|
|
m.fav_servers.AppendColumn(fav_servers_columns_to_append[i])
|
|
}
|
|
|
|
// Selection changed signal, which will update server's short info pane.
|
|
m.fav_servers.Connect("cursor-changed", m.showShortServerInformation)
|
|
|
|
// VBox for some servers list controllers.
|
|
tab_fav_srv_ctl_vbox := gtk.NewVBox(false, 0)
|
|
tab_fav_srv_hbox.PackStart(tab_fav_srv_ctl_vbox, false, true, 5)
|
|
|
|
// Checkbox for hiding offline servers.
|
|
m.fav_servers_hide_offline = gtk.NewCheckButtonWithLabel("Hide offline servers")
|
|
m.fav_servers_hide_offline.SetTooltipText("Hide offline servers on Favorites tab")
|
|
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_hide_offline, false, true, 5)
|
|
m.fav_servers_hide_offline.Clicked(m.hideOfflineFavoriteServers)
|
|
// Restore value of hide offline servers checkbox.
|
|
// Set to checked for new installations.
|
|
favorite_servers_hide_offline_cb_val, ok := ctx.Cfg.Cfg["/serverslist/favorite/hide_offline"]
|
|
if !ok {
|
|
m.fav_servers_hide_offline.SetActive(true)
|
|
} else {
|
|
if favorite_servers_hide_offline_cb_val == "1" {
|
|
m.fav_servers_hide_offline.SetActive(true)
|
|
}
|
|
}
|
|
|
|
// Checkbox for hiding passworded servers.
|
|
m.fav_servers_hide_private = gtk.NewCheckButtonWithLabel("Hide private servers")
|
|
m.fav_servers_hide_private.SetTooltipText("Hide servers which requires password to enter")
|
|
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_hide_private, false, true, 5)
|
|
m.fav_servers_hide_private.Clicked(m.hidePrivateFavoriteServers)
|
|
// Restore checkbox value.
|
|
fav_servers_hide_private_cb_val, ok := ctx.Cfg.Cfg["/serverslist/favorite/hide_private"]
|
|
if !ok {
|
|
m.fav_servers_hide_private.SetActive(true)
|
|
} else {
|
|
if fav_servers_hide_private_cb_val == "1" {
|
|
m.fav_servers_hide_private.SetActive(true)
|
|
}
|
|
}
|
|
|
|
// Final separator.
|
|
ctl_fav_sep := gtk.NewVSeparator()
|
|
tab_fav_srv_ctl_vbox.PackStart(ctl_fav_sep, true, true, 5)
|
|
|
|
// Add tab_widget widget to window.
|
|
m.hpane.Add1(m.tab_widget)
|
|
}
|
|
|
|
// Toolbar initialization.
|
|
func (m *MainWindow) InitializeToolbar() {
|
|
m.toolbar = gtk.NewToolbar()
|
|
m.vbox.PackStart(m.toolbar, false, false, 5)
|
|
|
|
// Update servers button.
|
|
button_update_all_servers_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ALL_SERVERS)
|
|
button_update_all_servers_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
button_update_all_servers_icon_pixbuf.SetSize(24, 24)
|
|
button_update_all_servers_icon_pixbuf.Write(button_update_all_servers_icon_bytes)
|
|
button_update_all_servers_icon := gtk.NewImageFromPixbuf(button_update_all_servers_icon_pixbuf.GetPixbuf())
|
|
button_update_all_servers := gtk.NewToolButton(button_update_all_servers_icon, "Update all servers")
|
|
button_update_all_servers.SetTooltipText("Update all servers in currently selected tab")
|
|
button_update_all_servers.OnClicked(m.UpdateServers)
|
|
m.toolbar.Insert(button_update_all_servers, 0)
|
|
|
|
button_update_one_server_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ONE_SERVER)
|
|
button_update_one_server_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
button_update_one_server_icon_pixbuf.SetSize(24, 24)
|
|
button_update_one_server_icon_pixbuf.Write(button_update_one_server_icon_bytes)
|
|
button_update_one_server_icon := gtk.NewImageFromPixbuf(button_update_one_server_icon_pixbuf.GetPixbuf())
|
|
button_update_one_server := gtk.NewToolButton(button_update_one_server_icon, "Update selected server")
|
|
button_update_one_server.SetTooltipText("Update only selected server")
|
|
button_update_one_server.OnClicked(m.updateOneServer)
|
|
m.toolbar.Insert(button_update_one_server, 1)
|
|
|
|
// Separator.
|
|
separator := gtk.NewSeparatorToolItem()
|
|
m.toolbar.Insert(separator, 2)
|
|
|
|
// Add server to favorites button.
|
|
fav_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.ADD_TO_FAVORITES)
|
|
fav_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
fav_button_icon_pixbuf.SetSize(24, 24)
|
|
fav_button_icon_pixbuf.Write(fav_button_icon_bytes)
|
|
fav_button_icon := gtk.NewImageFromPixbuf(fav_button_icon_pixbuf.GetPixbuf())
|
|
fav_button := gtk.NewToolButton(fav_button_icon, "Add to favorites")
|
|
fav_button.SetTooltipText("Add selected server to favorites")
|
|
fav_button.OnClicked(m.addToFavorites)
|
|
m.toolbar.Insert(fav_button, 3)
|
|
|
|
fav_edit_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.EDIT_FAVORITE)
|
|
fav_edit_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
fav_edit_button_icon_pixbuf.SetSize(24, 24)
|
|
fav_edit_button_icon_pixbuf.Write(fav_edit_button_icon_bytes)
|
|
fav_edit_button_icon := gtk.NewImageFromPixbuf(fav_edit_button_icon_pixbuf.GetPixbuf())
|
|
fav_edit_button := gtk.NewToolButton(fav_edit_button_icon, "Edit favorite")
|
|
fav_edit_button.SetTooltipText("Edit selected favorite server")
|
|
fav_edit_button.OnClicked(m.editFavorite)
|
|
m.toolbar.Insert(fav_edit_button, 4)
|
|
|
|
// Remove server from favorites button.
|
|
fav_delete_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REMOVE_FAVORITE)
|
|
fav_delete_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
fav_delete_button_icon_pixbuf.SetSize(24, 24)
|
|
fav_delete_button_icon_pixbuf.Write(fav_delete_button_icon_bytes)
|
|
fav_delete_button_icon := gtk.NewImageFromPixbuf(fav_delete_button_icon_pixbuf.GetPixbuf())
|
|
fav_delete_button := gtk.NewToolButton(fav_delete_button_icon, "Remove from favorites")
|
|
fav_delete_button.SetTooltipText("Remove selected server from favorites")
|
|
fav_delete_button.OnClicked(m.deleteFromFavorites)
|
|
m.toolbar.Insert(fav_delete_button, 5)
|
|
|
|
// Copy server address button.
|
|
copy_srv_addr_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.COPY_CREDENTIALS)
|
|
copy_srv_addr_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
|
copy_srv_addr_button_icon_pixbuf.SetSize(24, 24)
|
|
copy_srv_addr_button_icon_pixbuf.Write(copy_srv_addr_button_icon_bytes)
|
|
copy_srv_addr_button_icon := gtk.NewImageFromPixbuf(copy_srv_addr_button_icon_pixbuf.GetPixbuf())
|
|
copy_srv_addr_button := gtk.NewToolButton(copy_srv_addr_button_icon, "Copy server's creds")
|
|
copy_srv_addr_button.SetTooltipText("Copy server's credentials to clipboard for sharing")
|
|
copy_srv_addr_button.OnClicked(m.copyServerCredentialsToClipboard)
|
|
m.toolbar.Insert(copy_srv_addr_button, 6)
|
|
|
|
// Separator for toolbar's label and buttons.
|
|
toolbar_separator_toolitem := gtk.NewToolItem()
|
|
toolbar_separator_toolitem.SetExpand(true)
|
|
m.toolbar.Insert(toolbar_separator_toolitem, 7)
|
|
// Toolbar's label.
|
|
m.toolbar_label = gtk.NewLabel("URTrator is ready")
|
|
toolbar_label_toolitem := gtk.NewToolItem()
|
|
toolbar_label_toolitem.Add(m.toolbar_label)
|
|
m.toolbar.Insert(toolbar_label_toolitem, 8)
|
|
}
|
|
|
|
// Tray icon initialization.
|
|
func (m *MainWindow) initializeTrayIcon() {
|
|
fmt.Println("Initializing tray icon...")
|
|
|
|
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
|
|
icon_pixbuf := gdkpixbuf.NewLoader()
|
|
icon_pixbuf.Write(icon_bytes)
|
|
logo = icon_pixbuf.GetPixbuf()
|
|
|
|
m.tray_icon = gtk.NewStatusIconFromPixbuf(logo)
|
|
m.tray_icon.SetName("URTrator")
|
|
m.tray_icon.SetTitle("URTrator")
|
|
m.tray_icon.SetTooltipText("URTrator is ready")
|
|
|
|
// Tray menu is still buggy on windows, so skipping initialization,
|
|
// if OS is Windows.
|
|
if runtime.GOOS != "windows" {
|
|
m.tray_menu = gtk.NewMenu()
|
|
|
|
// Open/Close URTrator menu item.
|
|
open_close_item := gtk.NewMenuItemWithLabel("Show / Hide URTrator")
|
|
open_close_item.Connect("activate", m.showHide)
|
|
m.tray_menu.Append(open_close_item)
|
|
|
|
// Separator
|
|
sep1 := gtk.NewSeparatorMenuItem()
|
|
m.tray_menu.Append(sep1)
|
|
|
|
// Exit menu item.
|
|
exit_item := gtk.NewMenuItemWithLabel("Exit")
|
|
exit_item.Connect("activate", m.window.Destroy)
|
|
m.tray_menu.Append(exit_item)
|
|
|
|
// Connect things.
|
|
m.tray_icon.Connect("activate", m.showHide)
|
|
m.tray_icon.Connect("popup-menu", m.showTrayMenu)
|
|
m.tray_menu.ShowAll()
|
|
}
|
|
}
|