Compare commits
63 Commits
0.1.0-beta
...
v0.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| e66875ffbe | |||
| 979de8d858 | |||
| f0ddda1af5 | |||
| bd344fee2e | |||
| 7950ab5a1f | |||
| 3b3aae16b0 | |||
| a57c878dad | |||
| 474821ba7b | |||
| f32cf4d1f6 | |||
| bd04870aa3 | |||
| 280c65f116 | |||
| 32c6297765 | |||
| 190f76eb82 | |||
| 5c295f08ab | |||
| 061bfcaeb9 | |||
| 5ca8299714 | |||
| 9c8aa1cc34 | |||
| 5fcbd8536c | |||
| fb7a471aec | |||
| 8c9d948a52 | |||
| 8b44d194b5 | |||
| 3b0a93e63a | |||
| b85ba0470c | |||
| f127fdc9f4 | |||
| 5ef54d943e | |||
| 9e6cdfc869 | |||
| bfd3f884b3 | |||
| 7e6b698c1c | |||
| 4516abb916 | |||
| e731653652 | |||
| e16d6fa878 | |||
| 89298d894b | |||
| 88b9b31f6a | |||
| 1fe49871f1 | |||
| 4f5bf90dbe | |||
| 25bebf87df | |||
| c4ed421106 | |||
| 0c0fcd5b24 | |||
| 4d466a9d2b | |||
| 2cdee94efe | |||
| 2b1caac8f6 | |||
| 862b336556 | |||
| 90f888bdfb | |||
| a132ee0f7b | |||
| 8b06dff083 | |||
| ea8bdde224 | |||
| 6495e90737 | |||
| 3e89df1009 | |||
| c00ff2cea5 | |||
| 93d2bb7fc1 | |||
| 0392f510f5 | |||
| 57a5f7cb4c | |||
| 8a3f2a9a2e | |||
| 4e9a6ae970 | |||
| 7f80f99529 | |||
| b1d38bbdcf | |||
| e487b8521c | |||
| e12c76e424 | |||
| 640020d23f | |||
| a64c842e19 | |||
| 1330699f41 | |||
| a97b041679 | |||
| 68bd842c1f |
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
[](https://gitter.im/urtrator/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/urtrator/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
Chat on Matrix: #gitter_urtrator=2Flobby:matrix.org (Gitter bridge).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
URTrator is a desktop application that should (eventually) replace
|
URTrator is a desktop application that should (eventually) replace
|
||||||
@@ -25,6 +27,7 @@ the game.
|
|||||||
* Favorites servers.
|
* Favorites servers.
|
||||||
* Updating single server.
|
* Updating single server.
|
||||||
* Showing information about servers (like in UrT Connector).
|
* Showing information about servers (like in UrT Connector).
|
||||||
|
* Clipboard monitoring.
|
||||||
|
|
||||||
Planning:
|
Planning:
|
||||||
|
|
||||||
@@ -35,11 +38,15 @@ Planning:
|
|||||||
* All kinds of notifications.
|
* All kinds of notifications.
|
||||||
* Extended profile editor, so every profile could have own configuration
|
* Extended profile editor, so every profile could have own configuration
|
||||||
files, etc.
|
files, etc.
|
||||||
* Clipboard monitoring.
|
|
||||||
* ...maybe more :)
|
* ...maybe more :)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
|
## Precautions
|
||||||
|
|
||||||
|
Due to Go's GC bugs, it is required to use devel version of Go
|
||||||
|
compiler!
|
||||||
|
|
||||||
## Release
|
## Release
|
||||||
|
|
||||||
You don't need to install anything, thanks to Go's.
|
You don't need to install anything, thanks to Go's.
|
||||||
|
|||||||
9
cache/cache_servers.go
vendored
9
cache/cache_servers.go
vendored
@@ -55,6 +55,7 @@ func (c *Cache) FlushServers(data map[string]string) {
|
|||||||
new_servers[mapping_item_name].Port = s.Server.Port
|
new_servers[mapping_item_name].Port = s.Server.Port
|
||||||
new_servers[mapping_item_name].Name = s.Server.Name
|
new_servers[mapping_item_name].Name = s.Server.Name
|
||||||
new_servers[mapping_item_name].Players = s.Server.Players
|
new_servers[mapping_item_name].Players = s.Server.Players
|
||||||
|
new_servers[mapping_item_name].Bots = s.Server.Bots
|
||||||
new_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
|
new_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
|
||||||
new_servers[mapping_item_name].Ping = s.Server.Ping
|
new_servers[mapping_item_name].Ping = s.Server.Ping
|
||||||
new_servers[mapping_item_name].Map = s.Server.Map
|
new_servers[mapping_item_name].Map = s.Server.Map
|
||||||
@@ -65,11 +66,13 @@ func (c *Cache) FlushServers(data map[string]string) {
|
|||||||
new_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
|
new_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
|
||||||
new_servers[mapping_item_name].Favorite = s.Server.Favorite
|
new_servers[mapping_item_name].Favorite = s.Server.Favorite
|
||||||
new_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
|
new_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
|
||||||
|
new_servers[mapping_item_name].Password = s.Server.Password
|
||||||
} else {
|
} else {
|
||||||
cached_servers[mapping_item_name].Ip = s.Server.Ip
|
cached_servers[mapping_item_name].Ip = s.Server.Ip
|
||||||
cached_servers[mapping_item_name].Port = s.Server.Port
|
cached_servers[mapping_item_name].Port = s.Server.Port
|
||||||
cached_servers[mapping_item_name].Name = s.Server.Name
|
cached_servers[mapping_item_name].Name = s.Server.Name
|
||||||
cached_servers[mapping_item_name].Players = s.Server.Players
|
cached_servers[mapping_item_name].Players = s.Server.Players
|
||||||
|
cached_servers[mapping_item_name].Bots = s.Server.Bots
|
||||||
cached_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
|
cached_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
|
||||||
cached_servers[mapping_item_name].Ping = s.Server.Ping
|
cached_servers[mapping_item_name].Ping = s.Server.Ping
|
||||||
cached_servers[mapping_item_name].Map = s.Server.Map
|
cached_servers[mapping_item_name].Map = s.Server.Map
|
||||||
@@ -80,6 +83,7 @@ func (c *Cache) FlushServers(data map[string]string) {
|
|||||||
cached_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
|
cached_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
|
||||||
cached_servers[mapping_item_name].Favorite = s.Server.Favorite
|
cached_servers[mapping_item_name].Favorite = s.Server.Favorite
|
||||||
cached_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
|
cached_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
|
||||||
|
cached_servers[mapping_item_name].Password = s.Server.Password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,12 +92,12 @@ func (c *Cache) FlushServers(data map[string]string) {
|
|||||||
fmt.Println("Adding new servers...")
|
fmt.Println("Adding new servers...")
|
||||||
if len(new_servers) > 0 {
|
if len(new_servers) > 0 {
|
||||||
for _, srv := range new_servers {
|
for _, srv := range new_servers {
|
||||||
tx.NamedExec("INSERT INTO servers (ip, port, name, ping, players, maxplayers, gamemode, map, version, extended_config, players_info, is_private, favorite) VALUES (:ip, :port, :name, :ping, :players, :maxplayers, :gamemode, :map, :version, :extended_config, :players_info, :is_private, :favorite)", srv)
|
tx.NamedExec("INSERT INTO servers (ip, port, name, ping, players, maxplayers, gamemode, map, version, extended_config, players_info, is_private, favorite, profile_to_use, bots) VALUES (:ip, :port, :name, :ping, :players, :maxplayers, :gamemode, :map, :version, :extended_config, :players_info, :is_private, :favorite, :profile_to_use, :bots)", srv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("Updating cached servers...")
|
fmt.Println("Updating cached servers...")
|
||||||
for _, srv := range cached_servers {
|
for _, srv := range cached_servers {
|
||||||
_, err := tx.NamedExec("UPDATE servers SET name=:name, players=:players, maxplayers=:maxplayers, gamemode=:gamemode, map=:map, ping=:ping, version=:version, extended_config=:extended_config, favorite=:favorite, password=:password, players_info=:players_info, is_private=:is_private WHERE ip=:ip AND port=:port", &srv)
|
_, err := tx.NamedExec("UPDATE servers SET name=:name, players=:players, maxplayers=:maxplayers, gamemode=:gamemode, map=:map, ping=:ping, version=:version, extended_config=:extended_config, favorite=:favorite, password=:password, players_info=:players_info, is_private=:is_private, profile_to_use=:profile_to_use, bots=:bots WHERE ip=:ip AND port=:port", &srv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
}
|
}
|
||||||
@@ -123,6 +127,7 @@ func (c *Cache) LoadServers(data map[string]string) {
|
|||||||
c.Servers[key].Server.Ip = server.Ip
|
c.Servers[key].Server.Ip = server.Ip
|
||||||
c.Servers[key].Server.Port = server.Port
|
c.Servers[key].Server.Port = server.Port
|
||||||
c.Servers[key].Server.Players = server.Players
|
c.Servers[key].Server.Players = server.Players
|
||||||
|
c.Servers[key].Server.Bots = server.Bots
|
||||||
c.Servers[key].Server.Maxplayers = server.Maxplayers
|
c.Servers[key].Server.Maxplayers = server.Maxplayers
|
||||||
c.Servers[key].Server.Ping = server.Ping
|
c.Servers[key].Server.Ping = server.Ping
|
||||||
c.Servers[key].Server.Gamemode = server.Gamemode
|
c.Servers[key].Server.Gamemode = server.Gamemode
|
||||||
|
|||||||
114
clipboardwatcher/clipboardwatcher_object.go
Normal file
114
clipboardwatcher/clipboardwatcher_object.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
// URTator - Urban Terror server browser and game launcher, written in
|
||||||
|
// Go.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under Terms and Conditions of GNU General Public License
|
||||||
|
// version 3 or any higher.
|
||||||
|
// ToDo: put full text of license here.
|
||||||
|
package clipboardwatcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
// stdlib
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
// other
|
||||||
|
"github.com/mattn/go-gtk/gdk"
|
||||||
|
"github.com/mattn/go-gtk/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClipboardWatcher struct {
|
||||||
|
// Clipboard.
|
||||||
|
clipboard *gtk.Clipboard
|
||||||
|
// PRIMARY clipboard.
|
||||||
|
prim_clipboard *gtk.Clipboard
|
||||||
|
|
||||||
|
// Flags.
|
||||||
|
// We have just copy connect string to clipboard.
|
||||||
|
// Used to ignore clipboard data in check*Input()
|
||||||
|
just_set bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ClipboardWatcher) checkInput() {
|
||||||
|
if !cw.just_set {
|
||||||
|
text := cw.clipboard.WaitForText()
|
||||||
|
cw.parseData(text)
|
||||||
|
} else {
|
||||||
|
cw.just_set = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ClipboardWatcher) checkPrimaryInput() {
|
||||||
|
if !cw.just_set {
|
||||||
|
text := cw.prim_clipboard.WaitForText()
|
||||||
|
cw.parseData(text)
|
||||||
|
} else {
|
||||||
|
cw.just_set = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ClipboardWatcher) CopyServerData(server_address string) error {
|
||||||
|
server, ok := Cache.Servers[server_address]
|
||||||
|
if !ok {
|
||||||
|
// ToDo: show message box?
|
||||||
|
return errors.New("Server wasn't selected")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Composing connection string.
|
||||||
|
var connect_string string = ""
|
||||||
|
connect_string += "/connect " + server.Server.Ip + ":" + server.Server.Port
|
||||||
|
if len(server.Server.Password) >= 1 {
|
||||||
|
connect_string += ";password " + server.Server.Password
|
||||||
|
}
|
||||||
|
fmt.Println("Connect string: ", connect_string)
|
||||||
|
cw.just_set = true
|
||||||
|
cw.clipboard.SetText(connect_string)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ClipboardWatcher) Initialize() {
|
||||||
|
fmt.Println("Initializing clipboard watcher...")
|
||||||
|
|
||||||
|
cw.just_set = false
|
||||||
|
|
||||||
|
cw.clipboard = gtk.NewClipboardGetForDisplay(gdk.DisplayGetDefault(), gdk.SELECTION_CLIPBOARD)
|
||||||
|
cw.clipboard.Connect("owner-change", cw.checkInput)
|
||||||
|
|
||||||
|
cw.prim_clipboard = gtk.NewClipboardGetForDisplay(gdk.DisplayGetDefault(), gdk.SELECTION_PRIMARY)
|
||||||
|
cw.prim_clipboard.Connect("owner-change", cw.checkPrimaryInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *ClipboardWatcher) parseData(data string) {
|
||||||
|
// We should check only first string.
|
||||||
|
data = strings.Split(data, "\n")[0]
|
||||||
|
// Checking if we have connection string here.
|
||||||
|
if strings.Contains(data, "ct ") {
|
||||||
|
fmt.Println("Connection string detected!")
|
||||||
|
var server string = ""
|
||||||
|
var password string = ""
|
||||||
|
conn_string := strings.Split(data, ";")
|
||||||
|
if len(conn_string) > 0 {
|
||||||
|
srv_string := strings.Split(data, ";")[0]
|
||||||
|
srv_splitted := strings.Split(srv_string, "ct ")
|
||||||
|
if len(srv_splitted) > 1 {
|
||||||
|
server_raw := strings.Split(srv_splitted[1], " ")[0]
|
||||||
|
// Get rid of spaces.
|
||||||
|
server = strings.TrimSpace(server_raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(conn_string) > 1 && strings.Contains(data, "password") {
|
||||||
|
pw_string := strings.Split(data, ";")[1]
|
||||||
|
pw_splitted := strings.Split(pw_string, "password ")
|
||||||
|
if len(pw_splitted) > 1 {
|
||||||
|
password_raw := strings.Split(pw_splitted[1], " ")[0]
|
||||||
|
// Get rid of spaces.
|
||||||
|
password = strings.TrimSpace(password_raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Eventer.LaunchEvent("setQuickConnectDetails", map[string]string{"server": server, "password": password})
|
||||||
|
}
|
||||||
|
}
|
||||||
28
clipboardwatcher/exported.go
Normal file
28
clipboardwatcher/exported.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// URTator - Urban Terror server browser and game launcher, written in
|
||||||
|
// Go.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under Terms and Conditions of GNU General Public License
|
||||||
|
// version 3 or any higher.
|
||||||
|
// ToDo: put full text of license here.
|
||||||
|
package clipboardwatcher
|
||||||
|
|
||||||
|
import(
|
||||||
|
// local
|
||||||
|
"github.com/pztrn/urtrator/cache"
|
||||||
|
"github.com/pztrn/urtrator/eventer"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Cache *cache.Cache
|
||||||
|
Eventer *eventer.Eventer
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(c *cache.Cache, e *eventer.Eventer) *ClipboardWatcher {
|
||||||
|
Cache = c
|
||||||
|
Eventer = e
|
||||||
|
cw := ClipboardWatcher{}
|
||||||
|
return &cw
|
||||||
|
}
|
||||||
@@ -21,8 +21,28 @@ type Colorizer struct {
|
|||||||
colors map[string]string
|
colors map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Colorizer) ClearFromMarkup(data string) string {
|
||||||
|
var result string = ""
|
||||||
|
|
||||||
|
data = html.EscapeString(data)
|
||||||
|
|
||||||
|
data_splitted := strings.Split(data, ">")
|
||||||
|
|
||||||
|
if len(data_splitted) > 1 {
|
||||||
|
for item := range data_splitted {
|
||||||
|
if len(data_splitted[item]) > 0 {
|
||||||
|
result += strings.Split(data_splitted[item], "<")[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = data_splitted[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Colorizer) Fix(data string) string {
|
func (c *Colorizer) Fix(data string) string {
|
||||||
result := ""
|
var result string = ""
|
||||||
|
|
||||||
data = html.EscapeString(data)
|
data = html.EscapeString(data)
|
||||||
|
|
||||||
|
|||||||
@@ -10,5 +10,11 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
const (
|
const (
|
||||||
URTRATOR_VERSION = "0.1-beta3"
|
URTRATOR_VERSION = "0.1.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Self-named.
|
||||||
|
var SUPPORTED_URT_VERSIONS []string = []string{
|
||||||
|
"4.2.023",
|
||||||
|
"4.3.1",
|
||||||
|
}
|
||||||
|
|||||||
16
common/server_list_icons.go
Normal file
16
common/server_list_icons.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// URTator - Urban Terror server browser and game launcher, written in
|
||||||
|
// Go.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under Terms and Conditions of GNU General Public License
|
||||||
|
// version 3 or any higher.
|
||||||
|
// ToDo: put full text of license here.
|
||||||
|
package common
|
||||||
|
|
||||||
|
var SERVER_OFFLINE = `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`
|
||||||
|
var SERVER_ONLINE = `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`
|
||||||
|
var SERVER_PRIVATE = `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`
|
||||||
|
var SERVER_PUBLIC = `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
|
||||||
|
`
|
||||||
22
common/toolbar_icons.go
Normal file
22
common/toolbar_icons.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// URTator - Urban Terror server browser and game launcher, written in
|
||||||
|
// Go.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under Terms and Conditions of GNU General Public License
|
||||||
|
// version 3 or any higher.
|
||||||
|
// ToDo: put full text of license here.
|
||||||
|
package common
|
||||||
|
|
||||||
|
var ADD_TO_FAVORITES = `iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAK6SURBVFiFxZexaxRBGMXft7t6B4pR8CSKovbBQsTOwkrRMoVgm/wDVgpiZSUW+Qe0F9HCMkHsAjYiSMAUijZyIYdgipCbnW++Z3F7l93bu0v2NJuBZZZlZ+bHmzdvZoQkDrNEhzo6gKTKzyJyAkAT48ENgCO5dSAAAJoPX15ZI6w1EhBR59nCl7kqHVYFiIKF1v1bj5DETQAAAYAGH3bwauV5CxWntSoAjIYoSvDz9ypEBIAAIM7NXIXRqnY3BYARgQpjgEByYAqz6itqCgUImsKoEOYAzMOmWNLTKZABINOAAAJ9XQpYT26Goe9apwc8zLTwPdg/KpCFTANAPBGAhJpHGAYIux4QkdlJXSAXVnkFmotLl9cAjgyZfonj2AXVRgjFKVBTJHHsFpcutSe1B6Tz4sGPQVjlASKjteZvLuBI0sg+sfdI7h1oOL8N1UyBzIUu3cbdG/capMFoGNRmMAaYGdQc3n9cLoRVwQNmRIQY678+IJIIIjLyATCo+2Xjzzr6OyvJkc/JY+dLPikCkNCgCCGAwtGDC3YDKM/AfkWAoyFUy1lRAAhmPYONARgMnocoMGSDj4HQ4BGsuFRLCgTtAZhYWYHhwScpgCkUMCO66TYunr6GvvnYNx85eFdz2Nz6VlDh1PELiCRGyYQ0mAUYDanvTvSAkei8W30zcRkmSeJuX79TWoY0YvnTilPVxpimmWjSQS8LSgDu9eP2HPbYz+efnml7TaGqBQW8pkjTtPH2yebZSe2zwV0JYD/HKBGZtWwuhxXwufklubFXXyWA/RYzwqsrK+BdfbvhKAV6Dq9pN/Q+80AuDVNN6zsROU3hNRRyIPVpfSci5z3SEAo51PW1KWDouh00j86ABJiFTTft1uIBo6Hz+fvXMReTYsjsp0iVy6mIzKB3avpvV7NKAAdRDv12/Bc1PDWiO2VdhgAAAABJRU5ErkJggg==`
|
||||||
|
|
||||||
|
var COPY_CREDENTIALS = `iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAB11BMVEUAAAD///////+AgICAj4CJiYDDw8OQk42PkYyNkIqFh4KHioWHiYWJi4WJi4eLjYfDw8PFxcPFxcXHx8XHx8fJycfJycnp6enr6+nr6+vt7evt7e3v7+3v7+/x8e/x8fHz8/P19fX39/f5+fn7+/v9/f3///+IiYSQkY2QkY2GioWLjoiZm5aFioSGioSIi4eIi4aHioWIioWIi4aLjomGioSHiYSHioWIioSIioWIi4WJi4aJjIiJjYeLjomMjoqMjouMkImMkIqNkIuSlpCTlpGVlpWVmJOYm5eYnJeanJqbm5ubnpqdnZ2enp6fn5+kpKSmpqamqaWoqKioqaipqamwsa+xsbGzs7O0tLS5ubm6urq9vr2+vr7BwcHCwsLDw8LDw8PExMPExMTFxcTFxcXGxsXGxsbGx8XGx8bHx8bHx8fIyMfIyMjNzc3R0dHm5ubn5+fo6OXo6Ofo6Ojp6ejp6enp6ujq6unq6urr6+rr6+vs7Ovs7Ozt7evt7ezt7e3u7u3u7u7v7+3v7+7v7+/w8O/w8PDx8fDx8fHy8vLz8/P09PL09PT19fX29vX29vb39/X39/f4+Pf4+Pj5+fn6+vr7+/r7+/v8/Pz9/f3+/v7///9tYCWGAAAANXRSTlMAAQIMEBoiXF1eYmZ/f39/f39/f39/f39/f39/f39/f39/f39/f3+ct77C29zo7fD4+v7+/rdyDXMAAAABYktHRJxxvMInAAACOklEQVRIx51VQW7bMBAc7i5jt0AudRK/off+qO/qN/qWIO61SFEgAewmliWLnB5IS5SlKnF1kUDO7M7MEhRw4eOwNDezz2M9XDAs1rMVH0cE4DCDX54vyKUeLibY7C4vI/BCSZzk2L+qcd4Dc7Tr63PAqvgOu/uuQ5729dfZEL51HVw3oN8z+Ls5D3ifh/cPzr0NjSUhe5gRRo7nwPnykUMPb8ARzjzQ9ZTH8dTJNcoOWKTlqYwjENiZsK5CgbwdqyGYYrIEi4eyri/wikgBiVhKIhwKE48D8UAgbMWCQLhFqZ2FGoIgGDI+S2I3l8JDjp4EQTlBsgceSooHEKEIAhKIxFlKuQyKOSRESN3h7niiWNpzgwuLffSZQIIpJiu6nd5xlaInQDACdETIKRjAjOtfvoieSqaesScUxx0RiL/6OHEyx5s0Tzs77gACWg6iTtrEL9CbTlsiKfpb5rNzUkM4/9FbR4gZLgIQpKXoJXlWRHjzXlWypB7vUJbuzIr33quayx0+EICDc3BdNr0awi+8iZqqEDAcn8qrikkNQeTokxr1KrIPgKEqZ1wzluWTGjM1UYmbzcT/gRyqsaWJft9i6UHnmjEhJPxAjemXK1b7pvm5me5QqhG9EhU+B7b1rqrGhMhejfempipOXxiPzZ/nDceENquRRVIjqm3dNq5pttv7MGU6FGrMVFjVVYjt/ql6aKf+ouGGEeKcOFOnTo6Hev9S7193D6+T1/znT6P7HYi6r34E/OfzFzi+itJ7Ai74AAAAAElFTkSuQmCC`
|
||||||
|
|
||||||
|
var EDIT_FAVORITE = `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`
|
||||||
|
|
||||||
|
var REFRESH_ALL_SERVERS = `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`
|
||||||
|
|
||||||
|
var REFRESH_ONE_SERVER = `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`
|
||||||
|
|
||||||
|
var REMOVE_FAVORITE = `iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFFSURBVFiF7ZYxbsMwDEU/1Qbp1E6ekjno0Gv0ELllpiw9RYAORYCeIFMHA7Ec8neQZUtuk06GO8gA8anpP5IybSGJOR83q3sBKAAFoAD8B4D7mIjII4AlgLuJPQ1AQ/IrAwDw8LbZvAtZTelOkdPr8fgSzymAo2r1vN3CLZcQkT4AADF3w9T6zxiZhxloBqiCXU4zmPf42O0qJKNPAWCqIID6cIA4F0JkUJEBJMYIgomSDOadLlYrmGrWkQyAZlDvoW2bA4yM065kAEAGMAZxTRM6cw3AVKHe4xIB0jGkOjZPIBh1DEBCmuZ2B0wVl/M5dCAx/a3y3l5kqP5KJ2Lu/gKgGdq6xmK9zgx+1NqZSDTqVNJLCATtzkaireubIzA1O33u95O/hgi7IBQRKxCRJ4RFNPV2zBaRlJ/SAlAACkABmBvgG+Wf86x1nhNMAAAAAElFTkSuQmCC`
|
||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
// local
|
// local
|
||||||
"github.com/pztrn/urtrator/cache"
|
"github.com/pztrn/urtrator/cache"
|
||||||
|
"github.com/pztrn/urtrator/clipboardwatcher"
|
||||||
"github.com/pztrn/urtrator/colorizer"
|
"github.com/pztrn/urtrator/colorizer"
|
||||||
"github.com/pztrn/urtrator/configuration"
|
"github.com/pztrn/urtrator/configuration"
|
||||||
"github.com/pztrn/urtrator/database"
|
"github.com/pztrn/urtrator/database"
|
||||||
@@ -30,6 +31,8 @@ import (
|
|||||||
type Context struct {
|
type Context struct {
|
||||||
// Caching.
|
// Caching.
|
||||||
Cache *cache.Cache
|
Cache *cache.Cache
|
||||||
|
// Clipboard watcher.
|
||||||
|
Clipboard *clipboardwatcher.ClipboardWatcher
|
||||||
// Colors parser and prettifier.
|
// Colors parser and prettifier.
|
||||||
Colorizer *colorizer.Colorizer
|
Colorizer *colorizer.Colorizer
|
||||||
// Configuration.
|
// Configuration.
|
||||||
@@ -65,6 +68,11 @@ func (ctx *Context) initializeCache() {
|
|||||||
ctx.Cache.Initialize()
|
ctx.Cache.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) InitializeClipboardWatcher() {
|
||||||
|
ctx.Clipboard = clipboardwatcher.New(ctx.Cache, ctx.Eventer)
|
||||||
|
ctx.Clipboard.Initialize()
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *Context) initializeColorizer() {
|
func (ctx *Context) initializeColorizer() {
|
||||||
ctx.Colorizer = colorizer.New()
|
ctx.Colorizer = colorizer.New()
|
||||||
ctx.Colorizer.Initialize()
|
ctx.Colorizer.Initialize()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ func migrate_full(db *Database, version int) {
|
|||||||
if version == 6 {six_to_seven(db); version = 7}
|
if version == 6 {six_to_seven(db); version = 7}
|
||||||
if version == 7 {seven_to_eight(db); version = 8}
|
if version == 7 {seven_to_eight(db); version = 8}
|
||||||
if version == 8 {eight_to_nine(db); version = 9}
|
if version == 8 {eight_to_nine(db); version = 9}
|
||||||
|
if version == 9 {nine_to_ten(db); version = 10}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial database structure.
|
// Initial database structure.
|
||||||
@@ -115,3 +116,10 @@ func eight_to_nine(db *Database) {
|
|||||||
db.Db.MustExec("ALTER TABLE servers ADD is_private VARCHAR(1) NOT NULL DEFAULT '0'")
|
db.Db.MustExec("ALTER TABLE servers ADD is_private VARCHAR(1) NOT NULL DEFAULT '0'")
|
||||||
db.Db.MustExec("UPDATE database SET version=9")
|
db.Db.MustExec("UPDATE database SET version=9")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bots count.
|
||||||
|
func nine_to_ten(db *Database) {
|
||||||
|
fmt.Println("Upgrading database from 9 to 10...")
|
||||||
|
db.Db.MustExec("ALTER TABLE servers ADD bots VARCHAR(2) NOT NULL DEFAULT '0'")
|
||||||
|
db.Db.MustExec("UPDATE database SET version=10")
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ type Server struct {
|
|||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
// Current players count
|
// Current players count
|
||||||
Players string `db:"players"`
|
Players string `db:"players"`
|
||||||
|
// Bots count
|
||||||
|
Bots string `db:"bots"`
|
||||||
// Maximum players
|
// Maximum players
|
||||||
Maxplayers string `db:"maxplayers"`
|
Maxplayers string `db:"maxplayers"`
|
||||||
// Ping
|
// Ping
|
||||||
|
|||||||
@@ -150,6 +150,9 @@ ln -s ../../../Framework .
|
|||||||
cd ../../../MacOS
|
cd ../../../MacOS
|
||||||
GDK_PIXBUF_MODULE_FILE="../lib/gdk-pixbuf-2.0/loaders.cache" GDK_PIXBUF_MODULEDIR="../lib/gdk-pixbuf-2.0/2.10.0/loaders/" GTK_EXE_PREFIX="../lib" GTK_PATH="../Framework" ./gdk-pixbuf-query-loaders > ../lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
|
GDK_PIXBUF_MODULE_FILE="../lib/gdk-pixbuf-2.0/loaders.cache" GDK_PIXBUF_MODULEDIR="../lib/gdk-pixbuf-2.0/2.10.0/loaders/" GTK_EXE_PREFIX="../lib" GTK_PATH="../Framework" ./gdk-pixbuf-query-loaders > ../lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
|
||||||
|
|
||||||
|
echo "Copying icon theme..."
|
||||||
|
|
||||||
|
|
||||||
echo "Finishing..."
|
echo "Finishing..."
|
||||||
|
|
||||||
echo "URTrator is ready! Copy URTrator.app bundle to Applications and launch it!"
|
echo "URTrator is ready! Copy URTrator.app bundle to Applications and launch it!"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ check_msys() {
|
|||||||
# Check if we have neccessary MSYS packages installed.
|
# Check if we have neccessary MSYS packages installed.
|
||||||
check_msys_packages() {
|
check_msys_packages() {
|
||||||
echo "* Installing neccessary MSYS2 packages..."
|
echo "* Installing neccessary MSYS2 packages..."
|
||||||
pacman -S ${MINGW_PACKAGE_PREFIX}-tools-git ${MINGW_PACKAGE_PREFIX}-gtk2 ${MINGW_PACKAGE_PREFIX}-pkg-config ${MINGW_PACKAGE_PREFIX}-gtk-engines ${MINGW_PACKAGE_PREFIX}-gtk-engine-murrine --noconfirm --needed
|
pacman -S ${MINGW_PACKAGE_PREFIX}-tools-git ${MINGW_PACKAGE_PREFIX}-gtk2 ${MINGW_PACKAGE_PREFIX}-pkg-config ${MINGW_PACKAGE_PREFIX}-gtk-engines ${MINGW_PACKAGE_PREFIX}-gtk-engine-murrine ${MINGW_PACKAGE_PREFIX}-gcc --noconfirm --needed
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build URTrator
|
# Build URTrator
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import (
|
|||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
//"reflect"
|
||||||
|
|
||||||
|
// github
|
||||||
|
"github.com/mattn/go-gtk/glib"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Eventer struct {
|
type Eventer struct {
|
||||||
@@ -44,11 +48,19 @@ func (e *Eventer) LaunchEvent(event string, data map[string]string) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("Event " + event + " not found!")
|
return errors.New("Event " + event + " not found!")
|
||||||
}
|
}
|
||||||
fmt.Println("Launching event " + event)
|
|
||||||
|
|
||||||
for _, val := range e.events[event] {
|
fmt.Println("Launching event " + event)
|
||||||
val(data)
|
glib.IdleAdd(func() bool {
|
||||||
}
|
e.reallyLaunchEvent(event, data)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Eventer) reallyLaunchEvent(event string, data map[string]string) {
|
||||||
|
fmt.Println("Really launching event " + event + "...")
|
||||||
|
for _, val := range e.events[event] {
|
||||||
|
val(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -34,13 +35,17 @@ type Launcher struct {
|
|||||||
|
|
||||||
func (l *Launcher) CheckForLaunchedUrbanTerror() error {
|
func (l *Launcher) CheckForLaunchedUrbanTerror() error {
|
||||||
if l.launched {
|
if l.launched {
|
||||||
mbox_string := "Game is launched.\n\nCannot quit, because game is launched.\nQuit Urban Terror to exit URTrator!"
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Game is launched.\n\nCannot quit, because game is launched.\nQuit Urban Terror to exit URTrator!"
|
||||||
})
|
m := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
m.Response(func() {
|
||||||
return errors.New("User didn't select valid profile, mismatch with server's version.")
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
return errors.New("User didn't select valid profile, mismatch with server's version.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -110,6 +115,12 @@ func (l *Launcher) Launch(server_profile *datamodels.Server, user_profile *datam
|
|||||||
go func() {
|
go func() {
|
||||||
go func() {
|
go func() {
|
||||||
cmd := exec.Command(launch_bin, launch_params...)
|
cmd := exec.Command(launch_bin, launch_params...)
|
||||||
|
// This workaround is required on Windows, otherwise ioq3
|
||||||
|
// will not find game data.
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
dir := filepath.Dir(launch_bin)
|
||||||
|
cmd.Dir = dir
|
||||||
|
}
|
||||||
out, err1 := cmd.Output()
|
out, err1 := cmd.Output()
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
fmt.Println("Launch error: " + err1.Error())
|
fmt.Println("Launch error: " + err1.Error())
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
//"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -34,7 +34,8 @@ type Pooler struct {
|
|||||||
func (p *Pooler) Initialize() {
|
func (p *Pooler) Initialize() {
|
||||||
fmt.Println("Initializing requester goroutine pooler...")
|
fmt.Println("Initializing requester goroutine pooler...")
|
||||||
// ToDo: figure out how to make this work nice.
|
// ToDo: figure out how to make this work nice.
|
||||||
p.maxrequests = 100
|
p.maxrequests = 200
|
||||||
|
_ = runtime.GOMAXPROCS(runtime.NumCPU() * 4)
|
||||||
p.pp = "\377\377\377\377"
|
p.pp = "\377\377\377\377"
|
||||||
fmt.Println("Pooler initialized")
|
fmt.Println("Pooler initialized")
|
||||||
}
|
}
|
||||||
@@ -233,11 +234,34 @@ func (p *Pooler) UpdateSpecificServer(server *datamodels.Server) error {
|
|||||||
if len(received_lines) >= 2 {
|
if len(received_lines) >= 2 {
|
||||||
// Here we go, players information.
|
// Here we go, players information.
|
||||||
players := received_lines[2:]
|
players := received_lines[2:]
|
||||||
|
var real_players int = 0
|
||||||
|
var bots int = 0
|
||||||
// Calculate players!
|
// Calculate players!
|
||||||
if len(players) == 1 && len(players[0]) > 255 {
|
if len(players) == 1 && len(players[0]) > 255 {
|
||||||
server.Players = "0"
|
server.Players = "0"
|
||||||
|
server.Bots = "0"
|
||||||
} else {
|
} else {
|
||||||
server.Players = strconv.Itoa(len(players))
|
// Looks like we have last element to be empty, due to
|
||||||
|
// strings.Split() call before.
|
||||||
|
for i := range players {
|
||||||
|
// Get slice with data for bots-humans parsing.
|
||||||
|
player_data := strings.Split(string(players[i]), " ")
|
||||||
|
// If slice length isn't equal 3 - this is not what
|
||||||
|
// we want.
|
||||||
|
if len(player_data) != 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if player_data[1] == "0" {
|
||||||
|
bots++
|
||||||
|
} else {
|
||||||
|
real_players++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//server.Players = strconv.Itoa(len(players) - 1)
|
||||||
|
server.Players = strconv.Itoa(real_players)
|
||||||
|
server.Bots = strconv.Itoa(bots)
|
||||||
|
fmt.Println(server.Players, server.Bots)
|
||||||
}
|
}
|
||||||
server.PlayersInfo = strings.Join(received_lines[2:], "\\")
|
server.PlayersInfo = strings.Join(received_lines[2:], "\\")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ package requester
|
|||||||
import (
|
import (
|
||||||
// stdlib
|
// stdlib
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -46,11 +47,13 @@ func (r *Requester) Initialize() {
|
|||||||
|
|
||||||
// Gets all available servers from master server.
|
// Gets all available servers from master server.
|
||||||
// This isn't in pooler, because it have no need to be pooled.
|
// This isn't in pooler, because it have no need to be pooled.
|
||||||
func (r *Requester) getServers() {
|
func (r *Requester) getServers() error {
|
||||||
// IP addresses we will compose to return.
|
// IP addresses we will compose to return.
|
||||||
conn, err1 := net.Dial("udp", r.master_server + ":" + r.master_server_port)
|
conn, err1 := net.Dial("udp", r.master_server + ":" + r.master_server_port)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
fmt.Println("Error dialing to master server!")
|
fmt.Println("Error dialing to master server!")
|
||||||
|
Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "Failed to connect to master server!"})
|
||||||
|
return errors.New("Failed to connect to master server!")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -118,6 +121,8 @@ func (r *Requester) getServers() {
|
|||||||
Cache.Servers[addr].Server.Port = port
|
Cache.Servers[addr].Server.Port = port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates information about all available servers from master server and
|
// Updates information about all available servers from master server and
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
@@ -117,7 +118,6 @@ func (f *FavoriteDialog) initializeWindow() {
|
|||||||
f.window.SetModal(true)
|
f.window.SetModal(true)
|
||||||
f.window.SetSizeRequest(400, 200)
|
f.window.SetSizeRequest(400, 200)
|
||||||
f.window.SetResizable(false)
|
f.window.SetResizable(false)
|
||||||
f.vbox = gtk.NewVBox(false, 0)
|
|
||||||
|
|
||||||
// Load program icon from base64.
|
// Load program icon from base64.
|
||||||
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
|
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
|
||||||
@@ -131,54 +131,59 @@ func (f *FavoriteDialog) initializeWindow() {
|
|||||||
gtk_opts := gtk_opts_raw.ToGObject()
|
gtk_opts := gtk_opts_raw.ToGObject()
|
||||||
gtk_opts.Set("gtk-button-images", true)
|
gtk_opts.Set("gtk-button-images", true)
|
||||||
|
|
||||||
|
f.vbox = gtk.NewVBox(false, 0)
|
||||||
|
|
||||||
|
table := gtk.NewTable(5, 2, false)
|
||||||
|
f.vbox.PackStart(table, true, true, 5)
|
||||||
|
|
||||||
// Server name.
|
// Server name.
|
||||||
srv_name_hbox := gtk.NewHBox(false, 0)
|
|
||||||
f.vbox.PackStart(srv_name_hbox, false, true, 5)
|
|
||||||
srv_name_label := gtk.NewLabel("Server name:")
|
srv_name_label := gtk.NewLabel("Server name:")
|
||||||
srv_name_hbox.PackStart(srv_name_label, false, true, 5)
|
srv_name_label.SetAlignment(0, 0)
|
||||||
srv_name_sep := gtk.NewHSeparator()
|
table.Attach(srv_name_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
srv_name_hbox.PackStart(srv_name_sep, true, true, 5)
|
|
||||||
f.server_name = gtk.NewEntry()
|
f.server_name = gtk.NewEntry()
|
||||||
srv_name_hbox.PackStart(f.server_name, true, true, 5)
|
table.Attach(f.server_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Server address.
|
// Server address.
|
||||||
srv_addr_hbox := gtk.NewHBox(false, 0)
|
|
||||||
f.vbox.PackStart(srv_addr_hbox, false, true, 5)
|
|
||||||
srv_addr_label := gtk.NewLabel("Server address:")
|
srv_addr_label := gtk.NewLabel("Server address:")
|
||||||
srv_addr_hbox.PackStart(srv_addr_label, false, true, 5)
|
srv_addr_label.SetAlignment(0, 0)
|
||||||
srv_addr_sep := gtk.NewHSeparator()
|
table.Attach(srv_addr_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
srv_addr_hbox.PackStart(srv_addr_sep, true, true, 5)
|
|
||||||
|
srv_addr_hbox := gtk.NewHBox(false, 0)
|
||||||
f.server_address = gtk.NewEntry()
|
f.server_address = gtk.NewEntry()
|
||||||
srv_addr_hbox.PackStart(f.server_address, true, true, 5)
|
srv_addr_hbox.PackStart(f.server_address, true, true, 0)
|
||||||
srv_addr_update_btn := gtk.NewButton()
|
srv_addr_update_btn := gtk.NewButton()
|
||||||
srv_addr_update_btn.SetTooltipText("Update server information")
|
srv_addr_update_btn.SetTooltipText("Update server information")
|
||||||
srv_addr_update_btn_image := gtk.NewImageFromStock(gtk.STOCK_REDO, 24)
|
srv_addr_update_btn_image := gtk.NewImageFromStock(gtk.STOCK_REDO, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||||
srv_addr_update_btn.SetImage(srv_addr_update_btn_image)
|
srv_addr_update_btn.SetImage(srv_addr_update_btn_image)
|
||||||
srv_addr_update_btn.Clicked(f.updateServerInfo)
|
srv_addr_update_btn.Clicked(f.updateServerInfo)
|
||||||
srv_addr_hbox.PackStart(srv_addr_update_btn, false, true, 5)
|
srv_addr_hbox.PackStart(srv_addr_update_btn, false, true, 5)
|
||||||
if f.update {
|
if f.update {
|
||||||
f.server_address.SetSensitive(false)
|
f.server_address.SetSensitive(false)
|
||||||
}
|
}
|
||||||
|
table.Attach(srv_addr_hbox, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Server password.
|
// Server password.
|
||||||
srv_pass_hbox := gtk.NewHBox(false, 0)
|
|
||||||
f.vbox.PackStart(srv_pass_hbox, false, true, 5)
|
|
||||||
srv_pass_label := gtk.NewLabel("Password:")
|
srv_pass_label := gtk.NewLabel("Password:")
|
||||||
srv_pass_hbox.PackStart(srv_pass_label, false, true, 5)
|
srv_pass_label.SetAlignment(0, 0)
|
||||||
srv_pass_sep := gtk.NewHSeparator()
|
table.Attach(srv_pass_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
srv_pass_hbox.PackStart(srv_pass_sep, true, true, 5)
|
|
||||||
f.server_password = gtk.NewEntry()
|
f.server_password = gtk.NewEntry()
|
||||||
srv_pass_hbox.PackStart(f.server_password, true, true, 5)
|
table.Attach(f.server_password, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Profile to use.
|
// Profile to use.
|
||||||
profile_hbox := gtk.NewHBox(false, 0)
|
|
||||||
f.vbox.PackStart(profile_hbox, false, true, 5)
|
|
||||||
profile_label := gtk.NewLabel("Profile:")
|
profile_label := gtk.NewLabel("Profile:")
|
||||||
profile_hbox.PackStart(profile_label, false, true, 5)
|
profile_label.SetAlignment(0, 0)
|
||||||
profile_sep := gtk.NewHSeparator()
|
table.Attach(profile_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
profile_hbox.PackStart(profile_sep, true, true, 5)
|
|
||||||
f.profile = gtk.NewComboBoxText()
|
f.profile = gtk.NewComboBoxText()
|
||||||
profile_hbox.PackStart(f.profile, false, true, 5)
|
table.Attach(f.profile , 1, 2, 3, 4, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
|
// Invisible thing.
|
||||||
|
inv_label1 := gtk.NewLabel("")
|
||||||
|
table.Attach(inv_label1, 0, 1, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5)
|
||||||
|
inv_label2 := gtk.NewLabel("")
|
||||||
|
table.Attach(inv_label2, 1, 2, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Buttons hbox.
|
// Buttons hbox.
|
||||||
buttons_hbox := gtk.NewHBox(false, 0)
|
buttons_hbox := gtk.NewHBox(false, 0)
|
||||||
@@ -205,12 +210,16 @@ func (f *FavoriteDialog) saveFavorite() error {
|
|||||||
//ctx.Requester.Pooler.UpdateSpecificServer(f.server)
|
//ctx.Requester.Pooler.UpdateSpecificServer(f.server)
|
||||||
|
|
||||||
if len(f.server_address.GetText()) == 0 {
|
if len(f.server_address.GetText()) == 0 {
|
||||||
mbox_string := "Server address is empty.\n\nServers without address cannot be added."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Server address is empty.\n\nServers without address cannot be added."
|
||||||
})
|
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
m.Response(func() {
|
||||||
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
return errors.New("No server address specified")
|
return errors.New("No server address specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,12 +233,16 @@ func (f *FavoriteDialog) saveFavorite() error {
|
|||||||
f.server.Port = port
|
f.server.Port = port
|
||||||
|
|
||||||
if len(f.profile.GetActiveText()) == 0 {
|
if len(f.profile.GetActiveText()) == 0 {
|
||||||
mbox_string := "Profile wasn't selected.\n\nPlease, select valid profile for this server.\nIf you haven't add profiles yet - you can do it\nin options on \"Urban Terror\" tab."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Profile wasn't selected.\n\nPlease, select valid profile for this server.\nIf you haven't add profiles yet - you can do it\nin options on \"Urban Terror\" tab."
|
||||||
})
|
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
m.Response(func() {
|
||||||
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
return errors.New("No game profile specified")
|
return errors.New("No game profile specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
330
ui/mainwindow.go
330
ui/mainwindow.go
@@ -13,6 +13,7 @@ import (
|
|||||||
// stdlib
|
// stdlib
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -59,12 +60,26 @@ type MainWindow struct {
|
|||||||
profiles *gtk.ComboBoxText
|
profiles *gtk.ComboBoxText
|
||||||
// Checkbox for hiding/showing offline servers in 'Servers' tab list.
|
// Checkbox for hiding/showing offline servers in 'Servers' tab list.
|
||||||
all_servers_hide_offline *gtk.CheckButton
|
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.
|
// Checkbox for hiding/showing offline servers in 'Favorites' tab list.
|
||||||
fav_servers_hide_offline *gtk.CheckButton
|
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.
|
// Game launch button.
|
||||||
launch_button *gtk.Button
|
launch_button *gtk.Button
|
||||||
// Server's information.
|
// Server's main information.
|
||||||
server_info *gtk.TreeView
|
server_info *gtk.TreeView
|
||||||
|
// Players information.
|
||||||
|
players_info *gtk.TreeView
|
||||||
// Quick connect: server address
|
// Quick connect: server address
|
||||||
qc_server_address *gtk.Entry
|
qc_server_address *gtk.Entry
|
||||||
// Quick connect: password
|
// Quick connect: password
|
||||||
@@ -87,9 +102,12 @@ type MainWindow struct {
|
|||||||
fav_servers_store *gtk.ListStore
|
fav_servers_store *gtk.ListStore
|
||||||
// Server's information store.
|
// Server's information store.
|
||||||
server_info_store *gtk.ListStore
|
server_info_store *gtk.ListStore
|
||||||
|
// Players information store.
|
||||||
|
players_info_store *gtk.ListStore
|
||||||
|
|
||||||
// Dialogs.
|
// Dialogs.
|
||||||
options_dialog *OptionsDialog
|
options_dialog *OptionsDialog
|
||||||
|
server_cvars_dialog *ServerCVarsDialog
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
// Old profiles count.
|
// Old profiles count.
|
||||||
@@ -121,14 +139,20 @@ type MainWindow struct {
|
|||||||
// For online server.
|
// For online server.
|
||||||
server_online_pic *gdkpixbuf.Pixbuf
|
server_online_pic *gdkpixbuf.Pixbuf
|
||||||
// For private (passworded) server.
|
// For private (passworded) server.
|
||||||
server_passworded_pic *gdkpixbuf.Pixbuf
|
server_private_pic *gdkpixbuf.Pixbuf
|
||||||
// For public server
|
// For public server
|
||||||
server_public_pic *gdkpixbuf.Pixbuf
|
server_public_pic *gdkpixbuf.Pixbuf
|
||||||
|
|
||||||
|
|
||||||
// Flags.
|
// Flags.
|
||||||
|
// Application is initialized?
|
||||||
|
initialized bool
|
||||||
// Window is hidden?
|
// Window is hidden?
|
||||||
hidden bool
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainWindow) addToFavorites() {
|
func (m *MainWindow) addToFavorites() {
|
||||||
@@ -157,20 +181,36 @@ func (m *MainWindow) addToFavorites() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Executes when delimiter for two panes is moved, to calculate VALID
|
||||||
// position.
|
// position.
|
||||||
func (m *MainWindow) checkMainPanePosition() {
|
func (m *MainWindow) checkMainPanePosition() {
|
||||||
m.pane_negative_position = m.window_width - m.hpane.GetPosition()
|
glib.IdleAdd(func() bool {
|
||||||
|
m.pane_negative_position = m.window_width - m.hpane.GetPosition()
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes when main window is moved or resized.
|
// Executes when main window is moved or resized.
|
||||||
// Also calculating pane delimiter position and set it to avoid
|
// Also calculating pane delimiter position and set it to avoid
|
||||||
// widgets hell :).
|
// widgets hell :).
|
||||||
func (m *MainWindow) checkPositionAndSize() {
|
func (m *MainWindow) checkPositionAndSize() {
|
||||||
m.window.GetPosition(&m.window_pos_x, &m.window_pos_y)
|
glib.IdleAdd(func() bool {
|
||||||
m.window.GetSize(&m.window_width, &m.window_height)
|
m.window.GetPosition(&m.window_pos_x, &m.window_pos_y)
|
||||||
|
m.window.GetSize(&m.window_width, &m.window_height)
|
||||||
|
|
||||||
m.hpane.SetPosition(m.window_width - m.pane_negative_position)
|
m.hpane.SetPosition(m.window_width - m.pane_negative_position)
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes on URTrator shutdown.
|
// Executes on URTrator shutdown.
|
||||||
@@ -202,6 +242,13 @@ func (m *MainWindow) Close() {
|
|||||||
ctx.Close()
|
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.
|
// Deleting server from favorites.
|
||||||
func (m *MainWindow) deleteFromFavorites() {
|
func (m *MainWindow) deleteFromFavorites() {
|
||||||
fmt.Println("Removing server from favorites...")
|
fmt.Println("Removing server from favorites...")
|
||||||
@@ -221,12 +268,18 @@ func (m *MainWindow) deleteFromFavorites() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if not_favorited {
|
if not_favorited {
|
||||||
mbox_string := "Cannot delete server from favorites.\n\nServer isn't favorited."
|
// Temporary disable all these modals on Linux.
|
||||||
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
d.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
d.Destroy()
|
mbox_string := "Cannot delete server from favorites.\n\nServer isn't favorited."
|
||||||
})
|
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
|
||||||
d.Run()
|
d.Response(func() {
|
||||||
|
d.Destroy()
|
||||||
|
})
|
||||||
|
d.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Server isn't favorited</span></markup>"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
||||||
@@ -237,19 +290,23 @@ func (m *MainWindow) deleteFromFavorites() {
|
|||||||
func (m *MainWindow) dropDatabasesData() {
|
func (m *MainWindow) dropDatabasesData() {
|
||||||
fmt.Println("Dropping database data...")
|
fmt.Println("Dropping database data...")
|
||||||
var will_continue bool = false
|
var will_continue bool = false
|
||||||
mbox_string := "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?"
|
// Temporary disable all these modals on Linux.
|
||||||
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
d.Connect("response", func(resp *glib.CallbackContext) {
|
if runtime.GOOS != "linux" {
|
||||||
if resp.Args(0) == 4294967287 {
|
mbox_string := "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?"
|
||||||
will_continue = false
|
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string)
|
||||||
} else {
|
d.Connect("response", func(resp *glib.CallbackContext) {
|
||||||
will_continue = true
|
if resp.Args(0) == 4294967287 {
|
||||||
}
|
will_continue = false
|
||||||
})
|
} else {
|
||||||
d.Response(func() {
|
will_continue = true
|
||||||
d.Destroy()
|
}
|
||||||
})
|
d.Destroy()
|
||||||
d.Run()
|
})
|
||||||
|
d.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Remove ~/.config/urtrator/database.sqlite3 manually!</span></markup>"})
|
||||||
|
}
|
||||||
|
|
||||||
if will_continue {
|
if will_continue {
|
||||||
ctx.Database.Db.MustExec("DELETE FROM servers")
|
ctx.Database.Db.MustExec("DELETE FROM servers")
|
||||||
@@ -275,6 +332,16 @@ func (m *MainWindow) editFavorite() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Executes when "Hide offline servers" checkbox changed it's state on
|
||||||
// "Servers" tab.
|
// "Servers" tab.
|
||||||
func (m *MainWindow) hideOfflineAllServers() {
|
func (m *MainWindow) hideOfflineAllServers() {
|
||||||
@@ -287,6 +354,18 @@ func (m *MainWindow) hideOfflineAllServers() {
|
|||||||
ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{})
|
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
|
// Executes when "Hide offline servers" checkbox changed it's state on
|
||||||
// "Favorites" tab.
|
// "Favorites" tab.
|
||||||
func (m *MainWindow) hideOfflineFavoriteServers() {
|
func (m *MainWindow) hideOfflineFavoriteServers() {
|
||||||
@@ -299,9 +378,20 @@ func (m *MainWindow) hideOfflineFavoriteServers() {
|
|||||||
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
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) {
|
func (m *MainWindow) loadAllServers(data map[string]string) {
|
||||||
fmt.Println("Loading all servers...")
|
fmt.Println("Loading all servers...")
|
||||||
// ToDo: do it without clearing.
|
|
||||||
for _, server := range ctx.Cache.Servers {
|
for _, server := range ctx.Cache.Servers {
|
||||||
iter := new(gtk.TreeIter)
|
iter := new(gtk.TreeIter)
|
||||||
ping, _ := strconv.Atoi(server.Server.Ping)
|
ping, _ := strconv.Atoi(server.Server.Ping)
|
||||||
@@ -313,8 +403,39 @@ func (m *MainWindow) loadAllServers(data map[string]string) {
|
|||||||
iter = server.AllServersIter
|
iter = server.AllServersIter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide offline servers?
|
||||||
if m.all_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) {
|
if m.all_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) {
|
||||||
if server.AllServersIterInList {
|
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() != "All versions" && 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() != "All gamemodes" && gm_int_as_str != server.Server.Gamemode {
|
||||||
|
if server.AllServersIterInList && server.AllServersIterSet {
|
||||||
m.all_servers_store.Remove(iter)
|
m.all_servers_store.Remove(iter)
|
||||||
server.AllServersIterInList = false
|
server.AllServersIterInList = false
|
||||||
}
|
}
|
||||||
@@ -336,7 +457,7 @@ func (m *MainWindow) loadAllServers(data map[string]string) {
|
|||||||
m.all_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
|
m.all_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
|
||||||
}
|
}
|
||||||
if server.Server.IsPrivate == "1" {
|
if server.Server.IsPrivate == "1" {
|
||||||
m.all_servers_store.SetValue(iter, 1, m.server_passworded_pic.GPixbuf)
|
m.all_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf)
|
||||||
} else {
|
} else {
|
||||||
m.all_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
|
m.all_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
|
||||||
}
|
}
|
||||||
@@ -344,7 +465,7 @@ func (m *MainWindow) loadAllServers(data map[string]string) {
|
|||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Name"], server_name)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Name"], server_name)
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Mode"], m.getGameModeName(server.Server.Gamemode))
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Mode"], m.getGameModeName(server.Server.Gamemode))
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Map"], server.Server.Map)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Map"], server.Server.Map)
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Players"], server.Server.Players + "/" + server.Server.Maxplayers)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Players"], server.Server.Players + "/" + server.Server.Bots + "/" + server.Server.Maxplayers)
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Ping"], server.Server.Ping)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Ping"], server.Server.Ping)
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Version"], server.Server.Version)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["Version"], server.Server.Version)
|
||||||
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["IP"], server.Server.Ip + ":" + server.Server.Port)
|
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["IP"], server.Server.Ip + ":" + server.Server.Port)
|
||||||
@@ -365,6 +486,7 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
|
|||||||
iter = server.FavServersIter
|
iter = server.FavServersIter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide offline servers?
|
||||||
if m.fav_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) {
|
if m.fav_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) {
|
||||||
if server.FavServersIterInList {
|
if server.FavServersIterInList {
|
||||||
m.fav_servers_store.Remove(iter)
|
m.fav_servers_store.Remove(iter)
|
||||||
@@ -373,6 +495,36 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
|
|||||||
continue
|
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() != "All versions" && 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() != "All gamemodes" && 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
|
// If server on favorites widget, but not favorited (e.g. just
|
||||||
// removed from favorites) - remove it from list.
|
// removed from favorites) - remove it from list.
|
||||||
if server.Server.Favorite != "1" && server.FavServersIterSet && server.FavServersIterInList {
|
if server.Server.Favorite != "1" && server.FavServersIterSet && server.FavServersIterInList {
|
||||||
@@ -401,7 +553,7 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
|
|||||||
m.fav_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
|
m.fav_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
|
||||||
}
|
}
|
||||||
if server.Server.IsPrivate == "1" {
|
if server.Server.IsPrivate == "1" {
|
||||||
m.fav_servers_store.SetValue(iter, 1, m.server_passworded_pic.GPixbuf)
|
m.fav_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf)
|
||||||
} else {
|
} else {
|
||||||
m.fav_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
|
m.fav_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
|
||||||
}
|
}
|
||||||
@@ -409,7 +561,7 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
|
|||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Name"], server_name)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Name"], server_name)
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Mode"], m.getGameModeName(server.Server.Gamemode))
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Mode"], m.getGameModeName(server.Server.Gamemode))
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Map"], server.Server.Map)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Map"], server.Server.Map)
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Players"], server.Server.Players + "/" + server.Server.Maxplayers)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Players"], server.Server.Players + "/" + server.Server.Bots + "/" + server.Server.Maxplayers)
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Ping"], server.Server.Ping)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Ping"], server.Server.Ping)
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Version"], server.Server.Version)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["Version"], server.Server.Version)
|
||||||
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["IP"], server.Server.Ip + ":" + server.Server.Port)
|
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["IP"], server.Server.Ip + ":" + server.Server.Port)
|
||||||
@@ -431,10 +583,46 @@ func (m *MainWindow) loadProfiles(data map[string]string) {
|
|||||||
|
|
||||||
m.old_profiles_count = len(ctx.Cache.Profiles)
|
m.old_profiles_count = len(ctx.Cache.Profiles)
|
||||||
fmt.Println("Added " + strconv.Itoa(m.old_profiles_count) + " 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, "Servers") {
|
||||||
|
m.fav_servers.Emit("cursor-changed")
|
||||||
|
} else if strings.Contains(current_tab, "Favorites") {
|
||||||
|
m.all_servers.Emit("cursor-changed")
|
||||||
|
}
|
||||||
|
m.use_other_servers_tab = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainWindow) serversUpdateCompleted(data map[string]string) {
|
func (m *MainWindow) serversUpdateCompleted(data map[string]string) {
|
||||||
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "Servers updated."})
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "Servers updated."})
|
||||||
|
// 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, "Servers") {
|
||||||
|
m.all_servers.Emit("cursor-changed")
|
||||||
|
} else if strings.Contains(current_tab, "Favorites") {
|
||||||
|
m.fav_servers.Emit("cursor-changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
func (m *MainWindow) setToolbarLabelText(data map[string]string) {
|
||||||
@@ -459,14 +647,33 @@ func (m *MainWindow) showHide() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainWindow) showServerInformation() {
|
func (m *MainWindow) showServerCVars() {
|
||||||
fmt.Println("Showing server's information...")
|
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, "Servers") {
|
||||||
|
current_tab = "Favorites"
|
||||||
|
} else if strings.Contains(current_tab, "Favorites") {
|
||||||
|
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() {
|
func (m *MainWindow) showShortServerInformation() {
|
||||||
fmt.Println("Server selection changed, updating server's information widget...")
|
fmt.Println("Server selection changed, updating server's information widget...")
|
||||||
m.server_info_store.Clear()
|
m.server_info_store.Clear()
|
||||||
|
m.players_info_store.Clear()
|
||||||
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
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, "Servers") {
|
||||||
|
current_tab = "Favorites"
|
||||||
|
} else if strings.Contains(current_tab, "Favorites") {
|
||||||
|
current_tab = "Servers"
|
||||||
|
}
|
||||||
|
}
|
||||||
srv_address := m.getIpFromServersList(current_tab)
|
srv_address := m.getIpFromServersList(current_tab)
|
||||||
|
|
||||||
// Getting server information from cache.
|
// Getting server information from cache.
|
||||||
@@ -477,12 +684,8 @@ func (m *MainWindow) showShortServerInformation() {
|
|||||||
// Append to treeview generic info first. After appending it
|
// Append to treeview generic info first. After appending it
|
||||||
// will be deleted from map.
|
// will be deleted from map.
|
||||||
|
|
||||||
iter := new(gtk.TreeIter)
|
|
||||||
m.server_info_store.Append(iter)
|
|
||||||
m.server_info_store.SetValue(iter, 0, "<markup><span font_weight=\"bold\">GENERAL INFO</span></markup>")
|
|
||||||
|
|
||||||
// Server's name.
|
// Server's name.
|
||||||
iter = new(gtk.TreeIter)
|
iter := new(gtk.TreeIter)
|
||||||
m.server_info_store.Append(iter)
|
m.server_info_store.Append(iter)
|
||||||
m.server_info_store.SetValue(iter, 0, "Server's name")
|
m.server_info_store.SetValue(iter, 0, "Server's name")
|
||||||
m.server_info_store.SetValue(iter, 1, ctx.Colorizer.Fix(parsed_general_data["sv_hostname"]))
|
m.server_info_store.SetValue(iter, 1, ctx.Colorizer.Fix(parsed_general_data["sv_hostname"]))
|
||||||
@@ -499,7 +702,7 @@ func (m *MainWindow) showShortServerInformation() {
|
|||||||
iter = new(gtk.TreeIter)
|
iter = new(gtk.TreeIter)
|
||||||
m.server_info_store.Append(iter)
|
m.server_info_store.Append(iter)
|
||||||
m.server_info_store.SetValue(iter, 0, "Players")
|
m.server_info_store.SetValue(iter, 0, "Players")
|
||||||
m.server_info_store.SetValue(iter, 1, server_info.Players + " of " + parsed_general_data["sv_maxclients"])
|
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")
|
delete(parsed_general_data, "sv_maxclients")
|
||||||
|
|
||||||
// Ping
|
// Ping
|
||||||
@@ -530,23 +733,26 @@ func (m *MainWindow) showShortServerInformation() {
|
|||||||
}
|
}
|
||||||
m.server_info_store.SetValue(iter, 1, passworded_status)
|
m.server_info_store.SetValue(iter, 1, passworded_status)
|
||||||
|
|
||||||
// Just a separator.
|
// Sorting keys of map.
|
||||||
iter = new(gtk.TreeIter)
|
players_map_keys := make([]string, 0, len(parsed_players_info))
|
||||||
m.server_info_store.Append(iter)
|
for k := range parsed_players_info {
|
||||||
|
// ToDo: figure out how to do this properly without
|
||||||
// Players information
|
// append().
|
||||||
iter = new(gtk.TreeIter)
|
players_map_keys = append(players_map_keys, k)
|
||||||
m.server_info_store.Append(iter)
|
|
||||||
m.server_info_store.SetValue(iter, 0, "<markup><span font_weight=\"bold\">PLAYERS</span></markup>")
|
|
||||||
|
|
||||||
for _, value := range parsed_players_info {
|
|
||||||
iter = new(gtk.TreeIter)
|
|
||||||
nick := ctx.Colorizer.Fix(value["nick"])
|
|
||||||
m.server_info_store.Append(iter)
|
|
||||||
m.server_info_store.SetValue(iter, 0, nick)
|
|
||||||
m.server_info_store.SetValue(iter, 1, "(frags: " + value["frags"] + " | ping: " + value["ping"] + ")")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
// Just a separator.
|
||||||
iter = new(gtk.TreeIter)
|
iter = new(gtk.TreeIter)
|
||||||
m.server_info_store.Append(iter)
|
m.server_info_store.Append(iter)
|
||||||
@@ -556,12 +762,21 @@ func (m *MainWindow) showShortServerInformation() {
|
|||||||
m.server_info_store.Append(iter)
|
m.server_info_store.Append(iter)
|
||||||
m.server_info_store.SetValue(iter, 0, "<markup><span font_weight=\"bold\">OTHER PARAMETERS</span></markup>")
|
m.server_info_store.SetValue(iter, 0, "<markup><span font_weight=\"bold\">OTHER PARAMETERS</span></markup>")
|
||||||
|
|
||||||
for key, value := range parsed_general_data {
|
// 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)
|
iter = new(gtk.TreeIter)
|
||||||
m.server_info_store.Append(iter)
|
m.server_info_store.Append(iter)
|
||||||
m.server_info_store.SetValue(iter, 0, key)
|
m.server_info_store.SetValue(iter, 0, general_data_keys[k])
|
||||||
m.server_info_store.SetValue(iter, 1, value)
|
m.server_info_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]])
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,6 +792,7 @@ func (m *MainWindow) unlockInterface() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainWindow) updateOneServer() {
|
func (m *MainWindow) updateOneServer() {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Updating selected server...</span></markup>"})
|
||||||
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
||||||
srv_address := m.getIpFromServersList(current_tab)
|
srv_address := m.getIpFromServersList(current_tab)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
// local
|
// local
|
||||||
@@ -18,9 +19,11 @@ import (
|
|||||||
|
|
||||||
// Main window initialization.
|
// Main window initialization.
|
||||||
func (m *MainWindow) Initialize() {
|
func (m *MainWindow) Initialize() {
|
||||||
|
|
||||||
gtk.Init(nil)
|
gtk.Init(nil)
|
||||||
|
|
||||||
m.initializeStorages()
|
m.initializeStorages()
|
||||||
|
ctx.InitializeClipboardWatcher()
|
||||||
|
|
||||||
m.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
|
m.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
|
||||||
m.window.SetTitle("URTrator")
|
m.window.SetTitle("URTrator")
|
||||||
@@ -82,6 +85,7 @@ func (m *MainWindow) Initialize() {
|
|||||||
|
|
||||||
// Dialogs initialization.
|
// Dialogs initialization.
|
||||||
m.options_dialog = &OptionsDialog{}
|
m.options_dialog = &OptionsDialog{}
|
||||||
|
m.server_cvars_dialog = &ServerCVarsDialog{}
|
||||||
|
|
||||||
// Main menu.
|
// Main menu.
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
@@ -128,7 +132,7 @@ func (m *MainWindow) Initialize() {
|
|||||||
m.vbox.PackStart(profile_and_launch_hbox, false, true, 5)
|
m.vbox.PackStart(profile_and_launch_hbox, false, true, 5)
|
||||||
|
|
||||||
// Separator
|
// Separator
|
||||||
sep := gtk.NewHSeparator()
|
sep := gtk.NewHBox(false, 0)
|
||||||
profile_and_launch_hbox.PackStart(sep, true, true, 5)
|
profile_and_launch_hbox.PackStart(sep, true, true, 5)
|
||||||
|
|
||||||
// Profile selection.
|
// Profile selection.
|
||||||
@@ -147,12 +151,16 @@ func (m *MainWindow) Initialize() {
|
|||||||
m.launch_button = gtk.NewButtonWithLabel("Launch!")
|
m.launch_button = gtk.NewButtonWithLabel("Launch!")
|
||||||
m.launch_button.SetTooltipText("Launch Urban Terror")
|
m.launch_button.SetTooltipText("Launch Urban Terror")
|
||||||
m.launch_button.Clicked(m.launchGame)
|
m.launch_button.Clicked(m.launchGame)
|
||||||
launch_button_image := gtk.NewImageFromStock(gtk.STOCK_APPLY, 24)
|
launch_button_image := gtk.NewImageFromPixbuf(logo.ScaleSimple(24, 24, gdkpixbuf.INTERP_HYPER))
|
||||||
m.launch_button.SetImage(launch_button_image)
|
m.launch_button.SetImage(launch_button_image)
|
||||||
profile_and_launch_hbox.PackStart(m.launch_button, false, true, 5)
|
profile_and_launch_hbox.PackStart(m.launch_button, false, true, 5)
|
||||||
|
|
||||||
m.window.Add(m.vbox)
|
m.window.Add(m.vbox)
|
||||||
|
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
m.initializeMacAfter()
|
||||||
|
}
|
||||||
|
|
||||||
m.window.ShowAll()
|
m.window.ShowAll()
|
||||||
|
|
||||||
// Launch events.
|
// Launch events.
|
||||||
@@ -163,6 +171,9 @@ func (m *MainWindow) Initialize() {
|
|||||||
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
|
||||||
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "URTrator is ready."})
|
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()
|
gtk.Main()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +184,7 @@ func (m *MainWindow) initializeEvents() {
|
|||||||
ctx.Eventer.AddEventHandler("loadFavoriteServers", m.loadFavoriteServers)
|
ctx.Eventer.AddEventHandler("loadFavoriteServers", m.loadFavoriteServers)
|
||||||
ctx.Eventer.AddEventHandler("loadProfilesIntoMainWindow", m.loadProfiles)
|
ctx.Eventer.AddEventHandler("loadProfilesIntoMainWindow", m.loadProfiles)
|
||||||
ctx.Eventer.AddEventHandler("serversUpdateCompleted", m.serversUpdateCompleted)
|
ctx.Eventer.AddEventHandler("serversUpdateCompleted", m.serversUpdateCompleted)
|
||||||
|
ctx.Eventer.AddEventHandler("setQuickConnectDetails", m.setQuickConnectDetails)
|
||||||
ctx.Eventer.AddEventHandler("setToolbarLabelText", m.setToolbarLabelText)
|
ctx.Eventer.AddEventHandler("setToolbarLabelText", m.setToolbarLabelText)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +245,7 @@ func (m *MainWindow) initializeSidebar() {
|
|||||||
|
|
||||||
// Scrolled thing.
|
// Scrolled thing.
|
||||||
si_scroll := gtk.NewScrolledWindow(nil, nil)
|
si_scroll := gtk.NewScrolledWindow(nil, nil)
|
||||||
|
si_scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||||
si_vbox.PackStart(si_scroll, true, true, 5)
|
si_vbox.PackStart(si_scroll, true, true, 5)
|
||||||
|
|
||||||
// Server's information.
|
// Server's information.
|
||||||
@@ -247,10 +260,32 @@ func (m *MainWindow) initializeSidebar() {
|
|||||||
|
|
||||||
si_scroll.Add(m.server_info)
|
si_scroll.Add(m.server_info)
|
||||||
|
|
||||||
// Button to view additional server info.
|
// Players information.
|
||||||
additional_srv_info_button := gtk.NewButtonWithLabel("Additional information")
|
players_info_frame := gtk.NewFrame("Players")
|
||||||
additional_srv_info_button.Clicked(m.showServerInformation)
|
sidebar_vbox.PackStart(players_info_frame, true, true, 5)
|
||||||
si_vbox.PackStart(additional_srv_info_button, false, 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.
|
||||||
quick_connect_frame := gtk.NewFrame("Quick connect")
|
quick_connect_frame := gtk.NewFrame("Quick connect")
|
||||||
@@ -293,6 +328,9 @@ func (m *MainWindow) initializeSidebar() {
|
|||||||
|
|
||||||
// Initializes internal storages.
|
// Initializes internal storages.
|
||||||
func (m *MainWindow) initializeStorages() {
|
func (m *MainWindow) initializeStorages() {
|
||||||
|
// Application isn't initialized.
|
||||||
|
m.initialized = false
|
||||||
|
m.use_other_servers_tab = false
|
||||||
// Gamemodes.
|
// Gamemodes.
|
||||||
m.gamemodes = make(map[string]string)
|
m.gamemodes = make(map[string]string)
|
||||||
m.gamemodes = map[string]string{
|
m.gamemodes = map[string]string{
|
||||||
@@ -343,6 +381,10 @@ func (m *MainWindow) initializeStorages() {
|
|||||||
// Server's information store. Used for quick preview in main window.
|
// 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)
|
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.
|
// Profiles count after filling combobox. Defaulting to 0.
|
||||||
m.old_profiles_count = 0
|
m.old_profiles_count = 0
|
||||||
|
|
||||||
@@ -351,19 +393,37 @@ func (m *MainWindow) initializeStorages() {
|
|||||||
|
|
||||||
// Pixbufs.
|
// Pixbufs.
|
||||||
// Offline server.
|
// Offline server.
|
||||||
m.server_offline_pic = gtk.NewImage().RenderIcon(gtk.STOCK_NO, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
|
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.
|
// Online server.
|
||||||
m.server_online_pic = gtk.NewImage().RenderIcon(gtk.STOCK_OK, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
|
srv_online_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_ONLINE)
|
||||||
// Passworded server.
|
srv_online_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
||||||
m.server_passworded_pic = gtk.NewImage().RenderIcon(gtk.STOCK_CLOSE, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
|
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.
|
// Public server.
|
||||||
m.server_public_pic = gtk.NewImage().RenderIcon(gtk.STOCK_OK, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
|
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.
|
// Tabs widget initialization, including all child widgets.
|
||||||
func (m *MainWindow) InitializeTabs() {
|
func (m *MainWindow) InitializeTabs() {
|
||||||
// Create tabs widget.
|
// Create tabs widget.
|
||||||
m.tab_widget = gtk.NewNotebook()
|
m.tab_widget = gtk.NewNotebook()
|
||||||
|
m.tab_widget.Connect("switch-page", m.tabChanged)
|
||||||
|
|
||||||
tab_allsrv_hbox := gtk.NewHBox(false, 0)
|
tab_allsrv_hbox := gtk.NewHBox(false, 0)
|
||||||
swin1 := gtk.NewScrolledWindow(nil, nil)
|
swin1 := gtk.NewScrolledWindow(nil, nil)
|
||||||
@@ -419,9 +479,15 @@ func (m *MainWindow) InitializeTabs() {
|
|||||||
|
|
||||||
// Sorting.
|
// Sorting.
|
||||||
// By default we are sorting by server name.
|
// By default we are sorting by server name.
|
||||||
// ToDo: remembering it to configuration storage.
|
|
||||||
m.all_servers_store_sortable.SetSortColumnId(m.column_pos["Servers"]["Name"], gtk.SORT_ASCENDING)
|
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.
|
// Selection changed signal, which will update server's short info pane.
|
||||||
m.all_servers.Connect("cursor-changed", m.showShortServerInformation)
|
m.all_servers.Connect("cursor-changed", m.showShortServerInformation)
|
||||||
|
|
||||||
@@ -434,12 +500,75 @@ func (m *MainWindow) InitializeTabs() {
|
|||||||
m.all_servers_hide_offline.SetTooltipText("Hide offline servers on Servers tab")
|
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)
|
tab_all_srv_ctl_vbox.PackStart(m.all_servers_hide_offline, false, true, 5)
|
||||||
m.all_servers_hide_offline.Clicked(m.hideOfflineAllServers)
|
m.all_servers_hide_offline.Clicked(m.hideOfflineAllServers)
|
||||||
if ctx.Cfg.Cfg["/serverslist/all_servers/hide_offline"] == "1" {
|
// 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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtering by version.
|
||||||
|
m.all_servers_version = gtk.NewComboBoxText()
|
||||||
|
m.all_servers_version.SetTooltipText("Show only servers which uses selected version of Urban Terror")
|
||||||
|
m.all_servers_version.AppendText("All versions")
|
||||||
|
for i := range common.SUPPORTED_URT_VERSIONS {
|
||||||
|
m.all_servers_version.AppendText(common.SUPPORTED_URT_VERSIONS[i])
|
||||||
|
}
|
||||||
|
all_servers_version_val, ok := ctx.Cfg.Cfg["/serverslist/all_servers/version"]
|
||||||
|
if ok {
|
||||||
|
all_servers_version_int, _ := strconv.Atoi(all_servers_version_val)
|
||||||
|
m.all_servers_version.SetActive(all_servers_version_int)
|
||||||
|
} else {
|
||||||
|
m.all_servers_version.SetActive(0)
|
||||||
|
}
|
||||||
|
m.all_servers_version.Connect("changed", m.allServersVersionFilterChanged)
|
||||||
|
tab_all_srv_ctl_vbox.PackStart(m.all_servers_version, false, true, 5)
|
||||||
|
|
||||||
|
// Filtering by gamemode
|
||||||
|
m.all_servers_gamemode = gtk.NewComboBoxText()
|
||||||
|
m.all_servers_gamemode.SetTooltipText("Show only servers which uses selected game mode")
|
||||||
|
m.all_servers_gamemode.AppendText("All gamemodes")
|
||||||
|
// Get sorted gamemodes keys.
|
||||||
|
gm_keys := make([]int, 0, len(m.gamemodes))
|
||||||
|
for i := range m.gamemodes {
|
||||||
|
key, _ := strconv.Atoi(i)
|
||||||
|
gm_keys = append(gm_keys, key)
|
||||||
|
}
|
||||||
|
sort.Ints(gm_keys)
|
||||||
|
for i := range gm_keys {
|
||||||
|
m.all_servers_gamemode.AppendText(m.gamemodes[strconv.Itoa(gm_keys[i])])
|
||||||
|
}
|
||||||
|
all_servers_gamemode_val, ok := ctx.Cfg.Cfg["/serverslist/all_servers/gamemode"]
|
||||||
|
if ok {
|
||||||
|
all_servers_gamemode_int, _ := strconv.Atoi(all_servers_gamemode_val)
|
||||||
|
m.all_servers_gamemode.SetActive(all_servers_gamemode_int)
|
||||||
|
} else {
|
||||||
|
m.all_servers_gamemode.SetActive(0)
|
||||||
|
}
|
||||||
|
m.all_servers_gamemode.Connect("changed", m.allServersGamemodeFilterChanged)
|
||||||
|
tab_all_srv_ctl_vbox.PackStart(m.all_servers_gamemode, false, true, 5)
|
||||||
|
|
||||||
// Final separator.
|
// Final separator.
|
||||||
ctl_sep := gtk.NewVSeparator()
|
ctl_sep := gtk.NewVBox(false, 0)
|
||||||
tab_all_srv_ctl_vbox.PackStart(ctl_sep, true, true, 5)
|
tab_all_srv_ctl_vbox.PackStart(ctl_sep, true, true, 5)
|
||||||
|
|
||||||
// Favorites servers
|
// Favorites servers
|
||||||
@@ -473,7 +602,11 @@ func (m *MainWindow) InitializeTabs() {
|
|||||||
width_int, _ := strconv.Atoi(width)
|
width_int, _ := strconv.Atoi(width)
|
||||||
|
|
||||||
col := gtk.NewTreeViewColumnWithAttributes(name, gtk.NewCellRendererText(), "markup", position_int)
|
col := gtk.NewTreeViewColumnWithAttributes(name, gtk.NewCellRendererText(), "markup", position_int)
|
||||||
col.SetSortColumnId(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.SetReorderable(true)
|
||||||
col.SetResizable(true)
|
col.SetResizable(true)
|
||||||
// GtkTreeViewColumn.SetFixedWidth() accepts only positive integers.
|
// GtkTreeViewColumn.SetFixedWidth() accepts only positive integers.
|
||||||
@@ -504,12 +637,69 @@ func (m *MainWindow) InitializeTabs() {
|
|||||||
m.fav_servers_hide_offline.SetTooltipText("Hide offline servers on Favorites tab")
|
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)
|
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_hide_offline, false, true, 5)
|
||||||
m.fav_servers_hide_offline.Clicked(m.hideOfflineFavoriteServers)
|
m.fav_servers_hide_offline.Clicked(m.hideOfflineFavoriteServers)
|
||||||
if ctx.Cfg.Cfg["/serverslist/favorite/hide_offline"] == "1" {
|
// 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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.fav_servers_version = gtk.NewComboBoxText()
|
||||||
|
m.fav_servers_version.SetTooltipText("Show only servers which uses selected version of Urban Terror")
|
||||||
|
m.fav_servers_version.AppendText("All versions")
|
||||||
|
for i := range common.SUPPORTED_URT_VERSIONS {
|
||||||
|
m.fav_servers_version.AppendText(common.SUPPORTED_URT_VERSIONS[i])
|
||||||
|
}
|
||||||
|
fav_servers_version_val, ok := ctx.Cfg.Cfg["/serverslist/favorite/version"]
|
||||||
|
if ok {
|
||||||
|
fav_servers_version_int, _ := strconv.Atoi(fav_servers_version_val)
|
||||||
|
m.fav_servers_version.SetActive(fav_servers_version_int)
|
||||||
|
} else {
|
||||||
|
m.fav_servers_version.SetActive(0)
|
||||||
|
}
|
||||||
|
m.fav_servers_version.Connect("changed", m.favServersVersionFilterChanged)
|
||||||
|
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_version, false, true, 5)
|
||||||
|
|
||||||
|
// Filtering by gamemode
|
||||||
|
m.fav_servers_gamemode = gtk.NewComboBoxText()
|
||||||
|
m.fav_servers_gamemode.SetTooltipText("Show only servers which uses selected game mode")
|
||||||
|
m.fav_servers_gamemode.AppendText("All gamemodes")
|
||||||
|
// Gamemode keys already sorted while adding same filter to "Servers"
|
||||||
|
// tab, so just re-use them.
|
||||||
|
for i := range gm_keys {
|
||||||
|
m.fav_servers_gamemode.AppendText(m.gamemodes[strconv.Itoa(gm_keys[i])])
|
||||||
|
}
|
||||||
|
fav_servers_gamemode_val, ok := ctx.Cfg.Cfg["/serverslist/favorite/gamemode"]
|
||||||
|
if ok {
|
||||||
|
fav_servers_gamemode_int, _ := strconv.Atoi(fav_servers_gamemode_val)
|
||||||
|
m.fav_servers_gamemode.SetActive(fav_servers_gamemode_int)
|
||||||
|
} else {
|
||||||
|
m.fav_servers_gamemode.SetActive(0)
|
||||||
|
}
|
||||||
|
m.fav_servers_gamemode.Connect("changed", m.favServersGamemodeFilterChanged)
|
||||||
|
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_gamemode, false, true, 5)
|
||||||
|
|
||||||
// Final separator.
|
// Final separator.
|
||||||
ctl_fav_sep := gtk.NewVSeparator()
|
ctl_fav_sep := gtk.NewVBox(false, 0)
|
||||||
tab_fav_srv_ctl_vbox.PackStart(ctl_fav_sep, true, true, 5)
|
tab_fav_srv_ctl_vbox.PackStart(ctl_fav_sep, true, true, 5)
|
||||||
|
|
||||||
// Add tab_widget widget to window.
|
// Add tab_widget widget to window.
|
||||||
@@ -522,14 +712,22 @@ func (m *MainWindow) InitializeToolbar() {
|
|||||||
m.vbox.PackStart(m.toolbar, false, false, 5)
|
m.vbox.PackStart(m.toolbar, false, false, 5)
|
||||||
|
|
||||||
// Update servers button.
|
// Update servers button.
|
||||||
button_update_all_servers := gtk.NewToolButtonFromStock(gtk.STOCK_REFRESH)
|
button_update_all_servers_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ALL_SERVERS)
|
||||||
button_update_all_servers.SetLabel("Update all servers")
|
button_update_all_servers_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
|
||||||
button_update_all_servers.SetTooltipText("Update all servers in all tabs")
|
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)
|
button_update_all_servers.OnClicked(m.UpdateServers)
|
||||||
m.toolbar.Insert(button_update_all_servers, 0)
|
m.toolbar.Insert(button_update_all_servers, 0)
|
||||||
|
|
||||||
button_update_one_server := gtk.NewToolButtonFromStock(gtk.STOCK_REDO)
|
button_update_one_server_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ONE_SERVER)
|
||||||
button_update_one_server.SetLabel("Update selected 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.SetTooltipText("Update only selected server")
|
||||||
button_update_one_server.OnClicked(m.updateOneServer)
|
button_update_one_server.OnClicked(m.updateOneServer)
|
||||||
m.toolbar.Insert(button_update_one_server, 1)
|
m.toolbar.Insert(button_update_one_server, 1)
|
||||||
@@ -539,34 +737,57 @@ func (m *MainWindow) InitializeToolbar() {
|
|||||||
m.toolbar.Insert(separator, 2)
|
m.toolbar.Insert(separator, 2)
|
||||||
|
|
||||||
// Add server to favorites button.
|
// Add server to favorites button.
|
||||||
fav_button := gtk.NewToolButtonFromStock(gtk.STOCK_ADD)
|
fav_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.ADD_TO_FAVORITES)
|
||||||
fav_button.SetLabel("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.SetTooltipText("Add selected server to favorites")
|
||||||
fav_button.OnClicked(m.addToFavorites)
|
fav_button.OnClicked(m.addToFavorites)
|
||||||
m.toolbar.Insert(fav_button, 3)
|
m.toolbar.Insert(fav_button, 3)
|
||||||
|
|
||||||
fav_edit_button := gtk.NewToolButtonFromStock(gtk.STOCK_EDIT)
|
fav_edit_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.EDIT_FAVORITE)
|
||||||
fav_edit_button.SetLabel("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.SetTooltipText("Edit selected favorite server")
|
||||||
fav_edit_button.OnClicked(m.editFavorite)
|
fav_edit_button.OnClicked(m.editFavorite)
|
||||||
m.toolbar.Insert(fav_edit_button, 4)
|
m.toolbar.Insert(fav_edit_button, 4)
|
||||||
|
|
||||||
// Remove server from favorites button.
|
// Remove server from favorites button.
|
||||||
fav_delete_button := gtk.NewToolButtonFromStock(gtk.STOCK_REMOVE)
|
fav_delete_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REMOVE_FAVORITE)
|
||||||
fav_delete_button.SetLabel("Remove from favorites")
|
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.SetTooltipText("Remove selected server from favorites")
|
||||||
fav_delete_button.OnClicked(m.deleteFromFavorites)
|
fav_delete_button.OnClicked(m.deleteFromFavorites)
|
||||||
m.toolbar.Insert(fav_delete_button, 5)
|
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.
|
// Separator for toolbar's label and buttons.
|
||||||
toolbar_separator_toolitem := gtk.NewToolItem()
|
toolbar_separator_toolitem := gtk.NewToolItem()
|
||||||
toolbar_separator_toolitem.SetExpand(true)
|
toolbar_separator_toolitem.SetExpand(true)
|
||||||
m.toolbar.Insert(toolbar_separator_toolitem, 6)
|
m.toolbar.Insert(toolbar_separator_toolitem, 7)
|
||||||
// Toolbar's label.
|
// Toolbar's label.
|
||||||
m.toolbar_label = gtk.NewLabel("URTrator is ready")
|
m.toolbar_label = gtk.NewLabel("URTrator is ready")
|
||||||
toolbar_label_toolitem := gtk.NewToolItem()
|
toolbar_label_toolitem := gtk.NewToolItem()
|
||||||
toolbar_label_toolitem.Add(m.toolbar_label)
|
toolbar_label_toolitem.Add(m.toolbar_label)
|
||||||
m.toolbar.Insert(toolbar_label_toolitem, 7)
|
m.toolbar.Insert(toolbar_label_toolitem, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tray icon initialization.
|
// Tray icon initialization.
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ func (m *MainWindow) initializeMac() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MainWindow) initializeMacAfter() {
|
||||||
|
m.toolbar.SetStyle(gtk.TOOLBAR_ICONS)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MainWindow) initializeMacMenu() {
|
func (m *MainWindow) initializeMacMenu() {
|
||||||
// This is a placeholder, in future we will use native mac menu.
|
// This is a placeholder, in future we will use native mac menu.
|
||||||
// For now it launches default menu initialization.
|
// For now it launches default menu initialization.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
// stdlib
|
// stdlib
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
@@ -51,25 +52,46 @@ func (m *MainWindow) launchAsUsual() error {
|
|||||||
model.GetValue(iter, m.column_pos["Favorites"]["IP"], srv_address_gval)
|
model.GetValue(iter, m.column_pos["Favorites"]["IP"], srv_address_gval)
|
||||||
}
|
}
|
||||||
srv_address = srv_address_gval.GetString()
|
srv_address = srv_address_gval.GetString()
|
||||||
|
if len(srv_address) == 0 {
|
||||||
|
// Temporary disable all these modals on Linux.
|
||||||
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
mbox_string := "No server selected.\n\nPlease, select a server to continue connecting."
|
||||||
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
|
messagebox.Response(func() {
|
||||||
|
messagebox.Destroy()
|
||||||
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Select a server we will connect to!</span></markup>"})
|
||||||
|
}
|
||||||
|
return errors.New("No server selected.")
|
||||||
|
}
|
||||||
server_profile := ctx.Cache.Servers[srv_address].Server
|
server_profile := ctx.Cache.Servers[srv_address].Server
|
||||||
|
|
||||||
// Check for proper server name. If length == 0: server is offline,
|
// Check for proper server name. If length == 0: server is offline,
|
||||||
// we should show notification to user.
|
// we should show notification to user.
|
||||||
if len(server_profile.Name) == 0 {
|
if len(server_profile.Name) == 0 {
|
||||||
var will_continue bool = false
|
var will_continue bool = false
|
||||||
mbox_string := "Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Connect("response", func(resp *glib.CallbackContext) {
|
if runtime.GOOS != "linux" {
|
||||||
if resp.Args(0) == 4294967287 {
|
mbox_string := "Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server."
|
||||||
will_continue = false
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
|
||||||
} else {
|
messagebox.Connect("response", func(resp *glib.CallbackContext) {
|
||||||
will_continue = true
|
if resp.Args(0) == 4294967287 {
|
||||||
}
|
will_continue = false
|
||||||
})
|
} else {
|
||||||
m.Response(func() {
|
will_continue = true
|
||||||
m.Destroy()
|
}
|
||||||
})
|
messagebox.Destroy()
|
||||||
m.Run()
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
// We're okay to connect to empty server, temporary.
|
||||||
|
will_continue = true
|
||||||
|
}
|
||||||
|
|
||||||
if !will_continue {
|
if !will_continue {
|
||||||
return errors.New("User declined to connect to offline server")
|
return errors.New("User declined to connect to offline server")
|
||||||
}
|
}
|
||||||
@@ -83,19 +105,41 @@ func (m *MainWindow) launchAsUsual() error {
|
|||||||
// This check only relevant to "Servers" tab, favorite servers
|
// This check only relevant to "Servers" tab, favorite servers
|
||||||
// have profiles defined (see next).
|
// have profiles defined (see next).
|
||||||
if len(profile_name) == 0 {
|
if len(profile_name) == 0 {
|
||||||
mbox_string := "Invalid game profile selected.\n\nPlease, select profile and retry."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Invalid game profile selected.\n\nPlease, select profile and retry."
|
||||||
})
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
messagebox.Response(func() {
|
||||||
|
messagebox.Destroy()
|
||||||
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Invalid game profile selected.</span></markup>"})
|
||||||
|
}
|
||||||
return errors.New("User didn't select valid profile.")
|
return errors.New("User didn't select valid profile.")
|
||||||
}
|
}
|
||||||
user_profile = ctx.Cache.Profiles[profile_name].Profile
|
user_profile = ctx.Cache.Profiles[profile_name].Profile
|
||||||
} else if strings.Contains(current_tab, "Favorites") {
|
} else if strings.Contains(current_tab, "Favorites") {
|
||||||
// For favorite servers profile specified in favorite server
|
// For favorite servers profile specified in favorite server
|
||||||
// information have higher priority, so we just override it :)
|
// information have higher priority, so we just override it :)
|
||||||
user_profile = ctx.Cache.Profiles[server_profile.ProfileToUse].Profile
|
user_profile_cached, ok := ctx.Cache.Profiles[server_profile.ProfileToUse]
|
||||||
|
if !ok {
|
||||||
|
// Temporary disable all these modals on Linux.
|
||||||
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
mbox_string := "Invalid game profile specified for favorite server.\n\nPlease, edit your favorite server, select valid profile and retry."
|
||||||
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
|
messagebox.Response(func() {
|
||||||
|
messagebox.Destroy()
|
||||||
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Invalid game profile specified in favorite entry.</span></markup>"})
|
||||||
|
}
|
||||||
|
return errors.New("User didn't select valid profile.")
|
||||||
|
}
|
||||||
|
user_profile = user_profile_cached.Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
m.launchActually(server_profile, user_profile, "", "")
|
m.launchActually(server_profile, user_profile, "", "")
|
||||||
@@ -144,19 +188,25 @@ func (m *MainWindow) launchWithQuickConnect() error {
|
|||||||
func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, nickname_to_use string) error {
|
func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, nickname_to_use string) error {
|
||||||
if server_profile.Name == "" {
|
if server_profile.Name == "" {
|
||||||
var will_continue bool = false
|
var will_continue bool = false
|
||||||
mbox_string := "Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Connect("response", func(resp *glib.CallbackContext) {
|
if runtime.GOOS != "linux" {
|
||||||
if resp.Args(0) == 4294967287 {
|
mbox_string := "Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server."
|
||||||
will_continue = false
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
|
||||||
} else {
|
messagebox.Connect("response", func(resp *glib.CallbackContext) {
|
||||||
will_continue = true
|
if resp.Args(0) == 4294967287 {
|
||||||
}
|
will_continue = false
|
||||||
})
|
} else {
|
||||||
m.Response(func() {
|
will_continue = true
|
||||||
m.Destroy()
|
}
|
||||||
})
|
messagebox.Destroy()
|
||||||
m.Run()
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
// We're ok here, temporary.
|
||||||
|
will_continue = true
|
||||||
|
}
|
||||||
|
|
||||||
if !will_continue {
|
if !will_continue {
|
||||||
return errors.New("User declined to connect to offline server")
|
return errors.New("User declined to connect to offline server")
|
||||||
}
|
}
|
||||||
@@ -164,12 +214,18 @@ func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_prof
|
|||||||
|
|
||||||
// Check if server is applicable for selected profile.
|
// Check if server is applicable for selected profile.
|
||||||
if server_profile.Version != user_profile.Version {
|
if server_profile.Version != user_profile.Version {
|
||||||
mbox_string := "Invalid game profile selected.\n\nSelected profile have different game version than server.\nPlease, select valid profile and retry."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Invalid game profile selected.\n\nSelected profile have different game version than server.\nPlease, select valid profile and retry."
|
||||||
})
|
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
messagebox.Response(func() {
|
||||||
|
messagebox.Destroy()
|
||||||
|
})
|
||||||
|
messagebox.Run()
|
||||||
|
} else {
|
||||||
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Invalid game profile selected.</span></markup>"})
|
||||||
|
}
|
||||||
return errors.New("User didn't select valid profile, mismatch with server's version.")
|
return errors.New("User didn't select valid profile, mismatch with server's version.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +239,9 @@ func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_prof
|
|||||||
srv_name_for_label := server_profile.Name
|
srv_name_for_label := server_profile.Name
|
||||||
if strings.Contains(server_profile.Name, "markup") {
|
if strings.Contains(server_profile.Name, "markup") {
|
||||||
srv_name_for_label = string([]byte(server_profile.Name)[8:len(server_profile.Name)-9])
|
srv_name_for_label = string([]byte(server_profile.Name)[8:len(server_profile.Name)-9])
|
||||||
|
} else {
|
||||||
|
srv_name := ctx.Colorizer.Fix(server_profile.Name)
|
||||||
|
srv_name_for_label = string([]byte(srv_name)[8:len(srv_name)-9])
|
||||||
}
|
}
|
||||||
// Show great coloured label.
|
// Show great coloured label.
|
||||||
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Urban Terror is launched with profile </span><span foreground=\"blue\">" + user_profile.Name + "</span> <span foreground=\"red\" font_weight=\"bold\">and connected to </span><span foreground=\"orange\" font_weight=\"bold\">" + srv_name_for_label + "</span></markup>"})
|
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Urban Terror is launched with profile </span><span foreground=\"blue\">" + user_profile.Name + "</span> <span foreground=\"red\" font_weight=\"bold\">and connected to </span><span foreground=\"orange\" font_weight=\"bold\">" + srv_name_for_label + "</span></markup>"})
|
||||||
|
|||||||
96
ui/mainwindow_servers_sorting.go
Normal file
96
ui/mainwindow_servers_sorting.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
// stdlib
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
// other
|
||||||
|
"github.com/mattn/go-gtk/glib"
|
||||||
|
"github.com/mattn/go-gtk/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *MainWindow) sortServersByName(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int {
|
||||||
|
var name1_raw glib.GValue
|
||||||
|
var name2_raw glib.GValue
|
||||||
|
|
||||||
|
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
||||||
|
if current_tab == "Servers" {
|
||||||
|
model.GetValue(a, m.column_pos["Servers"]["Name"], &name1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Servers"]["Name"], &name2_raw)
|
||||||
|
} else if current_tab == "Favorites" {
|
||||||
|
model.GetValue(a, m.column_pos["Favorites"]["Name"], &name1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Favorites"]["Name"], &name2_raw)
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
name1 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name1_raw.GetString()))
|
||||||
|
name2 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name2_raw.GetString()))
|
||||||
|
|
||||||
|
if name1 < name2 {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MainWindow) sortServersByPlayers(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int {
|
||||||
|
var players1_raw glib.GValue
|
||||||
|
var players2_raw glib.GValue
|
||||||
|
|
||||||
|
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
||||||
|
if current_tab == "Servers" {
|
||||||
|
model.GetValue(a, m.column_pos["Servers"]["Players"], &players1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Servers"]["Players"], &players2_raw)
|
||||||
|
} else if current_tab == "Favorites" {
|
||||||
|
model.GetValue(a, m.column_pos["Favorites"]["Players"], &players1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Favorites"]["Players"], &players2_raw)
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
players1_online := strings.Split(players1_raw.GetString(), "/")[0]
|
||||||
|
players2_online := strings.Split(players2_raw.GetString(), "/")[0]
|
||||||
|
|
||||||
|
if len(players1_online) > 0 && len(players2_online) > 0 {
|
||||||
|
players1, _ := strconv.Atoi(players1_online)
|
||||||
|
players2, _ := strconv.Atoi(players2_online)
|
||||||
|
if players1 > players2 {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MainWindow) sortServersByPing(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int {
|
||||||
|
var ping1_raw glib.GValue
|
||||||
|
var ping2_raw glib.GValue
|
||||||
|
|
||||||
|
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
|
||||||
|
if current_tab == "Servers" {
|
||||||
|
model.GetValue(a, m.column_pos["Servers"]["Ping"], &ping1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Servers"]["Ping"], &ping2_raw)
|
||||||
|
} else if current_tab == "Favorites" {
|
||||||
|
model.GetValue(a, m.column_pos["Favorites"]["Ping"], &ping1_raw)
|
||||||
|
model.GetValue(b, m.column_pos["Favorites"]["Ping"], &ping2_raw)
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ping1, _ := strconv.Atoi(ping1_raw.GetString())
|
||||||
|
ping2, _ := strconv.Atoi(ping2_raw.GetString())
|
||||||
|
|
||||||
|
if ping1 < ping2 {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ package ui
|
|||||||
import (
|
import (
|
||||||
// stdlib
|
// stdlib
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
"github.com/pztrn/urtrator/datamodels"
|
"github.com/pztrn/urtrator/datamodels"
|
||||||
@@ -66,12 +67,16 @@ func (o *OptionsDialog) closeOptionsDialogWithSaving() {
|
|||||||
|
|
||||||
o.saveGeneral()
|
o.saveGeneral()
|
||||||
|
|
||||||
mbox_string := "Some options require application restart to be applied."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(o.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Some options require application restart to be applied."
|
||||||
})
|
m := gtk.NewMessageDialog(o.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
m.Response(func() {
|
||||||
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
|
|
||||||
o.window.Destroy()
|
o.window.Destroy()
|
||||||
}
|
}
|
||||||
@@ -141,15 +146,33 @@ func (o *OptionsDialog) initializeAppearanceTab() {
|
|||||||
func (o *OptionsDialog) initializeGeneralTab() {
|
func (o *OptionsDialog) initializeGeneralTab() {
|
||||||
general_vbox := gtk.NewVBox(false, 0)
|
general_vbox := gtk.NewVBox(false, 0)
|
||||||
|
|
||||||
|
general_table := gtk.NewTable(2, 2, false)
|
||||||
|
|
||||||
// Tray icon checkbox.
|
// Tray icon checkbox.
|
||||||
o.show_tray_icon = gtk.NewCheckButtonWithLabel("Show tray icon?")
|
show_tray_icon_label := gtk.NewLabel("Show icon in tray")
|
||||||
|
show_tray_icon_label.SetAlignment(0, 0)
|
||||||
|
general_table.Attach(show_tray_icon_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
|
o.show_tray_icon = gtk.NewCheckButtonWithLabel("")
|
||||||
o.show_tray_icon.SetTooltipText("Show icon in tray")
|
o.show_tray_icon.SetTooltipText("Show icon in tray")
|
||||||
general_vbox.PackStart(o.show_tray_icon, false, true, 5)
|
general_table.Attach(o.show_tray_icon, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Autoupdate checkbox.
|
// Autoupdate checkbox.
|
||||||
o.autoupdate = gtk.NewCheckButtonWithLabel("Automatically update URTrator?")
|
autoupdate_tooltip := "Should URTrator check for updates and update itself? Not working now."
|
||||||
o.autoupdate.SetTooltipText("Should URTrator check for updates and update itself? Not working now.")
|
autoupdate_label := gtk.NewLabel("Automatically update URTrator?")
|
||||||
general_vbox.PackStart(o.autoupdate, false, true, 5)
|
autoupdate_label.SetTooltipText(autoupdate_tooltip)
|
||||||
|
autoupdate_label.SetAlignment(0, 0)
|
||||||
|
general_table.Attach(autoupdate_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
|
o.autoupdate = gtk.NewCheckButtonWithLabel("")
|
||||||
|
o.autoupdate.SetTooltipText(autoupdate_tooltip)
|
||||||
|
general_table.Attach(o.autoupdate, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
|
// Vertical separator.
|
||||||
|
sep := gtk.NewVBox(false, 0)
|
||||||
|
|
||||||
|
general_vbox.PackStart(general_table, false, true, 0)
|
||||||
|
general_vbox.PackStart(sep, false, true, 0)
|
||||||
|
|
||||||
o.tab_widget.AppendPage(general_vbox, gtk.NewLabel("General"))
|
o.tab_widget.AppendPage(general_vbox, gtk.NewLabel("General"))
|
||||||
}
|
}
|
||||||
@@ -171,7 +194,7 @@ func (o *OptionsDialog) initializeTabs() {
|
|||||||
|
|
||||||
// Buttons for saving and discarding changes.
|
// Buttons for saving and discarding changes.
|
||||||
buttons_hbox := gtk.NewHBox(false, 0)
|
buttons_hbox := gtk.NewHBox(false, 0)
|
||||||
sep := gtk.NewHSeparator()
|
sep := gtk.NewHBox(false, 0)
|
||||||
|
|
||||||
cancel_button := gtk.NewButtonWithLabel("Cancel")
|
cancel_button := gtk.NewButtonWithLabel("Cancel")
|
||||||
cancel_button.Clicked(o.closeOptionsDialogByCancel)
|
cancel_button.Clicked(o.closeOptionsDialogByCancel)
|
||||||
@@ -190,7 +213,7 @@ func (o *OptionsDialog) initializeTabs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *OptionsDialog) initializeUrtTab() {
|
func (o *OptionsDialog) initializeUrtTab() {
|
||||||
urt_hbox := gtk.NewHBox(false, 0)
|
urt_hbox := gtk.NewHBox(false, 5)
|
||||||
|
|
||||||
// Profiles list.
|
// Profiles list.
|
||||||
o.profiles_list = gtk.NewTreeView()
|
o.profiles_list = gtk.NewTreeView()
|
||||||
@@ -200,17 +223,13 @@ func (o *OptionsDialog) initializeUrtTab() {
|
|||||||
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Profile name", gtk.NewCellRendererText(), "text", 0))
|
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Profile name", gtk.NewCellRendererText(), "text", 0))
|
||||||
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Urban Terror version", gtk.NewCellRendererText(), "text", 1))
|
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Urban Terror version", gtk.NewCellRendererText(), "text", 1))
|
||||||
|
|
||||||
//crt := gtk.NewCellRendererToggle()
|
|
||||||
//second_x_column := gtk.NewTreeViewColumnWithAttributes("Second X session", crt, "bool", 2)
|
|
||||||
//o.profiles_list.AppendColumn(second_x_column)
|
|
||||||
|
|
||||||
// Profiles list buttons.
|
// Profiles list buttons.
|
||||||
urt_profiles_buttons_vbox := gtk.NewVBox(false, 0)
|
urt_profiles_buttons_vbox := gtk.NewVBox(false, 0)
|
||||||
|
|
||||||
button_add := gtk.NewButtonWithLabel("Add")
|
button_add := gtk.NewButtonWithLabel("Add")
|
||||||
button_add.SetTooltipText("Add new profile")
|
button_add.SetTooltipText("Add new profile")
|
||||||
button_add.Clicked(o.addProfile)
|
button_add.Clicked(o.addProfile)
|
||||||
urt_profiles_buttons_vbox.PackStart(button_add, false, true, 5)
|
urt_profiles_buttons_vbox.PackStart(button_add, false, true, 0)
|
||||||
|
|
||||||
button_edit := gtk.NewButtonWithLabel("Edit")
|
button_edit := gtk.NewButtonWithLabel("Edit")
|
||||||
button_edit.SetTooltipText("Edit selected profile. Do nothing if no profile was selected.")
|
button_edit.SetTooltipText("Edit selected profile. Do nothing if no profile was selected.")
|
||||||
@@ -218,13 +237,13 @@ func (o *OptionsDialog) initializeUrtTab() {
|
|||||||
urt_profiles_buttons_vbox.PackStart(button_edit, false, true, 5)
|
urt_profiles_buttons_vbox.PackStart(button_edit, false, true, 5)
|
||||||
|
|
||||||
// Spacer for profiles list buttons.
|
// Spacer for profiles list buttons.
|
||||||
sep := gtk.NewVSeparator()
|
sep := gtk.NewVBox(false, 0)
|
||||||
urt_profiles_buttons_vbox.PackStart(sep, true, true, 5)
|
urt_profiles_buttons_vbox.PackStart(sep, true, true, 5)
|
||||||
|
|
||||||
button_delete := gtk.NewButtonWithLabel("Delete")
|
button_delete := gtk.NewButtonWithLabel("Delete")
|
||||||
button_delete.SetTooltipText("Delete selected profile. Do nothing if no profile was selected.")
|
button_delete.SetTooltipText("Delete selected profile. Do nothing if no profile was selected.")
|
||||||
button_delete.Clicked(o.deleteProfile)
|
button_delete.Clicked(o.deleteProfile)
|
||||||
urt_profiles_buttons_vbox.PackStart(button_delete, false, true, 5)
|
urt_profiles_buttons_vbox.PackStart(button_delete, false, true, 0)
|
||||||
|
|
||||||
urt_hbox.Add(urt_profiles_buttons_vbox)
|
urt_hbox.Add(urt_profiles_buttons_vbox)
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ import (
|
|||||||
type OptionsProfile struct {
|
type OptionsProfile struct {
|
||||||
// Window.
|
// Window.
|
||||||
window *gtk.Window
|
window *gtk.Window
|
||||||
// Main Vertical Box.
|
// Main table.
|
||||||
vbox *gtk.VBox
|
table *gtk.Table
|
||||||
// Profile name.
|
// Profile name.
|
||||||
profile_name *gtk.Entry
|
profile_name *gtk.Entry
|
||||||
// Binary path.
|
// Binary path.
|
||||||
@@ -71,12 +71,18 @@ func (op *OptionsProfile) browseForBinaryHelper() {
|
|||||||
if runtime.GOARCH == "amd64" {
|
if runtime.GOARCH == "amd64" {
|
||||||
if len(filename) > 0 && strings.Split(filename, ".")[1] != "x86_64" && strings.Split(filename, ".")[0] != "Quake3-UrT" {
|
if len(filename) > 0 && strings.Split(filename, ".")[1] != "x86_64" && strings.Split(filename, ".")[0] != "Quake3-UrT" {
|
||||||
fmt.Println("Invalid binary selected!")
|
fmt.Println("Invalid binary selected!")
|
||||||
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.x86_64."
|
// Temporary disable all these modals on Linux.
|
||||||
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
m.Response(func() {
|
if runtime.GOOS != "linux" {
|
||||||
m.Destroy()
|
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.x86_64."
|
||||||
})
|
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Run()
|
m.Response(func() {
|
||||||
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
}
|
||||||
op.binary_path.SetText("")
|
op.binary_path.SetText("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,21 +93,33 @@ func (op *OptionsProfile) browseForBinaryHelper() {
|
|||||||
filename = strings.Split(filename, "Quake3-UrT.app")[1]
|
filename = strings.Split(filename, "Quake3-UrT.app")[1]
|
||||||
if len(filename) > 0 && !strings.Contains(strings.Split(filename, ".")[1], "x86_64") && !strings.Contains(strings.Split(filename, ".")[0], "Quake3-UrT") {
|
if len(filename) > 0 && !strings.Contains(strings.Split(filename, ".")[1], "x86_64") && !strings.Contains(strings.Split(filename, ".")[0], "Quake3-UrT") {
|
||||||
fmt.Println("Invalid binary selected!")
|
fmt.Println("Invalid binary selected!")
|
||||||
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64."
|
// Temporary disable all these modals on Linux.
|
||||||
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64."
|
||||||
|
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
|
m.Response(func() {
|
||||||
|
m.Destroy()
|
||||||
|
})
|
||||||
|
m.Run()
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
op.binary_path.SetText("")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Temporary disable all these modals on Linux.
|
||||||
|
// See https://github.com/mattn/go-gtk/issues/289.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64.\n\nNote, that currently URTrator supports only official binary."
|
||||||
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
||||||
m.Response(func() {
|
m.Response(func() {
|
||||||
m.Destroy()
|
m.Destroy()
|
||||||
})
|
})
|
||||||
m.Run()
|
m.Run()
|
||||||
op.binary_path.SetText("")
|
} else {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
mbox_string := "Invalid binary selected!\nAccording to your OS, it should be Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64.\n\nNote, that currently URTrator supports only official binary."
|
|
||||||
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
|
|
||||||
m.Response(func() {
|
|
||||||
m.Destroy()
|
|
||||||
})
|
|
||||||
m.Run()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,90 +148,85 @@ func (op *OptionsProfile) Initialize(update bool) {
|
|||||||
op.window.SetPosition(gtk.WIN_POS_CENTER)
|
op.window.SetPosition(gtk.WIN_POS_CENTER)
|
||||||
op.window.SetIcon(logo)
|
op.window.SetIcon(logo)
|
||||||
|
|
||||||
op.vbox = gtk.NewVBox(false, 0)
|
op.table = gtk.NewTable(6, 2, false)
|
||||||
|
op.table.SetRowSpacings(2)
|
||||||
|
|
||||||
// Profile name.
|
// Profile name.
|
||||||
profile_name_tooltip := "This how you will see profile on profiles lists."
|
profile_name_tooltip := "This how you will see profile on profiles lists."
|
||||||
pn_hbox := gtk.NewHBox(false, 0)
|
|
||||||
pn_label := gtk.NewLabel("Profile name:")
|
pn_label := gtk.NewLabel("Profile name:")
|
||||||
pn_label.SetTooltipText(profile_name_tooltip)
|
pn_label.SetTooltipText(profile_name_tooltip)
|
||||||
profile_name_sep := gtk.NewHSeparator()
|
pn_label.SetAlignment(0, 0)
|
||||||
profile_name_sep.SetTooltipText(profile_name_tooltip)
|
op.table.Attach(pn_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
op.profile_name = gtk.NewEntry()
|
op.profile_name = gtk.NewEntry()
|
||||||
op.profile_name.SetTooltipText(profile_name_tooltip)
|
op.profile_name.SetTooltipText(profile_name_tooltip)
|
||||||
pn_hbox.PackStart(pn_label, false, true, 5)
|
op.table.Attach(op.profile_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
pn_hbox.PackStart(profile_name_sep, true, true, 5)
|
|
||||||
pn_hbox.PackStart(op.profile_name, true, true, 5)
|
|
||||||
op.vbox.PackStart(pn_hbox, false, true, 5)
|
|
||||||
|
|
||||||
// Urban Terror version.
|
// Urban Terror version.
|
||||||
urt_version_tooltip := "Urban Terror version for which this profile applies."
|
urt_version_tooltip := "Urban Terror version for which this profile applies."
|
||||||
urt_version_hbox := gtk.NewHBox(false, 0)
|
|
||||||
urt_version_label := gtk.NewLabel("Urban Terror version:")
|
urt_version_label := gtk.NewLabel("Urban Terror version:")
|
||||||
urt_version_label.SetTooltipText(urt_version_tooltip)
|
urt_version_label.SetTooltipText(urt_version_tooltip)
|
||||||
urt_version_sep := gtk.NewHSeparator()
|
urt_version_label.SetAlignment(0, 0)
|
||||||
urt_version_sep.SetTooltipText(urt_version_tooltip)
|
op.table.Attach(urt_version_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
op.urt_version_combo = gtk.NewComboBoxText()
|
op.urt_version_combo = gtk.NewComboBoxText()
|
||||||
op.urt_version_combo.SetTooltipText(urt_version_tooltip)
|
op.urt_version_combo.SetTooltipText(urt_version_tooltip)
|
||||||
op.urt_version_combo.AppendText("4.2.023")
|
op.urt_version_combo.AppendText("4.2.023")
|
||||||
op.urt_version_combo.AppendText("4.3.0")
|
op.urt_version_combo.AppendText("4.3.0")
|
||||||
op.urt_version_combo.AppendText("4.3.1")
|
op.urt_version_combo.AppendText("4.3.1")
|
||||||
op.urt_version_combo.SetActive(1)
|
op.urt_version_combo.SetActive(2)
|
||||||
urt_version_hbox.PackStart(urt_version_label, false, true, 5)
|
op.table.Attach(op.urt_version_combo, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
urt_version_hbox.PackStart(urt_version_sep, true, true, 5)
|
|
||||||
urt_version_hbox.PackStart(op.urt_version_combo, true, true, 5)
|
|
||||||
op.vbox.PackStart(urt_version_hbox, false, true, 5)
|
|
||||||
|
|
||||||
// Urban Terror binary path.
|
// Urban Terror binary path.
|
||||||
select_binary_tooltip := "Urban Terror binary. Some checks will be executed, so make sure you have selected right binary:\n\nQuake3-UrT.i386 for linux-x86\nQuake3-UrT.x86_64 for linux-amd64\nQuake3-UrT.app for macOS"
|
select_binary_tooltip := "Urban Terror binary. Some checks will be executed, so make sure you have selected right binary:\n\nQuake3-UrT.i386 for linux-x86\nQuake3-UrT.x86_64 for linux-amd64\nQuake3-UrT.app for macOS"
|
||||||
binpath_hbox := gtk.NewHBox(false, 0)
|
binpath_hbox := gtk.NewHBox(false, 0)
|
||||||
binpath_label := gtk.NewLabel("Urban Terror binary:")
|
binpath_label := gtk.NewLabel("Urban Terror binary:")
|
||||||
binpath_label.SetTooltipText(select_binary_tooltip)
|
binpath_label.SetTooltipText(select_binary_tooltip)
|
||||||
binpath_sep := gtk.NewHSeparator()
|
binpath_label.SetAlignment(0, 0)
|
||||||
binpath_sep.SetTooltipText(select_binary_tooltip)
|
op.table.Attach(binpath_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
op.binary_path = gtk.NewEntry()
|
op.binary_path = gtk.NewEntry()
|
||||||
op.binary_path.SetTooltipText(select_binary_tooltip)
|
op.binary_path.SetTooltipText(select_binary_tooltip)
|
||||||
button_select_binary := gtk.NewButtonWithLabel("Browse")
|
button_select_binary := gtk.NewButtonWithLabel("Browse")
|
||||||
button_select_binary.SetTooltipText(select_binary_tooltip)
|
button_select_binary.SetTooltipText(select_binary_tooltip)
|
||||||
button_select_binary.Clicked(op.browseForBinary)
|
button_select_binary.Clicked(op.browseForBinary)
|
||||||
binpath_hbox.PackStart(binpath_label, false, true, 5)
|
|
||||||
binpath_hbox.PackStart(binpath_sep, true, true, 5)
|
|
||||||
binpath_hbox.PackStart(op.binary_path, true, true, 5)
|
binpath_hbox.PackStart(op.binary_path, true, true, 5)
|
||||||
binpath_hbox.PackStart(button_select_binary, false, true, 5)
|
binpath_hbox.PackStart(button_select_binary, false, true, 5)
|
||||||
op.vbox.PackStart(binpath_hbox, false, true, 5)
|
op.table.Attach(binpath_hbox, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
|
||||||
|
|
||||||
// Should we use additional X session?
|
// Should we use additional X session?
|
||||||
another_x_tooltip := "If this is checked, Urban Terror will be launched in another X session.\n\nThis could help if you're experiencing visual lag, glitches and FPS drops under compositing WMs, like Mutter and KWin."
|
another_x_tooltip := "If this is checked, Urban Terror will be launched in another X session.\n\nThis could help if you're experiencing visual lag, glitches and FPS drops under compositing WMs, like Mutter and KWin."
|
||||||
op.another_x_session = gtk.NewCheckButtonWithLabel("Start Urban Terror in another X session?")
|
another_x_label := gtk.NewLabel("Start Urban Terror in another X session?")
|
||||||
|
another_x_label.SetTooltipText(another_x_tooltip)
|
||||||
|
another_x_label.SetAlignment(0, 0)
|
||||||
|
op.table.Attach(another_x_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
op.another_x_session = gtk.NewCheckButtonWithLabel("")
|
||||||
op.another_x_session.SetTooltipText(another_x_tooltip)
|
op.another_x_session.SetTooltipText(another_x_tooltip)
|
||||||
op.vbox.PackStart(op.another_x_session, false, true, 5)
|
// macOS and Windows can't do that :).
|
||||||
// macOS can't do that :).
|
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
op.another_x_session.SetSensitive(false)
|
op.another_x_session.SetSensitive(false)
|
||||||
}
|
}
|
||||||
|
op.table.Attach(op.another_x_session, 1, 2, 3, 4, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// Additional game parameters.
|
// Additional game parameters.
|
||||||
params_tooltip := "Additional parameters that will be passed to Urban Terror executable."
|
params_tooltip := "Additional parameters that will be passed to Urban Terror executable."
|
||||||
params_hbox := gtk.NewHBox(false, 0)
|
|
||||||
params_label := gtk.NewLabel("Additional parameters:")
|
params_label := gtk.NewLabel("Additional parameters:")
|
||||||
params_label.SetTooltipText(params_tooltip)
|
params_label.SetTooltipText(params_tooltip)
|
||||||
params_sep := gtk.NewHSeparator()
|
params_label.SetAlignment(0, 0)
|
||||||
params_sep.SetTooltipText(params_tooltip)
|
op.table.Attach(params_label, 0, 1, 4, 5, gtk.FILL, gtk.SHRINK, 5, 5)
|
||||||
|
|
||||||
op.additional_parameters = gtk.NewEntry()
|
op.additional_parameters = gtk.NewEntry()
|
||||||
op.additional_parameters.SetTooltipText(params_tooltip)
|
op.additional_parameters.SetTooltipText(params_tooltip)
|
||||||
params_hbox.PackStart(params_label, false, true, 5)
|
op.table.Attach(op.additional_parameters, 1, 2, 4, 5, gtk.FILL, gtk.FILL, 5, 5)
|
||||||
params_hbox.PackStart(params_sep, true, true, 5)
|
|
||||||
params_hbox.PackStart(op.additional_parameters, true, true, 5)
|
|
||||||
op.vbox.PackStart(params_hbox, false, true, 5)
|
|
||||||
|
|
||||||
// Vertical separator.
|
// Invisible thing.
|
||||||
vert_sep := gtk.NewVSeparator()
|
inv_label := gtk.NewLabel("")
|
||||||
op.vbox.PackStart(vert_sep, true, true, 5)
|
op.table.Attach(inv_label, 1, 2, 5, 6, gtk.EXPAND, gtk.FILL, 5, 5)
|
||||||
|
|
||||||
// The buttons.
|
// The buttons.
|
||||||
buttons_box := gtk.NewHBox(false, 0)
|
buttons_box := gtk.NewHBox(false, 0)
|
||||||
buttons_sep := gtk.NewHSeparator()
|
buttons_sep := gtk.NewHBox(false, 0)
|
||||||
|
|
||||||
cancel_button := gtk.NewButtonWithLabel("Cancel")
|
cancel_button := gtk.NewButtonWithLabel("Cancel")
|
||||||
cancel_button.SetTooltipText("Close without saving")
|
cancel_button.SetTooltipText("Close without saving")
|
||||||
@@ -233,9 +246,14 @@ func (op *OptionsProfile) Initialize(update bool) {
|
|||||||
add_button.Clicked(op.saveProfile)
|
add_button.Clicked(op.saveProfile)
|
||||||
buttons_box.PackStart(add_button, false, true, 5)
|
buttons_box.PackStart(add_button, false, true, 5)
|
||||||
|
|
||||||
op.vbox.PackStart(buttons_box, false, true, 5)
|
vert_sep_box := gtk.NewVBox(false, 0)
|
||||||
|
|
||||||
op.window.Add(op.vbox)
|
vbox := gtk.NewVBox(false, 0)
|
||||||
|
vbox.PackStart(op.table, false, true, 5)
|
||||||
|
vbox.PackStart(vert_sep_box, true, true, 5)
|
||||||
|
vbox.PackStart(buttons_box, false, true, 5)
|
||||||
|
|
||||||
|
op.window.Add(vbox)
|
||||||
op.window.ShowAll()
|
op.window.ShowAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,26 +262,23 @@ func (op *OptionsProfile) InitializeUpdate(profile_name string) {
|
|||||||
op.Initialize(true)
|
op.Initialize(true)
|
||||||
|
|
||||||
// Get profile data.
|
// Get profile data.
|
||||||
profile := []datamodels.Profile{}
|
profile := ctx.Cache.Profiles[profile_name].Profile
|
||||||
err := ctx.Database.Db.Select(&profile, ctx.Database.Db.Rebind("SELECT * FROM urt_profiles WHERE name=?"), profile_name)
|
op.profile_name.SetText(profile.Name)
|
||||||
if err != nil {
|
op.binary_path.SetText(profile.Binary)
|
||||||
fmt.Println(err.Error())
|
op.additional_parameters.SetText(profile.Additional_params)
|
||||||
}
|
if profile.Second_x_session == "1" {
|
||||||
|
|
||||||
op.profile_name.SetText(profile[0].Name)
|
|
||||||
op.binary_path.SetText(profile[0].Binary)
|
|
||||||
op.additional_parameters.SetText(profile[0].Additional_params)
|
|
||||||
if profile[0].Second_x_session == "1" {
|
|
||||||
op.another_x_session.SetActive(true)
|
op.another_x_session.SetActive(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if profile[0].Version == "4.3.0" {
|
if profile.Version == "4.3.0" {
|
||||||
op.urt_version_combo.SetActive(1)
|
op.urt_version_combo.SetActive(1)
|
||||||
|
} else if profile.Version == "4.3.1" {
|
||||||
|
op.urt_version_combo.SetActive(2)
|
||||||
} else {
|
} else {
|
||||||
op.urt_version_combo.SetActive(0)
|
op.urt_version_combo.SetActive(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
op.old_profile = &profile[0]
|
op.old_profile = profile
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
104
ui/server_cvars.go
Normal file
104
ui/server_cvars.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// URTator - Urban Terror server browser and game launcher, written in
|
||||||
|
// Go.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under Terms and Conditions of GNU General Public License
|
||||||
|
// version 3 or any higher.
|
||||||
|
// ToDo: put full text of license here.
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
// stdlib
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
// Local
|
||||||
|
"github.com/pztrn/urtrator/ioq3dataparser"
|
||||||
|
|
||||||
|
// Other
|
||||||
|
"github.com/mattn/go-gtk/gtk"
|
||||||
|
"github.com/mattn/go-gtk/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerCVarsDialog struct {
|
||||||
|
// Window.
|
||||||
|
window *gtk.Window
|
||||||
|
// Main Vertical Box.
|
||||||
|
vbox *gtk.VBox
|
||||||
|
// Treeview for CVars.
|
||||||
|
treeview *gtk.TreeView
|
||||||
|
// Store for treeview.
|
||||||
|
treeview_store *gtk.ListStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (scd *ServerCVarsDialog) Close() {
|
||||||
|
scd.window.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (scd *ServerCVarsDialog) fill(srv_address string) {
|
||||||
|
server_info := ctx.Cache.Servers[srv_address].Server
|
||||||
|
parsed_general_data := ioq3dataparser.ParseInfoToMap(server_info.ExtendedConfig)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
scd.treeview_store.Append(iter)
|
||||||
|
scd.treeview_store.SetValue(iter, 0, general_data_keys[k])
|
||||||
|
scd.treeview_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (scd *ServerCVarsDialog) Initialize(w *gtk.Window, srv_address string) {
|
||||||
|
fmt.Println("Showing server's CVars...")
|
||||||
|
|
||||||
|
scd.initializeStorages()
|
||||||
|
|
||||||
|
scd.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
|
||||||
|
scd.window.SetTitle("URTrator - Server CVars")
|
||||||
|
scd.window.Connect("destroy", scd.Close)
|
||||||
|
scd.window.SetTransientFor(w)
|
||||||
|
scd.window.SetDefaultSize(300, 400)
|
||||||
|
|
||||||
|
scd.vbox = gtk.NewVBox(false, 0)
|
||||||
|
scd.window.Add(scd.vbox)
|
||||||
|
|
||||||
|
// CVars scrolls.
|
||||||
|
si := gtk.NewScrolledWindow(nil, nil)
|
||||||
|
scd.vbox.PackStart(si, true, true, 5)
|
||||||
|
|
||||||
|
// CVars list.
|
||||||
|
scd.treeview = gtk.NewTreeView()
|
||||||
|
scd.treeview.SetModel(scd.treeview_store)
|
||||||
|
si.Add(scd.treeview)
|
||||||
|
|
||||||
|
scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Key", gtk.NewCellRendererText(), "markup", 0))
|
||||||
|
scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Value", gtk.NewCellRendererText(), "markup", 1))
|
||||||
|
|
||||||
|
// Close button.
|
||||||
|
hbox := gtk.NewHBox(false, 0)
|
||||||
|
scd.vbox.PackStart(hbox, false, true, 5)
|
||||||
|
|
||||||
|
sep := gtk.NewHBox(false, 0)
|
||||||
|
hbox.PackStart(sep, true, true, 5)
|
||||||
|
|
||||||
|
close_button := gtk.NewButtonWithLabel("Close")
|
||||||
|
close_button.Clicked(scd.Close)
|
||||||
|
hbox.PackStart(close_button, false, true, 5)
|
||||||
|
|
||||||
|
scd.fill(srv_address)
|
||||||
|
|
||||||
|
scd.window.ShowAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (scd *ServerCVarsDialog) initializeStorages() {
|
||||||
|
scd.treeview_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING)
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// URTator - Urban Terror server browser and game launcher, written in
|
|
||||||
// Go.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under Terms and Conditions of GNU General Public License
|
|
||||||
// version 3 or any higher.
|
|
||||||
// ToDo: put full text of license here.
|
|
||||||
package ui
|
|
||||||
|
|
||||||
import (
|
|
||||||
// stdlib
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
// Local
|
|
||||||
//"github.com/pztrn/urtrator/datamodels"
|
|
||||||
|
|
||||||
// Other
|
|
||||||
"github.com/mattn/go-gtk/gtk"
|
|
||||||
//"github.com/mattn/go-gtk/glib"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ServerInfoDialog struct {
|
|
||||||
// Window.
|
|
||||||
window *gtk.Window
|
|
||||||
// Main Vertical Box.
|
|
||||||
vbox *gtk.VBox
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sid *ServerInfoDialog) Initialize() {
|
|
||||||
fmt.Println("Showing server's information...")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user