// URTrator - Urban Terror server browser and game launcher, written in // Go. // // Copyright (c) 2016-2020, Stanslav N. a.k.a pztrn (or p0z1tr0n) and // URTrator contributors. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject // to the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package ui import ( // stdlib "fmt" "runtime" "sort" "strconv" "strings" // Local "go.dev.pztrn.name/urtrator/datamodels" "go.dev.pztrn.name/urtrator/ioq3dataparser" // Other "github.com/mattn/go-gtk/gdkpixbuf" "github.com/mattn/go-gtk/glib" "github.com/mattn/go-gtk/gtk" ) type MainWindow struct { // Gamemodes. gamemodes map[string]string text string // Widgets. // The window itself. window *gtk.Window // Vertical Box. vbox *gtk.VBox // Main menu. menubar *gtk.MenuBar // Toolbar toolbar *gtk.Toolbar // Horizontal box for main window. hpane *gtk.HPaned // Tab widget. tab_widget *gtk.Notebook // Tabs list. tabs map[string]*gtk.Frame // All servers widget. all_servers *gtk.TreeView // Favorite servers widget. fav_servers *gtk.TreeView // Statusbar. statusbar *gtk.Statusbar // Statusbar context ID. statusbar_context_id uint // Profiles combobox. profiles *gtk.ComboBoxText // Checkbox for hiding/showing offline servers in 'Servers' tab list. all_servers_hide_offline *gtk.CheckButton // Checkbox for hiding/showing passworded servers in 'Servers' tab list. all_servers_hide_private *gtk.CheckButton // Combobox for filtering server's versions. all_servers_version *gtk.ComboBoxText // Combobox for filtering by gamemode. all_servers_gamemode *gtk.ComboBoxText // Checkbox for hiding/showing offline servers in 'Favorites' tab list. fav_servers_hide_offline *gtk.CheckButton // Checkbox for hiding/showing passworded servers in 'Favorites' tab list. fav_servers_hide_private *gtk.CheckButton // Combobox for filtering server's versions. fav_servers_version *gtk.ComboBoxText // Combobox for filtering by gamemode. fav_servers_gamemode *gtk.ComboBoxText // Game launch button. launch_button *gtk.Button // Server's main information. server_info *gtk.TreeView // Players information. players_info *gtk.TreeView // Quick connect: server address qc_server_address *gtk.Entry // Quick connect: password qc_password *gtk.Entry // Quick connect: nickname qc_nickname *gtk.Entry // Tray icon. tray_icon *gtk.StatusIcon // Tray menu. tray_menu *gtk.Menu // Toolbar's label. toolbar_label *gtk.Label // Storages. // All servers store. all_servers_store *gtk.ListStore // All servers sortable store. all_servers_store_sortable *gtk.TreeSortable // Favorites fav_servers_store *gtk.ListStore // Server's information store. server_info_store *gtk.ListStore // Players information store. players_info_store *gtk.ListStore // Dialogs. options_dialog *OptionsDialog server_cvars_dialog *ServerCVarsDialog // Other // Old profiles count. old_profiles_count int // Window size. window_width int window_height int // Window position. window_pos_x int window_pos_y int // Main pane delimiter position. It is calculated like: // // window_width - pane_position // // so we will get same right pane width even if we will resize // main window. On resize and restore it will be set like: // // window_width - m.pane_negative_position pane_negative_position int // Columns names for servers tabs. column_names map[string]string // Real columns positions on servers tabs. column_pos map[string]map[string]int // Resources. // Pixbufs. // For unavailable (e.g. offline) server. server_offline_pic *gdkpixbuf.Pixbuf // For online server. server_online_pic *gdkpixbuf.Pixbuf // For private (passworded) server. server_private_pic *gdkpixbuf.Pixbuf // For public server server_public_pic *gdkpixbuf.Pixbuf // Flags. // Application is initialized? initialized bool // Window is hidden? hidden bool // Use other's tab information? // Used when user changed active tab, to show information about // server which is selected on activated tab. use_other_servers_tab bool // Does servers updating already in progress? // This helps to prevent random crashes when more than one // updating process in progress. servers_already_updating bool } func (m *MainWindow) addToFavorites() { fmt.Println("Adding server to favorites...") current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) server_address := "" if !strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { server_address = m.getIpFromServersList(current_tab) } // Getting server from database. fd := &FavoriteDialog{} if len(server_address) > 0 { servers := []datamodels.Server{} address := strings.Split(server_address, ":")[0] port := strings.Split(server_address, ":")[1] err1 := ctx.Database.Db.Select(&servers, ctx.Database.Db.Rebind("SELECT * FROM servers WHERE ip=? AND port=?"), address, port) if err1 != nil { fmt.Println(err1.Error()) } fd.InitializeUpdate(&servers[0]) } else { fd.InitializeNew() } } func (m *MainWindow) allServersGamemodeFilterChanged() { ctx.Cfg.Cfg["/serverslist/all_servers/gamemode"] = strconv.Itoa(m.all_servers_gamemode.GetActive()) ctx.Eventer.LaunchEvent("loadAllServers", nil) } func (m *MainWindow) allServersVersionFilterChanged() { ctx.Cfg.Cfg["/serverslist/all_servers/version"] = strconv.Itoa(m.all_servers_version.GetActive()) ctx.Eventer.LaunchEvent("loadAllServers", nil) } // Executes when delimiter for two panes is moved, to calculate VALID // position. func (m *MainWindow) checkMainPanePosition() { glib.IdleAdd(func() bool { m.pane_negative_position = m.window_width - m.hpane.GetPosition() return false }) } // Executes when main window is moved or resized. // Also calculating pane delimiter position and set it to avoid // widgets hell :). func (m *MainWindow) checkPositionAndSize() { glib.IdleAdd(func() bool { m.window_pos_x, m.window_pos_y = m.window.GetPosition() m.window_width, m.window_height = m.window.GetSize() m.hpane.SetPosition(m.window_width - m.pane_negative_position) return false }) } // Executes on URTrator shutdown. func (m *MainWindow) Close() { // Save window parameters. ctx.Cfg.Cfg["/mainwindow/width"] = strconv.Itoa(m.window_width) ctx.Cfg.Cfg["/mainwindow/height"] = strconv.Itoa(m.window_height) ctx.Cfg.Cfg["/mainwindow/position_x"] = strconv.Itoa(m.window_pos_x) ctx.Cfg.Cfg["/mainwindow/position_y"] = strconv.Itoa(m.window_pos_y) ctx.Cfg.Cfg["/mainwindow/pane_negative_position"] = strconv.Itoa(m.pane_negative_position) // Saving columns sizes and positions. all_servers_columns := m.all_servers.GetColumns() for i := range all_servers_columns { ctx.Cfg.Cfg["/mainwindow/all_servers/"+all_servers_columns[i].GetTitle()+"_position"] = strconv.Itoa(i) ctx.Cfg.Cfg["/mainwindow/all_servers/"+all_servers_columns[i].GetTitle()+"_width"] = strconv.Itoa(all_servers_columns[i].GetWidth()) } fav_servers_columns := m.fav_servers.GetColumns() for i := range fav_servers_columns { ctx.Cfg.Cfg["/mainwindow/fav_servers/"+fav_servers_columns[i].GetTitle()+"_position"] = strconv.Itoa(i) ctx.Cfg.Cfg["/mainwindow/fav_servers/"+fav_servers_columns[i].GetTitle()+"_width"] = strconv.Itoa(fav_servers_columns[i].GetWidth()) } // Additional actions should be taken on Windows. if runtime.GOOS == "windows" { m.closeWin() } ctx.Close() } func (m *MainWindow) copyServerCredentialsToClipboard() { fmt.Println("Copying server's credentials to clipboard...") current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) server_address := m.getIpFromServersList(current_tab) ctx.Clipboard.CopyServerData(server_address) } // Deleting server from favorites. func (m *MainWindow) deleteFromFavorites() { fmt.Println("Removing server from favorites...") current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) server_address := m.getIpFromServersList(current_tab) var not_favorited bool = false if len(server_address) > 0 { if ctx.Cache.Servers[server_address].Server.Favorite == "1" { ctx.Cache.Servers[server_address].Server.Favorite = "0" } else { not_favorited = true } } else { not_favorited = true } if not_favorited { // Temporary disable all these modals on Linux. // See https://github.com/mattn/go-gtk/issues/289. if runtime.GOOS != "linux" { mbox_string := ctx.Translator.Translate("Cannot delete server from favorites.\n\nServer isn't favorited.", nil) d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string) d.Response(func() { d.Destroy() }) d.Run() } else { ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "" + ctx.Translator.Translate("Server isn't favorited", nil) + ""}) } } ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) } // Drop database data. // ToDo: extend so we should have an ability to decide what to drop. func (m *MainWindow) dropDatabasesData() { fmt.Println("Dropping database data...") var will_continue bool = false // Temporary disable all these modals on Linux. // See https://github.com/mattn/go-gtk/issues/289. if runtime.GOOS != "linux" { mbox_string := ctx.Translator.Translate("You are about to drop whole database data.\n\nAfter clicking \"YES\" ALL data in database (servers, profiles, settings, etc.)\nwill be lost FOREVER. Are you sure?", nil) d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string) d.Connect("response", func(resp *glib.CallbackContext) { if resp.Args(0) == 4294967287 { will_continue = false } else { will_continue = true } d.Destroy() }) d.Run() } else { ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "" + ctx.Translator.Translate("Remove ~/.config/urtrator/database.sqlite3 manually!", nil) + ""}) } if will_continue { ctx.Database.Db.MustExec("DELETE FROM servers") ctx.Database.Db.MustExec("DELETE FROM settings") ctx.Database.Db.MustExec("DELETE FROM urt_profiles") ctx.Eventer.LaunchEvent("loadProfiles", map[string]string{}) ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{}) ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) } } // Executes on "Edit favorite server" click. func (m *MainWindow) editFavorite() { fmt.Println("Editing favorite server...") server_address := m.getIpFromServersList("Favorites") if len(server_address) > 0 { srv := ctx.Cache.Servers[server_address].Server fd := FavoriteDialog{} fd.InitializeUpdate(srv) } } func (m *MainWindow) favServersGamemodeFilterChanged() { ctx.Cfg.Cfg["/serverslist/favorite/gamemode"] = strconv.Itoa(m.fav_servers_gamemode.GetActive()) ctx.Eventer.LaunchEvent("loadFavoriteServers", nil) } func (m *MainWindow) favServersVersionFilterChanged() { ctx.Cfg.Cfg["/serverslist/favorite/version"] = strconv.Itoa(m.fav_servers_version.GetActive()) ctx.Eventer.LaunchEvent("loadFavoriteServers", nil) } // Executes when "Hide offline servers" checkbox changed it's state on // "Servers" tab. func (m *MainWindow) hideOfflineAllServers() { fmt.Println("(Un)Hiding offline servers in 'Servers' tab...") if m.all_servers_hide_offline.GetActive() { ctx.Cfg.Cfg["/serverslist/all_servers/hide_offline"] = "1" } else { ctx.Cfg.Cfg["/serverslist/all_servers/hide_offline"] = "0" } ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{}) } // Executes when "Hide passworded servers" checkbox changed it's state on // "Servers" tab. func (m *MainWindow) hidePrivateAllServers() { fmt.Println("(Un)Hiding private servers in 'Servers' tab...") if m.all_servers_hide_private.GetActive() { ctx.Cfg.Cfg["/serverslist/all_servers/hide_private"] = "1" } else { ctx.Cfg.Cfg["/serverslist/all_servers/hide_private"] = "0" } ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{}) } // Executes when "Hide offline servers" checkbox changed it's state on // "Favorites" tab. func (m *MainWindow) hideOfflineFavoriteServers() { fmt.Println("(Un)Hiding offline servers in 'Favorite' tab...") if m.fav_servers_hide_offline.GetActive() { ctx.Cfg.Cfg["/serverslist/favorite/hide_offline"] = "1" } else { ctx.Cfg.Cfg["/serverslist/favorite/hide_offline"] = "0" } ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) } // Executes when "Hide passworded servers" checkbox changed it's state on // "Favorites" tab. func (m *MainWindow) hidePrivateFavoriteServers() { fmt.Println("(Un)Hiding private servers in 'Favorite' tab...") if m.all_servers_hide_private.GetActive() { ctx.Cfg.Cfg["/serverslist/favorite/hide_private"] = "1" } else { ctx.Cfg.Cfg["/serverslist/favorite/hide_private"] = "0" } ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) } func (m *MainWindow) loadAllServers(data map[string]string) { fmt.Println("Loading all servers...") for _, server := range ctx.Cache.Servers { iter := new(gtk.TreeIter) ping, _ := strconv.Atoi(server.Server.Ping) if !server.AllServersIterSet { server.AllServersIter = iter server.AllServersIterSet = true } else { iter = server.AllServersIter } // Hide offline servers? if m.all_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) { if server.AllServersIterInList && server.AllServersIterSet { m.all_servers_store.Remove(iter) server.AllServersIterInList = false } continue } // Hide private servers? if m.all_servers_hide_private.GetActive() && server.Server.IsPrivate == "1" { if server.AllServersIterInList && server.AllServersIterSet { m.all_servers_store.Remove(iter) server.AllServersIterInList = false } continue } // Hide servers that using different version than selected in // filter? if m.all_servers_version.GetActiveText() != ctx.Translator.Translate("All versions", nil) && m.all_servers_version.GetActiveText() != server.Server.Version { if server.AllServersIterInList && server.AllServersIterSet { m.all_servers_store.Remove(iter) server.AllServersIterInList = false } continue } // Hide servers that using different gamemode than selected in // filter? gm_int_as_str := strconv.Itoa(m.all_servers_gamemode.GetActive()) if m.all_servers_gamemode.GetActiveText() != ctx.Translator.Translate("All gamemodes", nil) && gm_int_as_str != server.Server.Gamemode { if server.AllServersIterInList && server.AllServersIterSet { m.all_servers_store.Remove(iter) server.AllServersIterInList = false } continue } if !server.AllServersIterInList && server.AllServersIterSet { m.all_servers_store.Append(iter) server.AllServersIterInList = true } if server.Server.Name == "" && server.Server.Players == "" { m.all_servers_store.SetValue(iter, 0, m.server_offline_pic.GPixbuf) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("IP", nil)], server.Server.Ip+":"+server.Server.Port) } else { if ping > 9000 { m.all_servers_store.SetValue(iter, 0, m.server_offline_pic.GPixbuf) } else { m.all_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf) } if server.Server.IsPrivate == "1" { m.all_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf) } else { m.all_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf) } server_name := ctx.Colorizer.Fix(server.Server.Name) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Name", nil)], server_name) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Mode", nil)], m.getGameModeName(server.Server.Gamemode)) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Map", nil)], server.Server.Map) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Players", nil)], server.Server.Players+"/"+server.Server.Bots+"/"+server.Server.Maxplayers) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Ping", nil)], server.Server.Ping) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("Version", nil)], server.Server.Version) m.all_servers_store.SetValue(iter, m.column_pos["Servers"][ctx.Translator.Translate("IP", nil)], server.Server.Ip+":"+server.Server.Port) } } } func (m *MainWindow) loadFavoriteServers(data map[string]string) { fmt.Println("Loading favorite servers...") for _, server := range ctx.Cache.Servers { iter := new(gtk.TreeIter) ping, _ := strconv.Atoi(server.Server.Ping) if !server.FavServersIterSet { server.FavServersIter = iter server.FavServersIterSet = true } else { iter = server.FavServersIter } // Hide offline servers? if m.fav_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) { if server.FavServersIterInList { m.fav_servers_store.Remove(iter) server.FavServersIterInList = false } continue } // Hide private servers? if m.fav_servers_hide_private.GetActive() && server.Server.IsPrivate == "1" { if server.FavServersIterInList && server.FavServersIterSet { m.fav_servers_store.Remove(iter) server.FavServersIterInList = false } continue } // Hide servers that using different version than selected in // filter? if m.fav_servers_version.GetActiveText() != ctx.Translator.Translate("All versions", nil) && m.fav_servers_version.GetActiveText() != server.Server.Version { if server.FavServersIterInList && server.FavServersIterSet { m.fav_servers_store.Remove(iter) server.FavServersIterInList = false } continue } // Hide servers that using different gamemode than selected in // filter? gm_int_as_str := strconv.Itoa(m.fav_servers_gamemode.GetActive()) if m.fav_servers_gamemode.GetActiveText() != ctx.Translator.Translate("All gamemodes", nil) && gm_int_as_str != server.Server.Gamemode { if server.FavServersIterInList && server.FavServersIterSet { m.fav_servers_store.Remove(iter) server.FavServersIterInList = false } continue } // If server on favorites widget, but not favorited (e.g. just // removed from favorites) - remove it from list. if server.Server.Favorite != "1" && server.FavServersIterSet && server.FavServersIterInList { m.fav_servers_store.Remove(server.FavServersIter) server.FavServersIterInList = false server.FavServersIterSet = false } // Server isn't in favorites and wasn't previously added to widget. if server.Server.Favorite != "1" { continue } if !server.FavServersIterInList && server.FavServersIterSet { m.fav_servers_store.Append(iter) server.FavServersIterInList = true } if server.Server.Name == "" && server.Server.Players == "" { m.fav_servers_store.SetValue(iter, 0, m.server_offline_pic.GPixbuf) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("IP", nil)], server.Server.Ip+":"+server.Server.Port) } else { if ping > 9000 { m.fav_servers_store.SetValue(iter, 0, m.server_offline_pic.GPixbuf) } else { m.fav_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf) } if server.Server.IsPrivate == "1" { m.fav_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf) } else { m.fav_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf) } server_name := ctx.Colorizer.Fix(server.Server.Name) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Name", nil)], server_name) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Mode", nil)], m.getGameModeName(server.Server.Gamemode)) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Map", nil)], server.Server.Map) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Players", nil)], server.Server.Players+"/"+server.Server.Bots+"/"+server.Server.Maxplayers) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Ping", nil)], server.Server.Ping) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("Version", nil)], server.Server.Version) m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"][ctx.Translator.Translate("IP", nil)], server.Server.Ip+":"+server.Server.Port) } } } func (m *MainWindow) loadProfiles(data map[string]string) { fmt.Println("Loading profiles into combobox on MainWindow") for i := 0; i < m.old_profiles_count; i++ { // ComboBox indexes are shifting on element deletion, so we should // detele very first element every time. m.profiles.Remove(0) } for _, profile := range ctx.Cache.Profiles { m.profiles.AppendText(profile.Profile.Name) } m.old_profiles_count = len(ctx.Cache.Profiles) fmt.Println("Added " + strconv.Itoa(m.old_profiles_count) + " profiles") m.profiles.SetActive(0) } func (m *MainWindow) tabChanged() { if !m.initialized { return } fmt.Println("Active tab changed...") current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) fmt.Println(current_tab) m.use_other_servers_tab = true if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { m.fav_servers.Emit("cursor-changed") } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { m.all_servers.Emit("cursor-changed") } m.use_other_servers_tab = false } func (m *MainWindow) serversUpdateCompleted(data map[string]string) { ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": ctx.Translator.Translate("Servers updated.", nil)}) // Trigger "selection-changed" events on currently active tab's // servers list. current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { m.all_servers.Emit("cursor-changed") } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { m.fav_servers.Emit("cursor-changed") } m.servers_already_updating = false } func (m *MainWindow) setQuickConnectDetails(data map[string]string) { fmt.Println("Setting quick connect data...") m.qc_server_address.SetText(data["server"]) m.qc_password.SetText(data["password"]) } func (m *MainWindow) setToolbarLabelText(data map[string]string) { fmt.Println("Setting toolbar's label text...") if strings.Contains(data["text"], "") { fmt.Println("With markup") m.toolbar_label.SetMarkup(data["text"]) } else { fmt.Println("Without markup") m.toolbar_label.SetLabel(data["text"]) } } func (m *MainWindow) showHide() { if m.hidden { m.window.Show() m.hidden = false // Set window position on restore. Window loosing it on // multimonitor configurations. m.window.Move(m.window_pos_x, m.window_pos_y) } else { m.window.Hide() m.hidden = true } } func (m *MainWindow) showServerCVars() { current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) if m.use_other_servers_tab { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { current_tab = "Favorites" } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { current_tab = "Servers" } } srv_address := m.getIpFromServersList(current_tab) if len(srv_address) > 0 { m.server_cvars_dialog.Initialize(m.window, srv_address) } } func (m *MainWindow) showShortServerInformation() { fmt.Println("Server selection changed, updating server's information widget...") m.server_info_store.Clear() m.players_info_store.Clear() current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) if m.use_other_servers_tab { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { current_tab = "Favorites" } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { current_tab = "Servers" } } srv_address := m.getIpFromServersList(current_tab) // Getting server information from cache. if len(srv_address) > 0 && ctx.Cache.Servers[srv_address].Server.Players != "" { server_info := ctx.Cache.Servers[srv_address].Server parsed_general_data := ioq3dataparser.ParseInfoToMap(server_info.ExtendedConfig) parsed_players_info := ioq3dataparser.ParsePlayersInfoToMap(server_info.PlayersInfo) // Append to treeview generic info first. After appending it // will be deleted from map. // Server's name. iter := new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Server's name", nil)) m.server_info_store.SetValue(iter, 1, ctx.Colorizer.Fix(parsed_general_data["sv_hostname"])) delete(parsed_general_data, "sv_hostname") // Game version. iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Game version", nil)) m.server_info_store.SetValue(iter, 1, parsed_general_data["g_modversion"]) delete(parsed_general_data, "g_modversion") // Players. iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Players", nil)) m.server_info_store.SetValue(iter, 1, server_info.Players+" of "+parsed_general_data["sv_maxclients"]+" ("+server_info.Bots+" bots)") delete(parsed_general_data, "sv_maxclients") // Ping iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Ping", nil)) m.server_info_store.SetValue(iter, 1, server_info.Ping+" ms") // Game mode iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Game mode", nil)) m.server_info_store.SetValue(iter, 1, m.gamemodes[server_info.Gamemode]) // Map name iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Current map", nil)) m.server_info_store.SetValue(iter, 1, server_info.Map) // Private or public? iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, ctx.Translator.Translate("Passworded", nil)) passworded_status := "" + ctx.Translator.Translate("No", nil) + "" if server_info.IsPrivate == "1" { passworded_status = "" + ctx.Translator.Translate("Yes", nil) + "" } m.server_info_store.SetValue(iter, 1, passworded_status) // Sorting keys of map. players_map_keys := make([]string, 0, len(parsed_players_info)) for k := range parsed_players_info { // ToDo: figure out how to do this properly without // append(). players_map_keys = append(players_map_keys, k) } sort.Strings(players_map_keys) for k := range players_map_keys { iter = new(gtk.TreeIter) nick := ctx.Colorizer.Fix(parsed_players_info[players_map_keys[k]]["nick"]) m.players_info_store.Append(iter) m.players_info_store.SetValue(iter, 0, nick) m.players_info_store.SetValue(iter, 1, parsed_players_info[players_map_keys[k]]["frags"]) m.players_info_store.SetValue(iter, 2, parsed_players_info[players_map_keys[k]]["ping"]) } /* // Just a separator. iter = new(gtk.TreeIter) m.server_info_store.Append(iter) // Other parameters :). iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, "OTHER PARAMETERS") // Sort it! general_data_keys := make([]string, 0, len(parsed_general_data)) for k := range parsed_general_data { general_data_keys = append(general_data_keys, k) } sort.Strings(general_data_keys) for k := range general_data_keys { iter = new(gtk.TreeIter) m.server_info_store.Append(iter) m.server_info_store.SetValue(iter, 0, general_data_keys[k]) m.server_info_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]]) } */ } } // Show tray menu on right-click on tray icon. func (m *MainWindow) showTrayMenu(cbx *glib.CallbackContext) { m.tray_menu.Popup(nil, nil, gtk.StatusIconPositionMenu, m.tray_icon, uint(cbx.Args(0)), uint32(cbx.Args(1))) } // Unlocking interface after game shut down. func (m *MainWindow) unlockInterface() { m.launch_button.SetSensitive(true) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": ctx.Translator.Translate("URTrator is ready.", nil)}) } func (m *MainWindow) updateOneServer() { if m.servers_already_updating { return } m.servers_already_updating = true ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "" + ctx.Translator.Translate("Updating selected server...", nil) + ""}) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) srv_address := m.getIpFromServersList(current_tab) if len(srv_address) > 0 { go ctx.Requester.UpdateOneServer(srv_address) } } // Triggered when "Update all servers" button is clicked. func (m *MainWindow) UpdateServers() { if m.servers_already_updating { return } m.servers_already_updating = true ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "" + ctx.Translator.Translate("Updating servers...", nil) + ""}) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) fmt.Println("Updating servers on tab '" + current_tab + "'...") if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { go ctx.Requester.UpdateAllServers(false) } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { go ctx.Requester.UpdateFavoriteServers() } } func (m *MainWindow) UpdateServersEventHandler(data map[string]string) { ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "" + ctx.Translator.Translate("Updating servers...", nil) + ""}) go ctx.Requester.UpdateAllServers(true) }