74 Commits

Author SHA1 Message Date
e66875ffbe Version bump. 2016-11-26 19:32:37 +05:00
979de8d858 Filtering by game mode implemented. 2016-11-26 16:20:57 +05:00
f0ddda1af5 "All versions" instead of "All" in version select comboboxes. 2016-11-26 16:06:33 +05:00
bd344fee2e Filter by server version and forgotten server's CVars window.
Implemented filtering servers by server's version, related to #27.
This combobox is saved-restored across restarts.

Added forgotten bd04870 server_cvars.go, which is responsible for
showing server's CVars window.
2016-11-26 16:00:17 +05:00
7950ab5a1f macOS might have no GTK configuration, so forcing "only icons" for toolbar. 2016-11-26 09:35:59 +05:00
3b3aae16b0 Accidently attached wrong widget. 2016-11-26 09:27:46 +05:00
a57c878dad Prettified favorites add/edit dialog. Fixes #33. 2016-11-26 09:24:36 +05:00
474821ba7b Ooops :) 2016-11-26 09:11:51 +05:00
f32cf4d1f6 "GENERAL INFO" list item isn't needed anymore. 2016-11-26 09:10:57 +05:00
bd04870aa3 Splitted sidebar's list into two and separate CVars window.
Splitted sidebar's list into two separate lists - one for
general server's info (hostname, players, etc.) and one for
players list.

Also, moved CVars list to separate window which can be shown by
clicking approriate button under player's list.
2016-11-26 09:05:48 +05:00
280c65f116 Distinguish bots from humans.
Players column now have three integers - first is real humans
count, second - bots count, and third - maximum players allowed
on this server. Also, sidebar will show bots count as well.
2016-11-26 07:38:26 +05:00
32c6297765 Fixed game version combobox not selecting proper version on profile editing. 2016-11-25 04:49:19 +05:00
190f76eb82 Fixed profiles editing crashing application if profile wasn't saved in database. 2016-11-25 04:44:46 +05:00
5c295f08ab Prettify options window. 2016-11-25 04:31:45 +05:00
061bfcaeb9 UI design updates.
Got rid of visible separators, replaced them with HBox and VBox.

Reworked profile add/edit window, now it looks prettier and
organic.
2016-11-25 04:11:44 +05:00
5ca8299714 Show selected server's information on active tab changing.
URTrator will now show information about selected server on
activated tab. E.g. when you switched from "Servers" to
"Favorites", sidebar informational widget will be updated with
server's data for selected server on "Favorites" tab.
2016-11-25 03:12:05 +05:00
9c8aa1cc34 Preparing to 0.1.0 release. 2016-11-23 10:13:01 +05:00
5fcbd8536c Update selected server's info in sidebar after updating server's data. 2016-11-23 10:10:11 +05:00
fb7a471aec Shw message in toolbar when updating selected server's data. 2016-11-23 10:02:58 +05:00
8c9d948a52 Fixed tooltip text for "Update all servers" button. 2016-11-23 09:53:09 +05:00
8b44d194b5 Hide private servers checkboxes. 2016-11-23 09:49:39 +05:00
3b0a93e63a By default srting players by name as well as cvars in sidebar. 2016-11-23 07:51:41 +05:00
b85ba0470c Fixed rendering of logo on launch button.
Also, made this logo smaller to beautify interface.
2016-11-23 07:42:58 +05:00
f127fdc9f4 Fixed players counting on servers update. 2016-11-23 07:41:14 +05:00
5ef54d943e Removed unneded "Additional information" button. 2016-11-23 07:35:10 +05:00
9e6cdfc869 Increased max ping requests to servers. Fixes #3. 2016-11-22 18:50:56 +05:00
bfd3f884b3 Automatic profile selection. Fixes #14.
Automatically select first added profile on every profiles list
update. Yes, quick hack. In future we will autodetect profiles
based on server version, and profiles combobox will only be
needed for quick connect.
2016-11-22 18:33:53 +05:00
7e6b698c1c Proper sorting by servers names. Fixing #12. 2016-11-22 18:23:43 +05:00
4516abb916 go-gtk fixed default sorting, so unlock it for all OSes. 2016-11-22 17:14:02 +05:00
e731653652 Fix for previous commit, wrong sorting call was masked on Windows. 2016-11-22 14:37:11 +05:00
e16d6fa878 Disabling setting default sort column on windows until it will
be fixed in go-gtk (https://github.com/mattn/go-gtk/issues/291).
2016-11-22 14:25:16 +05:00
89298d894b Hello, 0.1.0-beta5! 2016-11-22 12:02:12 +05:00
88b9b31f6a Updated README about required Go version. 2016-11-22 11:56:48 +05:00
1fe49871f1 Proper sorting by server name. 2016-11-22 11:53:54 +05:00
4f5bf90dbe Set 4.3.1 as default version in profiles dialog. 2016-11-22 11:38:48 +05:00
25bebf87df Re-enabled sorting for servers lists and hide offline checkboxes default value.
Re-enabled sorting for servers lists, which forces to use devel
version of Go. 1.7.3 have problems with GC and URTrator will
segfault.

Hide offline checkboxes for all servers and favorites now
checked by default.
2016-11-22 11:36:17 +05:00
c4ed421106 Temporary disable sorting in servers list until fixed in go-gtk. 2016-11-22 10:51:48 +05:00
0c0fcd5b24 First "sort by server name" implementation and button name fix.
First implementation of "Sort by server name" algo. Shitty, kinda
unreliable, but better than GTK's default.

Added Colorizer.Clear() func, which clears passed data from
colorcodes.

Fixed name on "Add to favorites" button.

Still cannot be successfully launched until some race conditions
will be fixed in go-gtk.
2016-11-22 09:48:19 +05:00
4d466a9d2b Servers sorting by ping and players count.
For now only on "Servers" tab, and REQUIRES custom go-gtk build
(see https://github.com/mattn/go-gtk/issues/290#issuecomment-262127956)
2016-11-22 07:36:27 +05:00
2cdee94efe Clipboard monitoring is here, so updating README. 2016-11-22 05:42:15 +05:00
2b1caac8f6 Fixed caching servers not updating profile to use in database. 2016-11-22 05:03:30 +05:00
862b336556 Windows-related build script and game launching fixes.
Fixed Windows build script to install gcc in MSYS2, which is
needed for some dependencies.

Fixed game launching on Windows, now ioq3 will search for game
data in proper directory.
2016-11-22 04:56:18 +05:00
90f888bdfb Toolbar icons is now (temporary) hardcoded. 2016-11-22 03:30:58 +05:00
a132ee0f7b Fixed icons loading and changed icons from svg to png. 2016-11-22 02:55:48 +05:00
8b06dff083 Forcing icons for servers lists. 2016-11-22 02:15:07 +05:00
ea8bdde224 Temporary disabled all modals on Linuxes due to mattn/go-gtk#289. 2016-11-22 01:10:31 +05:00
6495e90737 gdk_threads are deprecated, as well as glib_threads. 2016-11-21 03:32:22 +05:00
3e89df1009 Missing return definition for functions in prev commit. 2016-11-21 02:52:26 +05:00
c00ff2cea5 Check window position and size and hpane size in glib thread. 2016-11-21 02:49:05 +05:00
93d2bb7fc1 Reverting moving LockOSThread to main module. 2016-11-21 02:43:05 +05:00
0392f510f5 Moved runtime.LockOSThread() to urtrator.go. 2016-11-21 01:33:04 +05:00
57a5f7cb4c Bumping to beta4. Not tagging, as Windows fix is coming. 2016-11-21 01:19:06 +05:00
8a3f2a9a2e Stop updating servers if we're failed to connect to master server. 2016-11-04 19:37:50 +05:00
4e9a6ae970 GLib threads initialization. 2016-11-04 18:46:07 +05:00
7f80f99529 GTK actions fix WIP and icon size fix.
Again, possibly fixed GTK actions calls from other goroutines
by wrapping events calls in glib.IdleAdd(). This should prevent
executing more than one event simultaneously, which will also
prevent crashes.

Fixed icons sizing for couple of icons.
2016-11-04 18:28:52 +05:00
b1d38bbdcf Possibly solved crashes on GTK's actions. 2016-11-02 22:28:15 +05:00
e487b8521c Fixed clipboard watcher not watching after copying server's creds. 2016-10-13 02:40:27 +05:00
e12c76e424 Saving passwords for favorited private servers. 2016-10-12 23:26:43 +05:00
640020d23f Fixed server name putting into status label.
Some server's names (like Turnpike City) was tructating without
preserving Pango markup integrity. This commit fixes it.
2016-10-12 22:18:36 +05:00
a64c842e19 Messageboxes fixes and copy server's creds to clipboard.
Fixed all messageboxes that can use struct object as self name
(e.g. m for messageboxes in mainwindow). Should help to avoid some
errors.

Added possibility to copy server's credentials into clipboard
for ease of sharing.
2016-10-12 19:23:10 +05:00
1330699f41 Favorites servers and profiles fix.
If favorite server for some reason have no profile defined - pop up
an error message and do nothing.
2016-10-11 20:07:10 +05:00
a97b041679 Improved clipboard watching mechanism.
And it will look only within first string in clipboard.
2016-10-11 19:49:02 +05:00
68bd842c1f First variant of clipboard watching. 2016-10-11 13:14:08 +05:00
9be55c982e Beta3 is here. 2016-10-11 00:18:10 +05:00
35097c3805 Changed order for applying OS-specific workarounds. 2016-10-11 00:14:37 +05:00
3537b05dce Moved windows actions to mainwindow_init_win.go. 2016-10-11 00:14:00 +05:00
56c0d2787a Mac GTK+2 theme initialization fix. 2016-10-10 21:19:04 +05:00
f8b29a03d3 Added initial Windows build script. 2016-10-10 21:09:05 +05:00
eaaa8b565f Windows: import fixes. 2016-10-10 20:21:10 +05:00
e817a8fe64 Windows theming with default theme. 2016-10-10 20:18:59 +05:00
1a15c6cd4d Added Windows-related initialization things. 2016-10-10 20:11:41 +05:00
2746e0e315 Options window tabs moved to left. 2016-10-10 19:22:21 +05:00
2784586f8d More Mac integration works - now it is able to load and use GTK+
themes. Configuration interface on ToDo.

This also indicates that URTrator is now able to perform basic
window theming.
2016-10-10 19:16:51 +05:00
25dfa5072b Add "-a" to macOS's open command.
On my machine this prevents terminal window to be opened.
2016-10-09 21:27:17 +05:00
45 changed files with 3128 additions and 327 deletions

View File

@@ -2,6 +2,8 @@
[![Join the chat at https://gitter.im/urtrator/Lobby](https://badges.gitter.im/urtrator/Lobby.svg)](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).
![Main Window](/doc/screenshots/0.1-main_window.png)
URTrator is a desktop application that should (eventually) replace
@@ -25,6 +27,7 @@ the game.
* Favorites servers.
* Updating single server.
* Showing information about servers (like in UrT Connector).
* Clipboard monitoring.
Planning:
@@ -35,11 +38,15 @@ Planning:
* All kinds of notifications.
* Extended profile editor, so every profile could have own configuration
files, etc.
* Clipboard monitoring.
* ...maybe more :)
# Installation
## Precautions
Due to Go's GC bugs, it is required to use devel version of Go
compiler!
## Release
You don't need to install anything, thanks to Go's.

View File

@@ -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].Name = s.Server.Name
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].Ping = s.Server.Ping
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].Favorite = s.Server.Favorite
new_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
new_servers[mapping_item_name].Password = s.Server.Password
} else {
cached_servers[mapping_item_name].Ip = s.Server.Ip
cached_servers[mapping_item_name].Port = s.Server.Port
cached_servers[mapping_item_name].Name = s.Server.Name
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].Ping = s.Server.Ping
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].Favorite = s.Server.Favorite
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...")
if len(new_servers) > 0 {
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...")
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 {
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.Port = server.Port
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.Ping = server.Ping
c.Servers[key].Server.Gamemode = server.Gamemode

View 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})
}
}

View 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
}

View File

@@ -21,8 +21,28 @@ type Colorizer struct {
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 {
result := ""
var result string = ""
data = html.EscapeString(data)

View File

@@ -10,5 +10,11 @@
package common
const (
URTRATOR_VERSION = "0.1-beta2"
URTRATOR_VERSION = "0.1.1"
)
// Self-named.
var SUPPORTED_URT_VERSIONS []string = []string{
"4.2.023",
"4.3.1",
}

View 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
View 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 = `iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kFHAI2InQyhO8AAAV3SURBVFjD5ZdZbFRVGMd/39xZOp1BZkoLtsNUizUEaQNFTXzQB02Me3xQRGIgIQrRxAcNPvDkgy/GhLhEjQqRfQnGaNwNiYlFExTagiCiggLODEJBwdJZ7r1zz/Hh3lnbTovRJ+9k7llyc/7/b/8O/N8fqd/Y+c72ZSL6TaV0M2jQ7r4uf1G/565FsH2G/5SjnM+07Xt+2bJlv/8jRjt3bbtk2Za+3CebG9Vnzmb013v7ze27tmS37dz4+FTw/PUbSjnRgD/A8PkzroRao7VGa+WNoLw5WpfnIoIPHwt6FwU72juCA/v3rd22Y/ONjyxd/piI6CkT0LqkX11eu7+KCYRqEwgIKK2xHZPM7ynmXN0NQmRoYHDJ1h2bIlrrpROR8E1EQOnS3JW0agABLR62i48APhFyuVF84mNm6yzm9/ZEmpqa7t26fePLl60BjQIN6XQa0zQrOvDM4GqmtHbNYPj9KOVgF238RpCW+Ax6e3sjg/sHH924ZX3/iuUr37sME7jz2YlEGbwEqj2/kNIaXd7LjmY5eGiIbDZLIZ8nHo9zXc/8yHcHD67/afG9e9sOH79VRPwx294lx4+bE2vAU38qncG0zCqfKPFzNeG9ygRsy0Z5a6UU6XSGrq4u2qKRUPTk2YF8W9v0YCCgL5w/vxpY0NAJtUAi0eFZuKyHEmYVcF2m0BrHUViWSTabJXfuLKkff4789OD9kWv+vEhfopNpGzZcOzJ37twGPqBBC+l0BssyK8fr+u8mfkLBIK2xZvZ9MUBb9zweuv0OdmxYTyh1ipts25cLhdINCICgSSQSpUirUf+4abT+LCvHD5vWMDPWxfDwb3zw/rtczFucM0RrpR648siR7NhEVO2EQDqTwbZMF1yqQSeBLxaY9ulqehIzaO9zGE7tY9vpRUTDBsb5S5tbjh79pHEU4MZ4cnYCEBeu8qrAy1gyyspzcd3DxBIzaO/rJZs5ic75CdsXaCpcXP/IK2+vmjQMRQQRSKcz2JbFGNllAg0UTcIfP03blbEy+OhogHNDe4gkO1nxXAW8IQGfuGkumUwiUpK6YgNhfMkvrFvCFe1x2hdVwIcH93DVqk3s+ebXyTNhydPE52bpTDqDaVklI9T5QRWHokXoo6dobZvmgp8+wehoiOHBfuJLXiTWdx9678tTqIZVJgBIJpMeqFRGzwQlbGUX+OOtJURmTadjUU8NeMvitYR77xrjX5P7gAeYSWWwbKuGFEjZBcSxCO5eQyxq0NE3n1zmBKPZJoYH+9G3rSG84J667DpVAl6ZS3ZW+UDdCELhu+0YC6+ndVaM7C8DZPNhzg31E7rrWYx5dzIycolwuKnGvFMngBsFlm15JVeqnMBdzfrrGPG+pUj7QvLHnuD0tx+S6V6KVUww/dQpuru7EfF5zc5lECiR6OxMllUuXgMgHoGjB75i6+5DPNl1MyM/fkzu0p+M9K1k+nV3E41GicVjhMNhAsFguVhNTkBVa0BIpVLYll3uPkQqeeC1l17g8y+HuOX6+TS3zEH3PsnMeIJINEJzuBmlFWiNbduYpolt2wABL9MrQDXUAEI5D1Sk9wwhwlNrnuO1TQvdqqEVSrkl2HEcikUbx1Hlc4rFIo7jABgeOIBuTEA3Tvlze25AEK9yGijldUaGO/cHvD5OhFAohM/NLZZ3sp6kJXOroSsdILpSEUVqPdrrDQ3DqKmWVLVtgUCgREA1akqjlTxQHXYTJd+a6wk1/bOudNK6VrjIRE7YBMQRcvlCvrkl3vqvXsEKhQI+w5cDpnlmsMc1wdDggbWvv/HqM2jdPF72Gi+UxtsbeweU3PeHj6yd7G4Y9f4BIPgv30NNT/Ks92/Y1hj/0WXYqd/4GwuRPIP1EzlKAAAAAElFTkSuQmCC`
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`

View File

@@ -16,6 +16,7 @@ import (
// local
"github.com/pztrn/urtrator/cache"
"github.com/pztrn/urtrator/clipboardwatcher"
"github.com/pztrn/urtrator/colorizer"
"github.com/pztrn/urtrator/configuration"
"github.com/pztrn/urtrator/database"
@@ -30,6 +31,8 @@ import (
type Context struct {
// Caching.
Cache *cache.Cache
// Clipboard watcher.
Clipboard *clipboardwatcher.ClipboardWatcher
// Colors parser and prettifier.
Colorizer *colorizer.Colorizer
// Configuration.
@@ -65,6 +68,11 @@ func (ctx *Context) initializeCache() {
ctx.Cache.Initialize()
}
func (ctx *Context) InitializeClipboardWatcher() {
ctx.Clipboard = clipboardwatcher.New(ctx.Cache, ctx.Eventer)
ctx.Clipboard.Initialize()
}
func (ctx *Context) initializeColorizer() {
ctx.Colorizer = colorizer.New()
ctx.Colorizer.Initialize()

View File

@@ -48,6 +48,7 @@ func migrate_full(db *Database, version int) {
if version == 6 {six_to_seven(db); version = 7}
if version == 7 {seven_to_eight(db); version = 8}
if version == 8 {eight_to_nine(db); version = 9}
if version == 9 {nine_to_ten(db); version = 10}
}
// 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("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")
}

View File

@@ -18,6 +18,8 @@ type Server struct {
Name string `db:"name"`
// Current players count
Players string `db:"players"`
// Bots count
Bots string `db:"bots"`
// Maximum players
Maxplayers string `db:"maxplayers"`
// Ping

View File

@@ -12,9 +12,19 @@ brew install go
* Install GTK+2:
```
brew install gtk+
brew install gtk+ --with-quartz-relocation
```
*Note: default GTK+2 build from Brew might not work for you!*
* Reinstall gdk-pixbuf with additional option:
```
brew install --with-relocations
```
*Note: default build might not work for you!*
* Install dylibbundler:
```
@@ -23,3 +33,13 @@ brew install dylibbundler
* Execute ``make-app.sh`` script from current directory. If everything
went fine - you will see URTrator.app right in this directory.
# Some descriptions
## Resources
This directory will be copied inside bundle. It contains resources needed
for proper working or/and launching.
Of course, it *might* be able to work without this directory, but it will
be superugly.

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

View File

@@ -0,0 +1,498 @@
# Author: perfectska04 (Victor C.)
# Theme: Clearlooks-Colors for Ubuntu Hardy/Gnome 2.22 or equivalent.
# Description: Clearlooks-Colors is 100% free and open source.
# NOTE: Uncommenting means to delete the "#" at the beginning of a line. Commenting means to add a "#" at the beginning of a line. The "#" tells the theme wether to ignore the specified line or not.
# These are the defined colors for the theme, you can change them in GNOME's appearance preferences.
gtk_color_scheme = "fg_color:#101010\nbg_color:#EBEBEB\nbase_color:#fff\ntext_color:#1A1A1A\nselected_bg_color:#729FCF\nselected_fg_color:#1A1A1A\ntooltip_bg_color:#F5F5B5\ntooltip_fg_color:#000"
#########
# ICONS
#########
gtk-icon-sizes = "gtk-button=16,16" # This makes button icons smaller.
#gtk-icon-sizes = "gtk-large-toolbar=16,16:gtk-small-toolbar=16,16:panel-menu=16,16:gtk-button=16,16" # This enables "compact-mode".
#gtk-button-images = 0 # Enables or disables icons on buttons (OS X-like).
#gtk-menu-popup-delay = 1 # Makes menus pop up faster! Set to 1 instead of 0 to avoid Banshee 1 bug.
##########
# PANELS
##########
include "./panel.rc" # This includes the file that handles panel theming. Gradient panel backgrounds are enabled by default for this setting. Please edit panel.rc if you don't want gradient backgrounds in your panels, or plan to use transparent/custom panels.
# The following lines make panel-menu-applet and gimmie applet's text bold.
style "bold-panel-menu"
{
font_name = "Bold"
}
widget "*Panel*slab-main-menu-panel-button*" style "bold-panel-menu"
widget "*Panel*MenuBar*" style "bold-panel-menu"
widget "*gimmie*" style "bold-panel-menu"
##########################
# GENERAL THEME SETTINGS
##########################
style "clearlooks-default"
{
GtkButton ::child-displacement-x = 0 # Pressed button icon displacement.
GtkButton ::child-displacement-y = 1 # Pressed button icon displacement.
GtkButton ::default-border = { 0, 0, 0, 0 }
GtkCheckButton ::indicator-size = 14 # Size for check buttons.
GtkRadioButton ::indicator-size = 14 # Size for radio buttons.
GtkPaned ::handle-size = 6 # Width of handles.
GtkRange ::trough-border = 0
GtkRange ::slider-width = 15
GtkRange ::stepper-size = 15
GtkScale ::slider-length = 24 # Length of sliders.
GtkScale ::trough-side-details = 1
GtkScrollbar ::min-slider-length = 30 # Min. length of scrollbars.
GtkMenuBar ::internal-padding = 0
GtkExpander ::expander-size = 16
GtkToolbar ::internal-padding = 1 # Toolbar padding.
GtkTreeView ::expander-size = 14
GtkTreeView ::vertical-separator = 0
GtkMenu ::horizontal-padding = 0
GtkMenu ::vertical-padding = 0
WnckTasklist ::fade-overlay-rect = 0
# GtkButton ::focus-padding = 0 # This can give you a more compact appearance.
GtkScrolledWindow ::scrollbar-spacing = 2 # This sets the spacing between scrollbars.
GtkTreeView::odd_row_color = mix(0.98, shade (0.93,@base_color), @selected_bg_color) # This sets the color for odd row items.
GtkEntry::honors-transparent-bg-hint = 1
# Uncomment one or both of the following for flat/unified menus or toolbars:
# GtkToolbar ::shadow-type = GTK_SHADOW_NONE # Makes toolbars flat and unified.
# GtkMenuBar ::shadow-type = GTK_SHADOW_NONE # Makes menus flat and unified.
xthickness = 1
ythickness = 1
fg[NORMAL] = @fg_color
fg[PRELIGHT] = @fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @fg_color
fg[INSENSITIVE] = darker (@bg_color)
bg[NORMAL] = @bg_color
bg[PRELIGHT] = shade (1.02, @bg_color)
bg[SELECTED] = @selected_bg_color # Color for selected items.
bg[INSENSITIVE] = @bg_color
bg[ACTIVE] = shade (0.90, @bg_color)
base[NORMAL] = @base_color
base[PRELIGHT] = shade (0.95, @bg_color)
base[ACTIVE] = shade (0.90, @bg_color)
base[SELECTED] = shade (1.25, @selected_bg_color) # Color for selected base items.
base[INSENSITIVE] = @bg_color
text[NORMAL] = @text_color
text[PRELIGHT] = @text_color
text[ACTIVE] = @selected_fg_color
text[SELECTED] = @selected_fg_color
text[INSENSITIVE] = darker (@bg_color)
engine "clearlooks"
{
reliefstyle = 1 # 0 makes buttons/widgets less raised.
menubarstyle = 2 # Gradient menubar, use tweak in line 66 for flat menubars.
toolbarstyle = 0 # 0 makes bad toolbars flat.
animation = TRUE # FALSE disables progressbar animations.
style = GUMMY # Could also be set to GLOSSY.
radius = 2.0 # Roundness of widgets.
hint = "use-hints" # Set a hint to disable backward compatibility fallbacks.
}
}
#################
# THEME MODULES
#################
style "evolution-hack" = "clearlooks-default" # Hacks for Evolution Mail.
{
bg[NORMAL] = shade (1.04, @bg_color) # Color for evo treeview headers.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for evo treeview header prelight.
bg[ACTIVE] = shade (0.90, @bg_color) # Color for unfocused evo selected items.
bg[SELECTED] = shade (1.25, @selected_bg_color) # Color for evo selected items.
fg[ACTIVE] = @selected_fg_color # Color for evo active text.
fg[SELECTED] = @selected_fg_color # Color for evo selected text.
}
style "clearlooks-wide"
{
xthickness = 2 # Can't change, or clowns will eat you.
ythickness = 2 # Can't change, or clowns will eat you.
}
style "clearlooks-wider"
{
xthickness = 3 # Can't change, or clowns will eat you.
ythickness = 3 # Can't change, or clowns will eat you.
}
style "clearlooks-button" = "clearlooks-wider"
{
bg[NORMAL] = shade (1.04, @bg_color) # Color for buttons.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for button-prelight.
bg[ACTIVE] = shade (0.85, @bg_color) # Color for pressed-buttons.
}
style "clearlooks-notebook-bg"
{
bg[NORMAL] = shade (1.04, @bg_color) # Tab background.
bg[ACTIVE] = shade (0.94, @bg_color) # Unfocused tab background.
}
style "clearlooks-notebook" = "clearlooks-notebook-bg"
{
xthickness = 3 # Width of tabs and notebook borders.
ythickness = 3 # Height of tabs and notebook borders.
}
style "clearlooks-menu" = "clearlooks-wider"
{
bg[NORMAL] = shade (1.05, @bg_color) # Color of menu background.
engine "clearlooks"
{
radius = 1.0 # Roundness of menu items.
}
}
style "clearlooks-menu-item" = "clearlooks-wider"
{
fg[PRELIGHT] = @selected_fg_color # Color of selected menu item text.
bg[SELECTED] = shade (1.25, @selected_bg_color) # Color of menu items.
bg[PRELIGHT] = shade (1.25, @selected_bg_color) # Color of menu items.
}
style "clearlooks-separator-menu-item"
{
xthickness = 1
ythickness = 2
# Code for pixmap menu separators.
engine "pixmap"
{
image
{
function = HLINE
recolorable = TRUE
file = "Menu-Menubar/menu-line.png"
border = { 1, 1, 1, 1 }
stretch = TRUE
}
}
}
style "clearlooks-menubar"
{
engine "clearlooks"
{
hint = "menubar"
}
}
style "clearlooks-treeview"
{
bg[SELECTED] = shade (1.25, @selected_bg_color) # Color workaround for Banshee 1.0.
engine "clearlooks"
{
hint = "treeview"
radius = 0.0 # This makes treeview progressbars square.
}
}
style "clearlooks-treeview-header" = "clearlooks-default"
{
xthickness = 2
ythickness = 1
bg[NORMAL] = shade (1.04, @bg_color) # Color for treeview headers.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for treeview header prelight.
bg[ACTIVE] = shade (0.85, @bg_color) # Color for pressed-treeview.
engine "clearlooks" {
hint = "treeview-header"
}
}
style "clearlooks-frame-title"
{
fg[NORMAL] = lighter (@fg_color)
}
style "clearlooks-tooltips" = "clearlooks-wider"
{
bg[NORMAL] = @tooltip_bg_color
fg[NORMAL] = @tooltip_fg_color
}
style "metacity-frame" = "clearlooks-default"
{
# bg[SELECTED] = @selected_bg_color # Color for metacity borders.
}
style "clearlooks-progressbar"
{
xthickness = 1
ythickness = 1
fg[PRELIGHT] = @base_color # Progressbar prelighted text.
engine "clearlooks"
{
radius = 1.0 # Roundness of progressbars.
hint = "progressbar"
}
}
style "clearlooks-statusbar"
{
engine "clearlooks"
{
hint = "statusbar"
}
}
style "clearlooks-comboboxentry"
{
engine "clearlooks"
{
hint = "comboboxentry"
}
}
style "clearlooks-spinbutton"
{
bg[NORMAL] = shade (1.04, @bg_color) # Color for spinbuttons.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for spinbutton prelight.
bg[ACTIVE] = shade (0.85, @bg_color) # Color for pressed-spinbuttons.
engine "clearlooks"
{
hint = "spinbutton"
}
}
style "clearlooks-scale" = "clearlooks-button"
{
bg[NORMAL] = shade (1.04, @bg_color) # Color for sliders.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for slider prelight.
bg[ACTIVE] = shade (0.85, @bg_color) # Color for pressed-sliders.
engine "clearlooks"
{
hint = "scale"
}
}
style "clearlooks-hscale" = "clearlooks-scale"
{
engine "clearlooks"
{
hint = "hscale"
}
}
style "clearlooks-vscale" = "clearlooks-scale"
{
engine "clearlooks"
{
hint = "vscale"
}
}
style "clearlooks-nautilus-location" # Workaround for nautilus' messages.
{
bg[NORMAL] = shade (1.25, @selected_bg_color)
}
style "clearlooks-radiocheck" = "clearlooks-default"
{
# text[NORMAL] = shade (0.9, @selected_bg_color) # Color for checks/radio items.
# bg[SELECTED] = lighter (@selected_bg_color) # Color for prelight of check/radio buttons.
}
##############
# SCROLLBARS
##############
style "clearlooks-scrollbar"
{
bg[NORMAL] = shade (1.04, @bg_color) # Color for non-colored scrollbars.
bg[PRELIGHT] = shade (1.08, @bg_color) # Color for scrollbar prelight? (probably obsolete)
bg[ACTIVE] = shade (0.85, @bg_color) # Color for pressed scrollbar buttons.
# bg[SELECTED] = @selected_bg_color # You can change the color of colorized scrollbars here.
engine "clearlooks"
{
# colorize_scrollbar = TRUE # Uncommenting this gives you colorful scrollbars.
radius = 1.0 # Roundness of scrollbars.
hint = "scrollbar"
}
}
style "clearlooks-hscrollbar" = "clearlooks-scrollbar"
{
engine "clearlooks"
{
hint = "hscrollbar"
}
}
style "clearlooks-vscrollbar" = "clearlooks-scrollbar"
{
engine "clearlooks"
{
hint = "vscrollbar"
}
}
############
# TOOLBARS
############
#Gradient toolbars are enabled for this theme.
style "clearlooks-toolbar" = "clearlooks-default"
{
bg[NORMAL] = shade (0.965, @bg_color) # Darkens gradient toolbars to match with unified metacity theme.
engine "clearlooks"
{
toolbarstyle = 1 # This forces gradient toolbars.
}
}
style "clearlooks-evo-new-button-workaround"
{
bg[NORMAL] = shade (0.965, @bg_color)
engine "clearlooks"
{
toolbarstyle = 0
}
}
widget_class "EShellWindow.GtkVBox.BonoboDock.BonoboDockBand.BonoboDockItem*" style "clearlooks-evo-new-button-workaround"
class "GtkHandleBox" style "clearlooks-toolbar"
#########################################
# Matches
#########################################
# Clearlooks default style is applied to every widget.
class "GtkWidget" style "clearlooks-default"
# Increase the x/ythickness in some widgets.
class "GtkToolbar" style "clearlooks-toolbar"
class "GtkFrame" style "clearlooks-wide"
class "GtkEntry" style "clearlooks-wider"
class "MetaFrames" style "metacity-frame"
class "GtkSeparator" style "clearlooks-wide"
class "GtkWindow" style "metacity-frame"
class "GtkCalendar" style "clearlooks-wide"
class "GtkSpinButton" style "clearlooks-spinbutton"
class "GtkScale" style "clearlooks-scale"
class "GtkVScale" style "clearlooks-vscale"
class "GtkHScale" style "clearlooks-hscale"
class "GtkScrollbar" style "clearlooks-scrollbar"
class "GtkVScrollbar" style "clearlooks-vscrollbar"
class "GtkHScrollbar" style "clearlooks-hscrollbar"
class "GtkRadio*" style "clearlooks-radiocheck"
class "GtkCheck*" style "clearlooks-radiocheck"
# General matching following, the order is choosen so that the right styles override each other eg. progressbar needs to be more important then the menu match.
# This is not perfect, it could be done better (That is modify *every* widget in the notebook, and change those back that we really don't want changed)
widget_class "*<GtkNotebook>*<GtkEventBox>" style "clearlooks-notebook-bg"
widget_class "*<GtkNotebook>*<GtkDrawingArea>" style "clearlooks-notebook-bg"
widget_class "*<GtkNotebook>*<GtkLayout>" style "clearlooks-notebook-bg"
widget_class "*.GtkNotebook.*.GtkViewport" style "clearlooks-notebook"
widget_class "*<GtkButton>" style "clearlooks-button"
widget_class "*<GtkNotebook>" style "clearlooks-notebook"
widget_class "*<GtkStatusbar>*" style "clearlooks-statusbar"
widget_class "*<GtkComboBoxEntry>*" style "clearlooks-comboboxentry"
widget_class "*<GtkCombo>*" style "clearlooks-comboboxentry"
widget_class "*<GtkMenuBar>*" style "clearlooks-menubar"
widget_class "*<GtkMenu>*" style "clearlooks-menu"
widget_class "*<GtkMenuItem>*" style "clearlooks-menu-item"
widget_class "*<GtkSeparatorMenuItem>*" style "clearlooks-separator-menu-item"
widget_class "*.<GtkFrame>.<GtkLabel>" style "clearlooks-frame-title"
widget_class "*.<GtkTreeView>*" style "clearlooks-treeview"
widget_class "*<GtkProgressBar>" style "clearlooks-progressbar"
# Treeview header
widget_class "*.<GtkTreeView>.<GtkButton>" style "clearlooks-treeview-header"
widget_class "*.<GtkCTree>.<GtkButton>" style "clearlooks-treeview-header"
widget_class "*.<GtkList>.<GtkButton>" style "clearlooks-treeview-header"
widget_class "*.<GtkCList>.<GtkButton>" style "clearlooks-treeview-header"
# Workarounds for Evolution
widget_class "*.ETable.ECanvas" style "clearlooks-treeview-header"
widget_class "*.ETree.ECanvas" style "clearlooks-treeview-header"
widget_class "*GtkCTree*" style "evolution-hack"
widget_class "*GtkList*" style "evolution-hack"
widget_class "*GtkCList*" style "evolution-hack"
widget_class "*.ETree.*" style "evolution-hack"
widget_class "*EInfoLabel*" style "evolution-hack"
# The window of the tooltip is called "gtk-tooltip"
################################
# FIXME:
# This will not work if one embeds eg. a button into the tooltip.
# As far as I can tell right now we will need to rework the theme
# quite a bit to get this working correctly.
# (It will involve setting different priorities, etc.)
################################
widget "gtk-tooltip*" style "clearlooks-tooltips"
###################################################
# SPECIAL CASES AND WORKAROUNDS
###################################################
# Special case the nautilus-extra-view-widget
# ToDo: A more generic approach for all applications that have a widget like this.
widget "*.nautilus-extra-view-widget" style : highest "clearlooks-nautilus-location"
# Work around for http://bugzilla.gnome.org/show_bug.cgi?id=382646
# Note that the work around assumes that the combobox is _not_ in appears-as-list mode.
# This style does not affect GtkComboBoxEntry, it does have an effect on comboboxes in appears-as-list mode though.
style "clearlooks-text-is-fg-color-workaround"
{
text[NORMAL] = @fg_color
text[PRELIGHT] = @fg_color
text[SELECTED] = @selected_fg_color
text[ACTIVE] = @fg_color
text[INSENSITIVE] = darker (@bg_color)
}
widget_class "*.<GtkComboBox>.<GtkCellView>" style "clearlooks-text-is-fg-color-workaround"
style "clearlooks-menuitem-text-is-fg-color-workaround"
{
text[NORMAL] = @fg_color
text[PRELIGHT] = @selected_fg_color
text[SELECTED] = @selected_fg_color
text[ACTIVE] = @fg_color
text[INSENSITIVE] = darker (@bg_color)
}
widget "*.gtk-combobox-popup-menu.*" style "clearlooks-menuitem-text-is-fg-color-workaround"
# Work around the usage of GtkLabel inside GtkListItems to display text.
# This breaks because the label is shown on a background that is based on the base color set.
style "clearlooks-fg-is-text-color-workaround"
{
fg[NORMAL] = @text_color
fg[PRELIGHT] = @text_color
fg[ACTIVE] = @selected_fg_color
fg[SELECTED] = @selected_fg_color
fg[INSENSITIVE] = darker (@bg_color)
}
widget_class "*<GtkListItem>*" style "clearlooks-fg-is-text-color-workaround"
# The same problem also exists for GtkCList and GtkCTree.
# Only match GtkCList and not the parent widgets, because that would also change the headers.
widget_class "*<GtkCList>" style "clearlooks-fg-is-text-color-workaround"
widget_class "*<EelEditableLabel>" style "clearlooks-fg-is-text-color-workaround"
# The answer to the ultimate question of life, the universe, and everything is 42.

View File

@@ -0,0 +1,53 @@
################################################
# PANELS
################################################
# Note: Uncommenting means to delete the "#" at the beginning of a line. Commenting out means to add a "#" at the beginning of a line. The "#" tells the theme wether to ignore the line or not.
style "theme-panel"
{
# The following two lines add gradient panel backgrounds. You may choose only one! Delete or comment out both to have regular, flat gnome-panels.
bg_pixmap[NORMAL] = "/Panels/panel-bg.png" # Light gradient panel.
#bg_pixmap[NORMAL] = "/Panels/panel-bg-dark.png" # Dark gradient panel.
# Uncomment the following lines when using dark panels! Note: Menus will remain the same.
# bg[SELECTED] = "#525252" # Makes selected items dark.
# bg[NORMAL] = "#3c3c3c" # Makes panel background dark.
# bg[PRELIGHT] = "#424242" # Makes panel button prelight dark.
# bg[ACTIVE] = "#333333" # Makes active buttons dark.
# bg[INSENSITIVE] = "#3C3C3C"
# fg[NORMAL] = "#D4D4D4" # Makes panel text light.
# fg[PRELIGHT] = lighter (@selected_bg_color) # Makes prelighted text colored.
# fg[SELECTED] = lighter (@selected_bg_color) # Makes prelighted text colored.
# fg[ACTIVE] = lighter (@selected_bg_color) # Makes active text colored.
# fg[INSENSITIVE] = "#666666" # Color for insensitive text.
# text[NORMAL] = @text_color
# text[PRELIGHT] = lighter (@selected_bg_color) # Makes prelighted text colored.
# text[SELECTED] = lighter (@selected_bg_color) # Makes prelighted text colored.
# text[ACTIVE] = lighter (@selected_bg_color) # Makes active text colored.
# text[INSENSITIVE] = "#666666"
}
# Panel settings. Do not change.
widget "*PanelWidget*" style "theme-panel"
widget "*PanelApplet*" style "theme-panel"
widget "*fast-user-switch*" style "theme-panel"
widget "*CPUFreq*Applet*" style "theme-panel"
widget "*indicator-applet*" style "theme-panel"
class "PanelApp*" style "theme-panel"
class "PanelToplevel*" style "theme-panel"
widget_class "*PanelToplevel*" style "theme-panel"
widget_class "*Mail*" style "theme-panel"
#class "*Panel*" style "theme-panel" # Disabled to fix bug.
widget_class "*notif*" style "theme-panel"
widget_class "*Notif*" style "theme-panel"
widget_class "*Tray*" style "theme-panel"
widget_class "*tray*" style "theme-panel"
widget_class "*Applet*Tomboy*" style "theme-panel"
widget_class "*Applet*Netstatus*" style "theme-panel"
# XFCE panel theming.
widget "*Xfce*Panel*" style "theme-panel"
class "*Xfce*Panel*" style "theme-panel"

View File

@@ -0,0 +1,6 @@
[X-GNOME-Metatheme]
Name=Clearlooks Brave
Encoding=UTF-8
GtkTheme=Clearlooks Brave
MetacityTheme=Clearlooks-Colors Metacity
IconTheme=gnome-brave

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

View File

@@ -0,0 +1,799 @@
#OS X El Capitan v0.6
gtk-color-scheme = "bg_color:#e4e4e4\nfg_color:#4c4c4c\nbase_color:#fff\ntext_color:#4c4c4c\nselected_bg_color:#116cd6\nselected_fg_color:#ffffff\ntooltip_bg_color:#fff\ntooltip_fg_color:#4c4c4c\ntitlebar_bg_color:#e4e4e4\ntitlebar_fg_color:#4c4c4c\nmenubar_bg_color:#e4e4e4\nmenubar_fg_color:#4c4c4c\ntoolbar_bg_color:#e4e4e4\ntoolbar_fg_color:#4c4c4c\nmenu_bg_color:#F5F5F5\nmenu_fg_color:#4c4c4c\npanel_bg_color:#F5F5F5\npanel_fg_color:#4c4c4c\nlink_color:#D1EDFE"
# Default Style
style "murrine-default" {
GtkArrow::arrow-scaling= 0.6
GtkButton::child-displacement-x = 0
GtkButton::child-displacement-y = 0
GtkButton::default-border = { 0, 0, 0, 0 }
GtkButtonBox::child-min-height = 26
GtkCheckButton::indicator-size = 16
# The following line hints to gecko (and possibly other appliations)
# that the entry should be drawn transparently on the canvas.
# Without this, gecko will fill in the background of the entry.
GtkEntry::honors-transparent-bg-hint = 1
GtkEntry::state-hint = 0
GtkExpander::expander-size = 16
GtkImage::x-ayatana-indicator-dynamic = 1
GtkMenu::horizontal-padding = 0
GtkMenu::vertical-padding = 0
GtkMenuBar::internal-padding = 0
GtkMenuBar::window-dragging = 1
GtkMenuItem::arrow-scaling= 0.5
GtkPaned::handle-size = 1
GtkProgressBar::min-horizontal-bar-height = 4
GtkProgressBar::min-vertical-bar-width = 4
GtkRange::trough-border = 0
GtkRange::slider-width = 12
GtkRange::stepper-size = 12
GtkRange::stepper_spacing = 0
GtkRange::trough-under-steppers = 1
GtkScale::slider-length = 16
GtkScale::slider-width = 16
GtkScale::trough-side-details = 1
GtkScrollbar::activate-slider = 1
GtkScrollbar::has-backward-stepper = 0
GtkScrollbar::has-forward-stepper = 0
GtkScrollbar::has-secondary-backward-stepper = 0
GtkScrollbar::has-secondary-forward-stepper = 0
GtkScrollbar::min-slider-length = 80
GtkScrollbar::slider-width = 6
GtkScrollbar::trough-border = 3
GtkScrolledWindow::scrollbar-spacing = 0
GtkScrolledWindow::scrollbars-within-bevel = 1
GtkSeparatorMenuItem::horizontal-padding = 0
GtkToolbar::internal-padding = 0
GtkTreeView::expander-size = 11
GtkTreeView::vertical-separator = 0
GtkWidget::focus-line-width = 1
# The following line prevents the Firefox tabs
# from jumping a few pixels when you create a new tab
GtkWidget::focus-padding = 0
GtkWidget::wide-separators = 1
GtkWidget::separator-width = 1
GtkWidget::separator-height = 1
GtkWindow::resize-grip-height = 0
GtkWindow::resize-grip-width = 0
WnckTasklist::fade-overlay-rect = 0
GnomeHRef::link_color = @link_color
GtkHTML::link-color = @link_color
GtkIMHtmlr::hyperlink-color = @link_color
GtkIMHtml::hyperlink-color = @link_color
GtkWidget::link-color = @link_color
GtkWidget::visited-link-color = @text_color
GtkToolbar::shadow-type = GTK_SHADOW_NONE # Makes toolbars flat and unified
GtkMenuBar::shadow-type = GTK_SHADOW_NONE # Makes menubars flat and unified
xthickness = 1
ythickness = 1
fg[NORMAL] = @fg_color
fg[PRELIGHT] = @fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @fg_color
fg[INSENSITIVE] = mix (0.5, @bg_color, @fg_color)
bg[NORMAL] = @bg_color
bg[PRELIGHT] = shade (1.02, @bg_color)
bg[SELECTED] = @selected_bg_color
bg[ACTIVE] = shade (0.9, @bg_color)
bg[INSENSITIVE] = @bg_color
base[NORMAL] = @base_color
base[PRELIGHT] = shade (0.95, @base_color)
base[SELECTED] = @selected_bg_color
base[ACTIVE] = @selected_bg_color
base[INSENSITIVE] = shade (0.85, @base_color)
text[NORMAL] = @text_color
text[PRELIGHT] = @text_color
text[SELECTED] = @selected_fg_color
text[ACTIVE] = @selected_fg_color
text[INSENSITIVE] = mix (0.5, @base_color, @text_color)
engine "murrine" {
animation = TRUE
arrowstyle = 1 # 0 = normal arrows, 1 = filled arrows
border_shades = { 1.0, 1.0 } # gradient to draw on border
colorize_scrollbar = FALSE
comboboxstyle = 0 # 0 = normal combobox, 1 = colorized combobox below arrow
contrast = 0.8 # overal contrast with borders
default_button_color = @selected_bg_color
focusstyle = 3 # 0 = none, 1 = grey dotted, 2 = colored with fill, 3 = colored glow
glazestyle = 0 # 0 = flat highlight, 1 = curved highlight, 2 = concave, 3 = top curved highlight, 4 = beryl highlight
glowstyle = 0 # 0 = glow on top, 1 = glow on bottom, 2 = glow on top and bottom, 3 = glow on middle vertically, 4 = glow on middle horizontally, 5 = glow on all sides
glow_shade = 1.0 # amount of glow
gradient_shades = { 1.0, 1.0, 1.0, 1.0 } # gradient to draw on widgets
highlight_shade = 1.0 # amount of highlight
lightborder_shade = 1.0 # amount of inset light border
lightborderstyle = 1 # 0 = lightborder on top side, 1 = lightborder on all sides
listviewheaderstyle = 0 # 0 = flat, 1 = glassy, 2 = raised
listviewstyle = 0 # 0 = none, 1 = dotted, 2 = line
menubaritemstyle = 0 # 0 = menuitem look, 1 = button look
menubarstyle = 0 # 0 = flat, 1 = glassy, 2 = gradient, 3 = striped
menuitemstyle = 0 # 0 = flat, 1 = glassy, 2 = striped
menustyle = 0 # 0 = none, 1 = vertical striped
progressbarstyle = 0 # 0 = none, 1 = diagonal striped, 2 = vertical striped
reliefstyle = 0 # 0 = flat, 1 = inset, 2 = shadow, 3 = shadow with gradient, 4 = stronger shadow with gradient
roundness = 1 # roundness of widgets
scrollbarstyle = 0 # 0 = none, 1 = circles, 2 = handles, 3 = diagonal stripes, 4 = diagonal stripes and handles, 5 = horizontal stripes, 6 = horizontal stripes and handles
sliderstyle = 0 # 0 = none, 1 = handles
stepperstyle = 1 # 0 = standard, 1 = integrated stepper handles
toolbarstyle = 0 # 0 = flat, 1 = glassy, 2 = gradient
}
}
style "murrine-wide" {
xthickness = 2
ythickness = 2
}
style "murrine-wider" {
xthickness = 3
ythickness = 3
}
style "murrine-thin" {
xthickness = 0
ythickness = 0
}
# Notebook
style "murrine-notebook-bg" {
bg[NORMAL] = @bg_color
bg[ACTIVE] = shade (0.9, @bg_color)
}
style "murrine-notebook" = "murrine-notebook-bg" {
xthickness = 2
ythickness = 2
engine "murrine" {
roundness = 6
gradient_shades = {1.1,1.0,1.0,0.9}
}
}
# Various Standard Widgets
style "murrine-button" = "murrine-wider" {
bg[NORMAL] = shade (1.1, @bg_color)
bg[PRELIGHT] = @bg_color
bg[ACTIVE] = @selected_bg_color
bg[INSENSITIVE] = shade (0.85, @bg_color)
engine "murrine" {
contrast = .8
lightborder_shade = 1.9
roundness = 4
border_shades = {0.95, 0.8}
shadow_shades = {1.0, 0.1}
gradient_shades = {1.1,1.0,1.0,0.9}
}
}
style "murrine-scrollbar" {
bg[NORMAL] = mix (0.21, @fg_color, @bg_color)
bg[PRELIGHT] = mix (0.31, @fg_color, @bg_color)
bg[ACTIVE] = shade (0.8, @bg_color)
engine "murrine" {
roundness = 6
contrast = 0.0
border_shades = { 1.0, 1.0 }
trough_shades = { 1.0, 1.0 }
trough_border_shades = { 1.0, 1.0 }
}
}
style "murrine-overlay-scrollbar" {
bg[ACTIVE] = shade (0.8, @bg_color)
bg[INSENSITIVE] = shade (0.97, @bg_color)
base[SELECTED] = shade (0.6, @base_color)
base[INSENSITIVE] = shade (0.85, @base_color)
}
style "murrine-scale" = "murrine-thin" {
bg[NORMAL] = @bg_color
bg[ACTIVE] = @bg_color
bg[SELECTED] = @selected_bg_color
bg[INSENSITIVE] = shade (0.95, @bg_color)
engine "murrine" {
roundness = 6
gradient_shades = { 1.08, 1.08, 1.08, 1.08 }
border_shades = { 1.0, 1.0 }
trough_shades = { 1.08, 1.08 }
trough_border_shades = { 0.8, 0.8 }
}
}
style "murrine-progressbar" = "murrine-thin" {
bg[NORMAL] = @bg_color
bg[ACTIVE] = shade (1.08, @bg_color)
fg[PRELIGHT] = @selected_fg_color
engine "murrine" {
roundness = 8
border_shades = { 1.2, 1.2 }
trough_border_shades = { 0.8, 0.8 }
}
}
style "murrine-treeview-header" = "murrine-button" {
engine "murrine" {
roundness = 0
}
}
style "murrine-treeview" {
engine "murrine" {
roundness = 0
}
}
style "murrine-frame-title" {
fg[NORMAL] = lighter (@fg_color)
}
style "murrine-tooltips" {
xthickness = 5
ythickness = 5
bg[NORMAL] = @tooltip_bg_color
bg[SELECTED] = @tooltip_bg_color
fg[NORMAL] = @tooltip_fg_color
engine "murrine" {
textstyle = 0
roundness = 2
rgba = FALSE
}
}
style "murrine-spinbutton" = "murrine-button" {
engine "murrine" {
}
}
style "murrine-radiocheck" = "murrine-default" {
bg[NORMAL] = @base_color
bg[SELECTED] = @selected_bg_color
text[NORMAL] = @base_color
text[PRELIGHT] = @base_color
engine "murrine" {
reliefstyle = 0
gradient_shades = {1.2, 1.0, 1.0, 0.9}
shadow_shades = {0.6, 0.5}
textstyle = 0
}
}
style "murrine-entry" = "murrine-wider" {
engine "murrine" {
roundness = 6
border_shades = { 1.15, 1.15 }
}
}
style "metacity-frame" = "murrine-default" {
bg[SELECTED] = @selected_bg_color
}
style "murrine-statusbar" { }
style "murrine-comboboxentry" = "murrine-entry" { }
style "murrine-hscale" = "murrine-scale" { }
style "murrine-vscale" = "murrine-scale" { }
style "murrine-hscrollbar" = "murrine-scrollbar" { }
style "murrine-vscrollbar" = "murrine-scrollbar" { }
# Menus
style "murrine-menu" = "murrine-thin" {
bg[NORMAL] = @menu_bg_color
bg[PRELIGHT] = @selected_bg_color
bg[SELECTED] = @selected_bg_color
bg[ACTIVE] = @menu_bg_color
bg[INSENSITIVE] = @menu_bg_color
fg[NORMAL] = @menu_fg_color
fg[PRELIGHT] = @selected_fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @selected_fg_color
fg[INSENSITIVE] = mix (0.5, @menu_bg_color, @menu_fg_color)
text[NORMAL] = @menu_fg_color
text[PRELIGHT] = @selected_fg_color
text[SELECTED] = @selected_fg_color
text[ACTIVE] = @selected_fg_color
text[INSENSITIVE] = mix (0.5, @menu_bg_color, @menu_fg_color)
engine "murrine" {
roundness = 0
}
}
style "murrine-menu-item" = "murrine-wider" {
bg[PRELIGHT] = @selected_bg_color
bg[SELECTED] = @selected_bg_color
bg[ACTIVE] = @selected_bg_color
fg[NORMAL] = @menu_fg_color # Fix for XFCE menu text
fg[PRELIGHT] = @selected_fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @selected_fg_color
fg[INSENSITIVE] = mix (0.5, @menu_bg_color, @menu_fg_color)
engine "murrine" {
textstyle = 0
border_shades = { 1.2, 1.2 }
}
}
style "murrine-separator-menu-item" = "murrine-thin" { }
style "murrine-menubar" {
bg[NORMAL] = @menubar_bg_color
bg[PRELIGHT] = mix (0.21, @menubar_fg_color, @menubar_bg_color)
bg[SELECTED] = mix (0.21, @menubar_fg_color, @menubar_bg_color)
bg[ACTIVE] = shade (0.9, @menubar_bg_color)
bg[INSENSITIVE] = @menubar_bg_color
fg[NORMAL] = @menubar_fg_color
fg[PRELIGHT] = shade (1.08, @menubar_fg_color)
fg[SELECTED] = shade (1.08, @menubar_fg_color)
fg[ACTIVE] = @menubar_fg_color
fg[INSENSITIVE] = mix (0.5, @menubar_bg_color, @menubar_fg_color)
engine "murrine" {
roundness = 0
}
}
style "murrine-menubaritem" {
bg[NORMAL] = @menubar_bg_color
bg[PRELIGHT] = mix (0.21, @menubar_fg_color, @menubar_bg_color)
bg[SELECTED] = mix (0.21, @menubar_fg_color, @menubar_bg_color)
bg[ACTIVE] = shade (0.9, @menubar_bg_color)
bg[INSENSITIVE] = @menubar_bg_color
fg[NORMAL] = @menubar_fg_color
fg[PRELIGHT] = shade (1.08, @menubar_fg_color)
fg[SELECTED] = shade (1.08, @menubar_fg_color)
fg[ACTIVE] = @menubar_fg_color
fg[INSENSITIVE] = mix (0.5, @menubar_bg_color, @menubar_fg_color)
engine "murrine" {
roundness = 0
}
}
# Toolbars
style "murrine-toolbar" = "murrine-thin" {
bg[NORMAL] = @bg_color
bg[PRELIGHT] = shade (1.02, @bg_color)
bg[SELECTED] = @selected_bg_color
bg[ACTIVE] = shade (0.9, @bg_color)
bg[INSENSITIVE] = @bg_color
fg[NORMAL] = @fg_color
fg[PRELIGHT] = @fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @fg_color
fg[INSENSITIVE] = mix (0.5, @bg_color, @fg_color)
engine "murrine" {
}
}
style "murrine-toolbutton" = "murrine-button" {
bg[NORMAL] = shade (1.08, @bg_color)
bg[PRELIGHT] = shade (1.10, @bg_color)
bg[SELECTED] = @bg_color
bg[ACTIVE] = shade (0.95, @bg_color)
bg[INSENSITIVE] = shade (0.85, @bg_color)
fg[NORMAL] = @fg_color
fg[PRELIGHT] = @fg_color
fg[SELECTED] = @fg_color
fg[ACTIVE] = @fg_color
fg[INSENSITIVE] = mix (0.5, @bg_color, @fg_color)
engine "murrine" {
roundness = 6
}
}
class "GtkToolbar" style "murrine-toolbar"
class "GtkHandleBox" style "murrine-toolbar"
widget_class "*Toolbar*.*Separator*" style "murrine-toolbar"
# Panels
style "murrine-panel" = "murrine-thin" {
xthickness = 2
bg[NORMAL] = @panel_bg_color
bg[PRELIGHT] = mix (0.21, @panel_fg_color, @panel_bg_color)
bg[SELECTED] = mix (0.21, @panel_fg_color, @panel_bg_color)
bg[ACTIVE] = shade (0.8, @panel_bg_color)
bg[INSENSITIVE] = @panel_bg_color
fg[NORMAL] = @panel_fg_color
fg[PRELIGHT] = shade (1.08, @panel_fg_color)
fg[SELECTED] = shade (1.08, @panel_fg_color)
fg[ACTIVE] = @panel_fg_color
fg[INSENSITIVE] = mix (0.5, @panel_bg_color, @panel_fg_color)
base[NORMAL] = @panel_bg_color
base[PRELIGHT] = mix (0.21, @panel_fg_color, @panel_bg_color)
base[SELECTED] = mix (0.21, @panel_fg_color, @panel_bg_color)
base[ACTIVE] = shade (0.9, @panel_bg_color)
base[INSENSITIVE] = @panel_bg_color
text[NORMAL] = @panel_fg_color
text[PRELIGHT] = shade (1.08, @panel_fg_color)
text[SELECTED] = shade (1.08, @panel_fg_color)
text[ACTIVE] = @panel_fg_color
text[INSENSITIVE] = mix (0.5, @panel_bg_color, @panel_fg_color)
engine "murrine" {
roundness = 0
contrast = 0.0
}
}
widget "*PanelWidget*" style "murrine-panel"
widget "*PanelApplet*" style "murrine-panel"
widget "*fast-user-switch*" style "murrine-panel"
widget "*CPUFreq*Applet*" style "murrine-panel"
widget "*indicator-applet*" style "murrine-panel"
class "PanelApp*" style "murrine-panel"
class "PanelToplevel*" style "murrine-panel"
widget_class "*PanelToplevel*" style "murrine-panel"
widget_class "*notif*" style "murrine-panel"
widget_class "*Notif*" style "murrine-panel"
widget_class "*Tray*" style "murrine-panel"
widget_class "*tray*" style "murrine-panel"
widget_class "*computertemp*" style "murrine-panel"
widget_class "*Applet*Tomboy*" style "murrine-panel"
widget_class "*Applet*Netstatus*" style "murrine-panel"
widget "*gdm-user-switch-menubar*" style "murrine-panel"
style "bold-panel-item" {
font_name = "Bold"
engine "murrine" {
roundness = 0
}
}
widget "*Panel*MenuBar*" style "bold-panel-item"
widget "*gimmie*" style "bold-panel-item"
# widget_class "*Mail*" style "murrine-panel" # Disabled to fix Evolution bug
# class "*Panel*" style "murrine-panel" # Disabled to fix bug
# XFCE Styles
style "workspace-switcher" = "murrine-panel" {
bg[SELECTED] = @selected_bg_color
}
style "xfce-header" {
bg[NORMAL] = shade (0.9, @bg_color)
base[NORMAL] = shade (1.18, @bg_color)
}
style "xfdesktop-windowlist" {
bg[NORMAL] = @base_color
fg[INSENSITIVE] = shade (0.95, @base_color)
text[INSENSITIVE] = shade (0.95, @base_color)
}
style "xfdesktop-icon-view" {
XfdesktopIconView::label-alpha = 0
XfdesktopIconView::selected-label-alpha = 60
XfdesktopIconVIew::ellipsize-icon-labels = 1
base[NORMAL] = @selected_bg_color
base[SELECTED] = @selected_bg_color
base[ACTIVE] = @selected_bg_color
fg[NORMAL] = @selected_fg_color
fg[SELECTED] = @selected_fg_color
fg[ACTIVE] = @selected_fg_color
engine "murrine" {
textstyle = 5
text_shade = 0.05
}
}
style "xfwm-tabwin" {
Xfwm4TabwinWidget::border-width = 0
Xfwm4TabwinWidget::icon-size = 64
bg[NORMAL] = @menu_bg_color
fg[NORMAL] = @menu_fg_color
engine "murrine" {
focusstyle = 0
}
}
style "xfsm-logout" {
bg[NORMAL] = @menu_bg_color
bg[ACTIVE] = @menu_bg_color
bg[PRELIGHT] = shade (1.1, @menu_bg_color)
bg[SELECTED] = shade (0.5, @menu_bg_color)
bg[INSENSITIVE] = shade (1.3, @menu_bg_color)
fg[NORMAL] = @menu_fg_color
fg[PRELIGHT] = @menu_fg_color
text[NORMAL] = @menu_fg_color
engine "murrine" {
}
}
style "xfsm-logout-button" {
bg[NORMAL] = shade (1.2, @menu_bg_color)
bg[PRELIGHT] = shade (1.4, @menu_bg_color)
engine "murrine" {
}
}
widget "*WnckPager*" style "workspace-switcher"
widget "*Xfce*Panel*" style "murrine-panel"
class "*Xfce*Panel*" style "murrine-panel"
# Thunar Styles
style "sidepane" {
base[NORMAL] = @bg_color
base[INSENSITIVE] = mix (0.4, shade (1.35, @selected_bg_color), shade (0.9, @base_color))
bg[NORMAL] = @bg_color
text[NORMAL] = mix (0.9, @fg_color, @bg_color)
}
widget_class "*ThunarShortcutsView*" style "sidepane"
widget_class "*ThunarTreeView*" style "sidepane"
widget_class "*ThunarLocationEntry*" style "murrine-entry"
# Gtk2 Open-File Dialog
widget_class "*GtkFileChooserWidget.GtkFileChooserDefault.GtkVBox.GtkHPaned.GtkVBox.GtkScrolledWindow.GtkTreeView*" style "sidepane"
widget_class "*GtkFileChooserWidget.GtkFileChooserDefault.GtkVBox.GtkHPaned.GtkVBox.GtkScrolledWindow.<GtkTreeView>.<GtkButton>" style "murrine-treeview-header"
# Google Chrome/Chromium Styles (requires 9.0.597 or newer)
style "chromium-toolbar-button" {
engine "murrine" {
roundness = 4
textstyle = 0
}
}
style "chrome-gtk-frame" {
ChromeGtkFrame::frame-color = @titlebar_bg_color
ChromeGtkFrame::inactive-frame-color = @titlebar_bg_color
ChromeGtkFrame::frame-gradient-size = 0
ChromeGtkFrame::frame-gradient-color = @titlebar_bg_color
ChromeGtkFrame::incognito-frame-color = @titlebar_bg_color
ChromeGtkFrame::incognito-inactive-frame-color = @titlebar_bg_color
ChromeGtkFrame::incognito-frame-gradient-size = 0
ChromeGtkFrame::incognito-frame-gradient-color = @titlebar_bg_color
ChromeGtkFrame::scrollbar-trough-color = @bg_color
ChromeGtkFrame::scrollbar-slider-normal-color = mix (0.21, @fg_color, @bg_color)
ChromeGtkFrame::scrollbar-slider-prelight-color = mix (0.31, @fg_color, @bg_color)
}
class "ChromeGtkFrame" style "chrome-gtk-frame"
widget_class "*Chrom*Button*" style "chromium-toolbar-button"
# General Styles
class "GtkWidget" style "murrine-default"
class "GtkFrame" style "murrine-wide"
class "MetaFrames" style "metacity-frame"
class "GtkWindow" style "metacity-frame"
class "GtkSeparator" style "murrine-wide"
class "GtkCalendar" style "murrine-wide"
class "GtkSpinButton" style "murrine-spinbutton"
class "GtkScale" style "murrine-scale"
class "GtkVScale" style "murrine-vscale"
class "GtkHScale" style "murrine-hscale"
class "GtkScrollbar" style "murrine-scrollbar"
class "GtkVScrollbar" style "murrine-vscrollbar"
class "GtkHScrollbar" style "murrine-hscrollbar"
class "GtkRadio*" style "murrine-radiocheck"
class "GtkCheck*" style "murrine-radiocheck"
class "GtkEntry" style "murrine-entry"
widget_class "*<GtkNotebook>" style "murrine-notebook"
widget_class "*<GtkNotebook>*<GtkEventBox>" style "murrine-notebook-bg"
widget_class "*<GtkNotebook>*<GtkDrawingArea>" style "murrine-notebook-bg"
widget_class "*<GtkNotebook>*<GtkLayout>" style "murrine-notebook-bg"
widget_class "*.GtkNotebook.*.GtkViewport" style "murrine-notebook"
widget_class "*<GtkButton>" style "murrine-button"
widget_class "*<GtkStatusbar>*" style "murrine-statusbar"
widget_class "*<GtkProgress>" style "murrine-progressbar"
widget_class "*<GtkProgressBar>" style "murrine-progressbar"
widget_class "*<GtkComboBoxEntry>*" style "murrine-comboboxentry"
widget_class "*<GtkCombo>*" style "murrine-comboboxentry"
widget_class "*<GtkMenu>*" style "murrine-menu"
widget_class "*<GtkMenuItem>*" style "murrine-menu-item"
widget_class "*<GtkSeparatorMenuItem>*" style "murrine-separator-menu-item"
widget_class "*Menu*.*Sepa*" style "murrine-separator-menu-item"
widget_class "*<GtkMenuBar>*" style "murrine-menubar"
widget_class "*<GtkMenuBar>*<GtkMenuItem>*" style "murrine-menubaritem"
widget_class "*GtkToolButton*" style "murrine-toolbutton"
widget_class "*GtkToggleToolButton*" style "murrine-toolbutton"
widget_class "*GtkMenuToolButton*" style "murrine-toolbutton"
widget_class "*GtkToolbar*Button" style "murrine-toolbutton"
widget_class "*.<GtkFrame>.<GtkLabel>" style "murrine-frame-title"
widget_class "*.<GtkTreeView>*" style "murrine-treeview"
widget_class "*.<GtkTreeView>.<GtkButton>" style "murrine-treeview-header"
widget_class "*.<GtkCTree>.<GtkButton>" style "murrine-treeview-header"
widget_class "*.<GtkList>.<GtkButton>" style "murrine-treeview-header"
widget_class "*.<GtkCList>.<GtkButton>" style "murrine-treeview-header"
widget "gtk-tooltip*" style "murrine-tooltips"
widget_class "*<GtkScrolledWindow>*<OsScrollbar>" style "murrine-overlay-scrollbar"
# Workarounds and Non-Standard Styling
style "text-is-fg-color-workaround" {
text[NORMAL] = @text_color
text[PRELIGHT] = @fg_color
text[SELECTED] = @selected_fg_color
text[ACTIVE] = @fg_color
text[INSENSITIVE] = mix (0.5, @bg_color, @fg_color)
}
widget_class "*.<GtkComboBox>.<GtkCellView>" style "text-is-fg-color-workaround"
style "fg-is-text-color-workaround" {
fg[NORMAL] = @text_color
fg[PRELIGHT] = @text_color
fg[ACTIVE] = @selected_fg_color
fg[SELECTED] = @selected_fg_color
fg[INSENSITIVE] = darker (@fg_color)
}
widget_class "*<GtkListItem>*" style "fg-is-text-color-workaround"
widget_class "*<GtkCList>" style "fg-is-text-color-workaround"
widget_class "*<EelEditableLabel>" style "fg-is-text-color-workaround"
style "murrine-evo-new-button-workaround" {
engine "murrine" {
toolbarstyle = 0
}
}
widget_class "EShellWindow.GtkVBox.BonoboDock.BonoboDockBand.BonoboDockItem*" style "murrine-evo-new-button-workaround"
style "inkscape-toolbar-fix" {
engine "murrine" {
gradient_shades = { 1.0, 1.0, 1.0, 1.0 }
highlight_shade = 1.0
}
}
#widget "*GtkHandleBox*" style "inkscape-toolbar-fix"
#widget "*HandleBox*CommandsToolbar*" style "inkscape-toolbar-fix"
#widget "*HandleBox*SnapToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*SelectToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*NodeToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*TweakToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*ZoomToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*StarToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*RectToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*3DBoxToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*ArcToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*SpiralToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*PencilToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*PenToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*CalligraphyToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*EraserToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*LPEToolToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*DropperToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*ConnectorToolbar*" style "inkscape-toolbar-fix"
widget "*HandleBox*PaintbucketToolbar*" style "inkscape-toolbar-fix"
# Performance Fixes
style "performance-fix" {
engine "murrine" {
textstyle = 0
}
}
widget_class "*gtkmm__GtkWindow*" style "performance-fix" # Inkscape
widget_class "*GimpDisplayShell*" style "performance-fix" # Gimp
widget_class "*GimpToolbox*" style "performance-fix"
widget_class "*GimpMenuDock*" style "performance-fix"
widget "*OOoFixed*" style "performance-fix" # Openoffice/Libreoffice
widget_class "*MozContainer*" style "performance-fix" # Firefox (Not sure if this one does anything though.)
widget_class "*XfceHeading*" style "xfce-header"
widget_class "*XfceDesktop*" style "xfdesktop-windowlist"
widget_class "*XfdesktopIconView*" style "xfdesktop-icon-view"
widget "xfwm4-tabwin*" style "xfwm-tabwin"
widget_class "*XfsmLogoutDialog*" style "xfsm-logout"
widget_class "*XfsmLogoutDialog*GtkButton" style "xfsm-logout-button"
widget "*Panel*" style "panel"
widget "*PanelWidget*" style "panel"
widget "*PanelApplet*" style "panel"
widget "*fast-user-switch*" style "panel" # workaround for Fast User Switch applet
widget "*CPUFreqApplet*" style "panel" # workaround for CpuFreq Applet
class "PanelApp*" style "panel"
class "PanelToplevel*" style "panel"
#widget_class "*Mail*" style "panel"
widget_class "*notif*" style "panel"
#widget_class "*?anel*utton" style "panel_task_button" # causing problems to monodevelop
widget "*task*" style "panel_task_button"
widget "*.tasklist-button" style "panel_task_button"
widget "*PanelApplet*TaskTitle*" style "panel_task_button"
widget_class "*Xfce*Panel*" style "XFCE"
class "GtkScrollbar" style "murrine-scrollbar"

View File

@@ -0,0 +1,11 @@
[Desktop Entry]
Type=X-GNOME-Metatheme
Name=OS X El Capitan
Comment=A theme by Christian Medel (Elbullazul) simulating OS X 10.11 El Capitan
Comment=v0.5
Encoding=UTF-8
[X-GNOME-Metatheme]
GtkTheme=OS X El Capitan
MetacityTheme=OS X El Capitan
ButtonLayout=:minimize,maximize,close

View File

@@ -0,0 +1,2 @@
include "ClearlooksBrave/gtk-2.0/gtkrc"
include "gtkrc-keybindings"

View File

@@ -0,0 +1,157 @@
gtk-enable-mnemonics = 0
binding "gtk-mac-alt-arrows"
{
bind "<alt>Right" { "move-cursor" (words, 1, 0) }
bind "<alt>KP_Right" { "move-cursor" (words, 1, 0) }
bind "<alt>Left" { "move-cursor" (words, -1, 0) }
bind "<alt>KP_Left" { "move-cursor" (words, -1, 0) }
bind "<shift><alt>Right" { "move-cursor" (words, 1, 1) }
bind "<shift><alt>KP_Right" { "move-cursor" (words, 1, 1) }
bind "<shift><alt>Left" { "move-cursor" (words, -1, 1) }
bind "<shift><alt>KP_Left" { "move-cursor" (words, -1, 1) }
}
class "GtkTextView" binding "gtk-mac-alt-arrows"
class "GtkLabel" binding "gtk-mac-alt-arrows"
class "GtkEntry" binding "gtk-mac-alt-arrows"
binding "gtk-mac-alt-delete"
{
bind "<alt>Delete" { "delete-from-cursor" (word-ends, 1) }
bind "<alt>KP_Delete" { "delete-from-cursor" (word-ends, 1) }
bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
}
class "GtkTextView" binding "gtk-mac-alt-delete"
class "GtkEntry" binding "gtk-mac-alt-delete"
binding "gtk-mac-cmd-c"
{
bind "<meta>x" { "cut-clipboard" () }
bind "<meta>c" { "copy-clipboard" () }
bind "<meta>v" { "paste-clipboard" () }
unbind "<ctrl>x"
unbind "<ctrl>c"
unbind "<ctrl>v"
}
class "GtkTextView" binding "gtk-mac-cmd-c"
class "GtkEntry" binding "gtk-mac-cmd-c"
binding "gtk-mac-text-view"
{
bind "<shift><meta>a" { "select-all" (0) }
bind "<meta>a" { "select-all" (1) }
unbind "<shift><ctrl>a"
unbind "<ctrl>a"
}
class "GtkTextView" binding "gtk-mac-text-view"
binding "gtk-mac-label"
{
bind "<meta>a" {
"move-cursor" (paragraph-ends, -1, 0)
"move-cursor" (paragraph-ends, 1, 1)
}
bind "<shift><meta>a" { "move-cursor" (paragraph-ends, 0, 0) }
bind "<meta>c" { "copy-clipboard" () }
unbind "<ctrl>a"
unbind "<shift><ctrl>a"
unbind "<ctrl>c"
}
class "GtkLabel" binding "gtk-mac-label"
binding "gtk-mac-entry"
{
bind "<meta>a" {
"move-cursor" (buffer-ends, -1, 0)
"move-cursor" (buffer-ends, 1, 1)
}
bind "<shift><meta>a" { "move-cursor" (visual-positions, 0, 0) }
unbind "<ctrl>a"
unbind "<shift><ctrl>a"
}
class "GtkEntry" binding "gtk-mac-entry"
binding "gtk-mac-cmd-arrows"
{
bind "<meta>Left" { "move-cursor" (paragraph-ends, -1, 0) }
bind "<meta>KP_Left" { "move-cursor" (paragraph-ends, -1, 0) }
bind "<shift><meta>Left" { "move-cursor" (paragraph-ends, -1, 1) }
bind "<shift><meta>KP_Left" { "move-cursor" (paragraph-ends, -1, 1) }
bind "<meta>Right" { "move-cursor" (paragraph-ends, 1, 0) }
bind "<meta>KP_Right" { "move-cursor" (paragraph-ends, 1, 0) }
bind "<shift><meta>Right" { "move-cursor" (paragraph-ends, 1, 1) }
bind "<shift><meta>KP_Right" { "move-cursor" (paragraph-ends, 1, 1) }
}
class "GtkTextView" binding "gtk-mac-cmd-arrows"
class "GtkLabel" binding "gtk-mac-cmd-arrows"
class "GtkEntry" binding "gtk-mac-cmd-arrows"
binding "gtk-mac-emacs-like"
{
bind "<ctrl>a" { "move-cursor" (paragraph-ends, -1, 0) }
bind "<shift><ctrl>a" { "move-cursor" (paragraph-ends, -1, 1) }
bind "<ctrl>e" { "move-cursor" (paragraph-ends, 1, 0) }
bind "<shift><ctrl>e" { "move-cursor" (paragraph-ends, 1, 1) }
bind "<ctrl>b" { "move-cursor" (logical-positions, -1, 0) }
bind "<shift><ctrl>b" { "move-cursor" (logical-positions, -1, 1) }
bind "<ctrl>f" { "move-cursor" (logical-positions, 1, 0) }
bind "<shift><ctrl>f" { "move-cursor" (logical-positions, 1, 1) }
}
class "GtkTextView" binding "gtk-mac-emacs-like"
class "GtkLabel" binding "gtk-mac-emacs-like"
class "GtkEntry" binding "gtk-mac-emacs-like"
binding "gtk-mac-file-chooser"
{
bind "<meta>v" { "location-popup-on-paste" () }
unbind "<ctrl>v"
bind "<meta><shift>G" { "location-popup" () }
bind "<meta><shift>H" { "home-folder" () }
bind "<meta>Up" { "up-folder" () }
}
class "GtkFileChooserDefault" binding "gtk-mac-file-chooser"
binding "gtk-mac-tree-view"
{
bind "<meta>a" { "select-all" () }
bind "<shift><meta>a" { "unselect-all" () }
bind "<meta>f" { "start-interactive-search" () }
bind "<meta>F" { "start-interactive-search" () }
unbind "<ctrl>a"
unbind "<shift><ctrl>a"
unbind "<ctrl>f"
unbind "<ctrl>F"
}
class "GtkTreeView" binding "gtk-mac-tree-view"
binding "gtk-mac-icon-view"
{
bind "<meta>a" { "select-all" () }
bind "<shift><meta>a" { "unselect-all" () }
unbind "<ctrl>a"
unbind "<shift><ctrl>a"
}
class "GtkIconView" binding "gtk-mac-icon-view"

View File

@@ -1,5 +1,31 @@
#!/bin/bash
#####################################################################
# HELPER FUNCTIONS
#####################################################################
# Libraries work.
change_framework_library_load_path() {
local bin_to_fix=$1
local path=$2
# First iteration - main libraries.
echo "Copying libraries..."
dylibbundler -of -b -x ${bin_to_fix} -d ./URTrator.app/Contents/Framework/ -p ${path}
# Fix shit for dylibbundler. By this moment we should have everything
# we needed in Framework directory.
for lib in $(ls ./URTrator.app/Contents/Framework); do
libname=$(echo ${lib} | awk -F"/" {' print $NF '})
DEPS=$(otool -L ./URTrator.app/Contents/Framework/${lib} | grep "/usr/local")
for dep in ${DEPS[@]}; do
dep_name=$(echo ${dep} | awk -F"/" {' print $NF '})
install_name_tool -change ${dep} ${path}/${dep_name} ./URTrator.app/Contents/Framework/${libname}
done
done
}
# More permissive UMASK.
umask 002
# Do some checks.
# Do we have brew installed?
@@ -40,8 +66,11 @@ fi
echo "Creating app bundle..."
mkdir -p URTrator.app/Contents/{MacOS,Framework,Resources}
# Copying URTrator binary
cp $GOPATH/bin/urtrator URTrator.app/Contents/MacOS/
cp $GOPATH/src/github.com/pztrn/urtrator/artwork/urtrator.icns URTrator.app/Contents/Resources/
# Copying main resources.
cp $GOPATH/src/github.com/pztrn/urtrator/artwork/urtrator.icns ./URTrator.app/Contents/Resources/
cp -R ./Resources/themes ./URTrator.app/Contents/Resources/
#####################################################################
# APP BUNDLE INFO.PLIST
@@ -73,27 +102,56 @@ INFOPLIST='<?xml version="1.0" encoding="UTF-8"?>
</dict>
</plist>'
echo ${INFOPLIST} > URTrator.app/Contents/Info.plist
echo -e ${INFOPLIST} > URTrator.app/Contents/Info.plist
echo -e '#!/bin/bash\ncd "${0%/*}"\n./urtrator' > ./URTrator.app/Contents/MacOS/urtrator.sh
echo -e '#!/bin/bash\ncd "${0%/*}"\nexport GTK_PATH="../lib/gtk-2.0/"\nexport GTK_MODULES="../lib/gtk-2.0/"\nexport GDK_PIXBUF_MODULE_FILE="../lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"\nexport GDK_PIXBUF_MODULEDIR="../lib/gdk-pixbuf-2.0/2.10.0/loaders/"\nexport GTK_EXE_PREFIX="../lib"\n./urtrator' > ./URTrator.app/Contents/MacOS/urtrator.sh
chmod +x ./URTrator.app/Contents/MacOS/urtrator.sh
#####################################################################
# Copying helper binaries.
cp /usr/local/Cellar/gdk-pixbuf/2.36.0_2/bin/gdk-pixbuf-query-loaders ./URTrator.app/Contents/MacOS/
# Copy GTK engines as needed for default theme.
cp /usr/local/lib/gtk-2.0/2.10.0/engines/* ./URTrator.app/Contents/Framework/
cp /usr/local/Cellar/gdk-pixbuf/2.36.0_2/lib/gdk-pixbuf-2.0/2.10.0/loaders/*.so ./URTrator.app/Contents/Framework/
chmod -R 0644 ./URTrator.app/Contents/Framework/*
chmod -R 0755 ./URTrator.app/Contents/MacOS/*
# Libraries works.
# First iteration - main libraries.
echo "Copying libraries..."
dylibbundler -of -b -x ./URTrator.app/Contents/MacOS/urtrator -d ./URTrator.app/Contents/Framework/ -p @executable_path/../Framework/
change_framework_library_load_path "./URTrator.app/Contents/MacOS/urtrator" "@executable_path/../Framework"
change_framework_library_load_path "./URTrator.app/Contents/MacOS/gdk-pixbuf-query-loaders" "@executable_path/../Framework"
# Fix shit for dylibbundler. By this moment we should have everything
# we needed in Framework directory.
for lib in $(ls ./URTrator.app/Contents/Framework); do
libname=$(echo ${lib} | awk -F"/" {' print $NF '})
DEPS=$(otool -L ./URTrator.app/Contents/Framework/${lib} | grep "/usr/local")
#####################################################################
# Directory structure for GTK things. We will symlink neccessary
# libraries from /Framework here.
echo "Creating libraries structure with symlinks"
# GTK engines
mkdir -p ./URTrator.app/Contents/lib/gtk-2.0/2.10.0/engines/
cd ./URTrator.app/Contents/lib/gtk-2.0/2.10.0/engines/
ln -s ../../../../Framework/libclearlooks.so libclearlooks.so
ln -s ../../../../Framework/libmurrine.so libmurrine.so
ln -s ../../../../Framework/libpixmap.so libpixmap.so
# Pixbuf loaders
cd ../../../../
mkdir -p lib/gdk-pixbuf-2.0/2.10.0/loaders/
cd lib/gdk-pixbuf-2.0/2.10.0/loaders/
for file in $(ls ../../../../Framework | grep libpixbufloader); do
ln -s ../../../../Framework/${file} ${file}
done
# Fix pixbuf loaders to load things from "../Framework".
for file in $(ls . | grep libpixbufloader); do
DEPS=$(otool -L ${file} | grep "executable_path")
for dep in ${DEPS[@]}; do
dep_name=$(echo ${dep} | awk -F"/" {' print $NF '})
install_name_tool -change ${dep} @executable_path/../Framework/${dep_name} ./URTrator.app/Contents/Framework/${libname}
install_name_tool -change ${dep} ../Framework/${dep_name} ${file}
done
done
cd ..
ln -s ../../../Framework .
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
echo "Copying icon theme..."
echo "Finishing..."

View File

@@ -0,0 +1,3 @@
# Windows installation
*TBW*

View File

@@ -0,0 +1,115 @@
#!/bin/bash
# URTrator Windows build scripts.
# Requirements: installed and properly configured Go and MSYS2
#####################################################################
# VARIABLES
#####################################################################
# Path of script.
SCRIPT_PATH=$(dirname "`readlink -f "${BASH_SOURCE}"`")
# Go binary path.
GO=$(which go | awk {' print $1 '})
#####################################################################
# Checks if Go installed and properly configured.
check_golang() {
if [ ${#GO} -eq 0 ]; then
echo "! Can't find Go binary. Please, install Go and configure your environment."
fi
}
# Check if we are in valid MSYS2 environment.
check_msys() {
echo "* Checking for MSYS..."
if [ -z MSYSTEM ]; then
echo "! Probably, not MSYS2 environment. Building can continue only with MSYS2!"
exit 1
fi
if [ "${MSYSTEM}" == "MSYS" ]; then
echo "! Invalid MSYS2 environment. You're launched MSYS console, but building can continue in MINGW64 console only."
exit 1
fi
}
# Check if we have neccessary MSYS packages installed.
check_msys_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 ${MINGW_PACKAGE_PREFIX}-gcc --noconfirm --needed
}
# Build URTrator
urtrator_build() {
echo "* Starting URTrator building..."
# Create temporary Go root.
if [ -d "${SCRIPT_PATH}/GOROOT" ]; then
rm -rf "${SCRIPT_PATH}/GOROOT"
fi
mkdir -p "${SCRIPT_PATH}/GOROOT"
# Exporting Go variables.
export GOPATH="${SCRIPT_PATH}/GOROOT"
echo "* Obtaining URTrator and dependencies sources..."
go get -u -d -v github.com/pztrn/urtrator
echo "* Building URTrator"
go install -v github.com/pztrn/urtrator
}
# Prepare urtrator distribution.
urtrator_dist() {
echo "* Preparing URTrator distribution..."
echo "* Creating distribution directory..."
if [ -d "${SCRIPT_PATH}/dist" ]; then
rm -rf "${SCRIPT_PATH}/dist"
fi
mkdir "${SCRIPT_PATH}/dist"
echo "* Copying URTrator binary..."
cp "${GOPATH}/bin/urtrator.exe" "${SCRIPT_PATH}/dist/"
echo "* Getting list of library dependencies..."
DEPS=$(ldd dist/urtrator.exe | grep -v "Windows" | awk {' print $1 '})
echo "* Copying dependencies..."
for dep in ${DEPS[@]}; do
cp /mingw64/bin/${dep} "${SCRIPT_PATH}/dist"
done
echo "* Installing GTK+2 theme engines..."
mkdir -p "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libmurrine.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libredmond95.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libthinice.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libmist.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libindustrial.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libhcengine.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libglide.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libcrux-engine.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libclearlooks.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
cp /mingw64/lib/gtk-2.0/2.10.0/engines/libwimp.dll "${SCRIPT_PATH}/dist/lib/gtk-2.0/2.10.0/engines/"
echo "* Checking that we haven't forget any of dependencies..."
LIBS=$(ls "${SCRIPT_PATH}/dist" | grep ".dll")
for lib in ${LIBS[@]}; do
LIBDEPS=$(ldd "${SCRIPT_PATH}/dist/${lib}" | grep -v "Windows" | awk {' print $1 '})
for libdep in ${LIBDEPS[@]}; do
if [ ! -f "${SCRIPT_PATH}/dist/${lib}" ]; then
cp /mingw64/bin/${libdep} "${SCRIPT_PATH}/dist"
fi
done
done
echo "* Installing default theme..."
mkdir -p "${SCRIPT_PATH}/dist/themes"
cp -R /mingw64/share/themes/ "${SCRIPT_PATH}/dist/"
}
echo "Launched in ${SCRIPT_PATH}"
check_msys
check_golang
check_msys_packages
urtrator_build
urtrator_dist
echo "*** URTrator done."

View File

@@ -13,6 +13,10 @@ import (
crand "crypto/rand"
"errors"
"fmt"
//"reflect"
// github
"github.com/mattn/go-gtk/glib"
)
type Eventer struct {
@@ -44,11 +48,19 @@ func (e *Eventer) LaunchEvent(event string, data map[string]string) error {
if !ok {
return errors.New("Event " + event + " not found!")
}
fmt.Println("Launching event " + event)
for _, val := range e.events[event] {
val(data)
}
fmt.Println("Launching event " + event)
glib.IdleAdd(func() bool {
e.reallyLaunchEvent(event, data)
return false
})
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)
}
}

View File

@@ -15,6 +15,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
@@ -34,13 +35,17 @@ type Launcher struct {
func (l *Launcher) CheckForLaunchedUrbanTerror() error {
if l.launched {
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.Response(func() {
m.Destroy()
})
m.Run()
return errors.New("User didn't select valid profile, mismatch with server's version.")
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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.Response(func() {
m.Destroy()
})
m.Run()
return errors.New("User didn't select valid profile, mismatch with server's version.")
}
}
return nil
@@ -104,12 +109,18 @@ func (l *Launcher) Launch(server_profile *datamodels.Server, user_profile *datam
bundle_path := strings.Split(launch_bin, "/Contents")[0]
// and create special launch string, which involves open.
launch_bin = "/usr/bin/open"
launch_params = append([]string{launch_bin, "-W", bundle_path, "--args"}, launch_params...)
launch_params = append([]string{launch_bin, "-W", "-a", bundle_path, "--args"}, launch_params...)
}
fmt.Println(launch_bin, launch_params)
go func() {
go func() {
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()
if err1 != nil {
fmt.Println("Launch error: " + err1.Error())

View File

@@ -14,7 +14,7 @@ import (
"errors"
"fmt"
"net"
//"runtime"
"runtime"
"strconv"
"strings"
"sync"
@@ -34,7 +34,8 @@ type Pooler struct {
func (p *Pooler) Initialize() {
fmt.Println("Initializing requester goroutine pooler...")
// 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"
fmt.Println("Pooler initialized")
}
@@ -233,11 +234,34 @@ func (p *Pooler) UpdateSpecificServer(server *datamodels.Server) error {
if len(received_lines) >= 2 {
// Here we go, players information.
players := received_lines[2:]
var real_players int = 0
var bots int = 0
// Calculate players!
if len(players) == 1 && len(players[0]) > 255 {
server.Players = "0"
server.Bots = "0"
} 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:], "\\")
}

View File

@@ -12,6 +12,7 @@ package requester
import (
// stdlib
"bytes"
"errors"
"fmt"
"net"
"strconv"
@@ -46,11 +47,13 @@ func (r *Requester) Initialize() {
// Gets all available servers from master server.
// 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.
conn, err1 := net.Dial("udp", r.master_server + ":" + r.master_server_port)
if err1 != nil {
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()
@@ -118,6 +121,8 @@ func (r *Requester) getServers() {
Cache.Servers[addr].Server.Port = port
}
}
return nil
}
// Updates information about all available servers from master server and

View File

@@ -14,6 +14,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"runtime"
"strings"
// Local
@@ -117,7 +118,6 @@ func (f *FavoriteDialog) initializeWindow() {
f.window.SetModal(true)
f.window.SetSizeRequest(400, 200)
f.window.SetResizable(false)
f.vbox = gtk.NewVBox(false, 0)
// Load program icon from base64.
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
@@ -131,54 +131,59 @@ func (f *FavoriteDialog) initializeWindow() {
gtk_opts := gtk_opts_raw.ToGObject()
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.
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_hbox.PackStart(srv_name_label, false, true, 5)
srv_name_sep := gtk.NewHSeparator()
srv_name_hbox.PackStart(srv_name_sep, true, true, 5)
srv_name_label.SetAlignment(0, 0)
table.Attach(srv_name_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
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.
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_hbox.PackStart(srv_addr_label, false, true, 5)
srv_addr_sep := gtk.NewHSeparator()
srv_addr_hbox.PackStart(srv_addr_sep, true, true, 5)
srv_addr_label.SetAlignment(0, 0)
table.Attach(srv_addr_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
srv_addr_hbox := gtk.NewHBox(false, 0)
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.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.Clicked(f.updateServerInfo)
srv_addr_hbox.PackStart(srv_addr_update_btn, false, true, 5)
if f.update {
f.server_address.SetSensitive(false)
}
table.Attach(srv_addr_hbox, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
// 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_hbox.PackStart(srv_pass_label, false, true, 5)
srv_pass_sep := gtk.NewHSeparator()
srv_pass_hbox.PackStart(srv_pass_sep, true, true, 5)
srv_pass_label.SetAlignment(0, 0)
table.Attach(srv_pass_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
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_hbox := gtk.NewHBox(false, 0)
f.vbox.PackStart(profile_hbox, false, true, 5)
profile_label := gtk.NewLabel("Profile:")
profile_hbox.PackStart(profile_label, false, true, 5)
profile_sep := gtk.NewHSeparator()
profile_hbox.PackStart(profile_sep, true, true, 5)
profile_label.SetAlignment(0, 0)
table.Attach(profile_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
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 := gtk.NewHBox(false, 0)
@@ -205,12 +210,16 @@ func (f *FavoriteDialog) saveFavorite() error {
//ctx.Requester.Pooler.UpdateSpecificServer(f.server)
if len(f.server_address.GetText()) == 0 {
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.Response(func() {
m.Destroy()
})
m.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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.Response(func() {
m.Destroy()
})
m.Run()
}
return errors.New("No server address specified")
}
@@ -224,12 +233,16 @@ func (f *FavoriteDialog) saveFavorite() error {
f.server.Port = port
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."
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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.Response(func() {
m.Destroy()
})
m.Run()
}
return errors.New("No game profile specified")
}

View File

@@ -12,6 +12,8 @@ package ui
import (
// stdlib
"fmt"
"runtime"
"sort"
"strconv"
"strings"
@@ -29,6 +31,8 @@ type MainWindow struct {
// Gamemodes.
gamemodes map[string]string
text string
// Widgets.
// The window itself.
window *gtk.Window
@@ -56,12 +60,26 @@ type MainWindow struct {
profiles *gtk.ComboBoxText
// Checkbox for hiding/showing offline servers in 'Servers' tab list.
all_servers_hide_offline *gtk.CheckButton
// Checkbox for hiding/showing passworded servers in 'Servers' tab list.
all_servers_hide_private *gtk.CheckButton
// Combobox for filtering server's versions.
all_servers_version *gtk.ComboBoxText
// Combobox for filtering by gamemode.
all_servers_gamemode *gtk.ComboBoxText
// Checkbox for hiding/showing offline servers in 'Favorites' tab list.
fav_servers_hide_offline *gtk.CheckButton
// Checkbox for hiding/showing passworded servers in 'Favorites' tab list.
fav_servers_hide_private *gtk.CheckButton
// Combobox for filtering server's versions.
fav_servers_version *gtk.ComboBoxText
// Combobox for filtering by gamemode.
fav_servers_gamemode *gtk.ComboBoxText
// Game launch button.
launch_button *gtk.Button
// Server's information.
// Server's main information.
server_info *gtk.TreeView
// Players information.
players_info *gtk.TreeView
// Quick connect: server address
qc_server_address *gtk.Entry
// Quick connect: password
@@ -84,9 +102,12 @@ type MainWindow struct {
fav_servers_store *gtk.ListStore
// Server's information store.
server_info_store *gtk.ListStore
// Players information store.
players_info_store *gtk.ListStore
// Dialogs.
options_dialog *OptionsDialog
server_cvars_dialog *ServerCVarsDialog
// Other
// Old profiles count.
@@ -118,14 +139,20 @@ type MainWindow struct {
// For online server.
server_online_pic *gdkpixbuf.Pixbuf
// For private (passworded) server.
server_passworded_pic *gdkpixbuf.Pixbuf
server_private_pic *gdkpixbuf.Pixbuf
// For public server
server_public_pic *gdkpixbuf.Pixbuf
// Flags.
// Application is initialized?
initialized bool
// Window is hidden?
hidden bool
// Use other's tab information?
// Used when user changed active tab, to show information about
// server which is selected on activated tab.
use_other_servers_tab bool
}
func (m *MainWindow) addToFavorites() {
@@ -154,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
// position.
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.
// Also calculating pane delimiter position and set it to avoid
// widgets hell :).
func (m *MainWindow) checkPositionAndSize() {
m.window.GetPosition(&m.window_pos_x, &m.window_pos_y)
m.window.GetSize(&m.window_width, &m.window_height)
glib.IdleAdd(func() bool {
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.
@@ -191,9 +234,21 @@ func (m *MainWindow) Close() {
ctx.Cfg.Cfg["/mainwindow/fav_servers/" + fav_servers_columns[i].GetTitle() + "_width"] = strconv.Itoa(fav_servers_columns[i].GetWidth())
}
// Additional actions should be taken on Windows.
if runtime.GOOS == "windows" {
m.closeWin()
}
ctx.Close()
}
func (m *MainWindow) copyServerCredentialsToClipboard() {
fmt.Println("Copying server's credentials to clipboard...")
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
server_address := m.getIpFromServersList(current_tab)
ctx.Clipboard.CopyServerData(server_address)
}
// Deleting server from favorites.
func (m *MainWindow) deleteFromFavorites() {
fmt.Println("Removing server from favorites...")
@@ -213,12 +268,18 @@ func (m *MainWindow) deleteFromFavorites() {
}
if not_favorited {
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.Response(func() {
d.Destroy()
})
d.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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.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{})
@@ -229,19 +290,23 @@ func (m *MainWindow) deleteFromFavorites() {
func (m *MainWindow) dropDatabasesData() {
fmt.Println("Dropping database data...")
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?"
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string)
d.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
})
d.Response(func() {
d.Destroy()
})
d.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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?"
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string)
d.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
d.Destroy()
})
d.Run()
} else {
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">Remove ~/.config/urtrator/database.sqlite3 manually!</span></markup>"})
}
if will_continue {
ctx.Database.Db.MustExec("DELETE FROM servers")
@@ -267,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
// "Servers" tab.
func (m *MainWindow) hideOfflineAllServers() {
@@ -279,6 +354,18 @@ func (m *MainWindow) hideOfflineAllServers() {
ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{})
}
// Executes when "Hide passworded servers" checkbox changed it's state on
// "Servers" tab.
func (m *MainWindow) hidePrivateAllServers() {
fmt.Println("(Un)Hiding private servers in 'Servers' tab...")
if m.all_servers_hide_private.GetActive() {
ctx.Cfg.Cfg["/serverslist/all_servers/hide_private"] = "1"
} else {
ctx.Cfg.Cfg["/serverslist/all_servers/hide_private"] = "0"
}
ctx.Eventer.LaunchEvent("loadAllServers", map[string]string{})
}
// Executes when "Hide offline servers" checkbox changed it's state on
// "Favorites" tab.
func (m *MainWindow) hideOfflineFavoriteServers() {
@@ -291,9 +378,20 @@ func (m *MainWindow) hideOfflineFavoriteServers() {
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
}
// Executes when "Hide passworded servers" checkbox changed it's state on
// "Favorites" tab.
func (m *MainWindow) hidePrivateFavoriteServers() {
fmt.Println("(Un)Hiding private servers in 'Favorite' tab...")
if m.all_servers_hide_private.GetActive() {
ctx.Cfg.Cfg["/serverslist/favorite/hide_private"] = "1"
} else {
ctx.Cfg.Cfg["/serverslist/favorite/hide_private"] = "0"
}
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
}
func (m *MainWindow) loadAllServers(data map[string]string) {
fmt.Println("Loading all servers...")
// ToDo: do it without clearing.
for _, server := range ctx.Cache.Servers {
iter := new(gtk.TreeIter)
ping, _ := strconv.Atoi(server.Server.Ping)
@@ -305,8 +403,39 @@ func (m *MainWindow) loadAllServers(data map[string]string) {
iter = server.AllServersIter
}
// Hide offline servers?
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)
server.AllServersIterInList = false
}
@@ -328,7 +457,7 @@ func (m *MainWindow) loadAllServers(data map[string]string) {
m.all_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
}
if server.Server.IsPrivate == "1" {
m.all_servers_store.SetValue(iter, 1, m.server_passworded_pic.GPixbuf)
m.all_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf)
} else {
m.all_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
}
@@ -336,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"]["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"]["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"]["Version"], server.Server.Version)
m.all_servers_store.SetValue(iter, m.column_pos["Servers"]["IP"], server.Server.Ip + ":" + server.Server.Port)
@@ -357,6 +486,7 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
iter = server.FavServersIter
}
// Hide offline servers?
if m.fav_servers_hide_offline.GetActive() && (server.Server.Players == "" && server.Server.Maxplayers == "" || ping > 9000) {
if server.FavServersIterInList {
m.fav_servers_store.Remove(iter)
@@ -365,6 +495,36 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
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
// removed from favorites) - remove it from list.
if server.Server.Favorite != "1" && server.FavServersIterSet && server.FavServersIterInList {
@@ -393,7 +553,7 @@ func (m *MainWindow) loadFavoriteServers(data map[string]string) {
m.fav_servers_store.SetValue(iter, 0, m.server_online_pic.GPixbuf)
}
if server.Server.IsPrivate == "1" {
m.fav_servers_store.SetValue(iter, 1, m.server_passworded_pic.GPixbuf)
m.fav_servers_store.SetValue(iter, 1, m.server_private_pic.GPixbuf)
} else {
m.fav_servers_store.SetValue(iter, 1, m.server_public_pic.GPixbuf)
}
@@ -401,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"]["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"]["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"]["Version"], server.Server.Version)
m.fav_servers_store.SetValue(iter, m.column_pos["Favorites"]["IP"], server.Server.Ip + ":" + server.Server.Port)
@@ -423,10 +583,46 @@ func (m *MainWindow) loadProfiles(data map[string]string) {
m.old_profiles_count = len(ctx.Cache.Profiles)
fmt.Println("Added " + strconv.Itoa(m.old_profiles_count) + " profiles")
m.profiles.SetActive(0)
}
func (m *MainWindow) tabChanged() {
if !m.initialized {
return
}
fmt.Println("Active tab changed...")
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
fmt.Println(current_tab)
m.use_other_servers_tab = true
if strings.Contains(current_tab, "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) {
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) {
@@ -451,14 +647,33 @@ func (m *MainWindow) showHide() {
}
}
func (m *MainWindow) showServerInformation() {
fmt.Println("Showing server's information...")
func (m *MainWindow) showServerCVars() {
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
if m.use_other_servers_tab {
if strings.Contains(current_tab, "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() {
fmt.Println("Server selection changed, updating server's information widget...")
m.server_info_store.Clear()
m.players_info_store.Clear()
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
if m.use_other_servers_tab {
if strings.Contains(current_tab, "Servers") {
current_tab = "Favorites"
} else if strings.Contains(current_tab, "Favorites") {
current_tab = "Servers"
}
}
srv_address := m.getIpFromServersList(current_tab)
// Getting server information from cache.
@@ -469,12 +684,8 @@ func (m *MainWindow) showShortServerInformation() {
// Append to treeview generic info first. After appending it
// 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.
iter = new(gtk.TreeIter)
iter := new(gtk.TreeIter)
m.server_info_store.Append(iter)
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"]))
@@ -491,7 +702,7 @@ func (m *MainWindow) showShortServerInformation() {
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
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")
// Ping
@@ -522,23 +733,26 @@ func (m *MainWindow) showShortServerInformation() {
}
m.server_info_store.SetValue(iter, 1, passworded_status)
// Just a separator.
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
// Players information
iter = new(gtk.TreeIter)
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"] + ")")
// Sorting keys of map.
players_map_keys := make([]string, 0, len(parsed_players_info))
for k := range parsed_players_info {
// ToDo: figure out how to do this properly without
// append().
players_map_keys = append(players_map_keys, k)
}
sort.Strings(players_map_keys)
for k := range players_map_keys {
iter = new(gtk.TreeIter)
nick := ctx.Colorizer.Fix(parsed_players_info[players_map_keys[k]]["nick"])
m.players_info_store.Append(iter)
m.players_info_store.SetValue(iter, 0, nick)
m.players_info_store.SetValue(iter, 1, parsed_players_info[players_map_keys[k]]["frags"])
m.players_info_store.SetValue(iter, 2, parsed_players_info[players_map_keys[k]]["ping"])
}
/*
// Just a separator.
iter = new(gtk.TreeIter)
m.server_info_store.Append(iter)
@@ -548,12 +762,21 @@ func (m *MainWindow) showShortServerInformation() {
m.server_info_store.Append(iter)
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)
m.server_info_store.Append(iter)
m.server_info_store.SetValue(iter, 0, key)
m.server_info_store.SetValue(iter, 1, value)
m.server_info_store.SetValue(iter, 0, general_data_keys[k])
m.server_info_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]])
}
*/
}
}
@@ -569,6 +792,7 @@ func (m *MainWindow) unlockInterface() {
}
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()))
srv_address := m.getIpFromServersList(current_tab)

View File

@@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"runtime"
"sort"
"strconv"
// local
@@ -18,9 +19,11 @@ import (
// Main window initialization.
func (m *MainWindow) Initialize() {
gtk.Init(nil)
m.initializeStorages()
ctx.InitializeClipboardWatcher()
m.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
m.window.SetTitle("URTrator")
@@ -36,6 +39,14 @@ func (m *MainWindow) Initialize() {
m.window.Connect("configure-event", m.checkPositionAndSize)
// Additional OS-specific initialization.
if runtime.GOOS == "windows" {
m.initializeWin()
}
if runtime.GOOS == "darwin" {
m.initializeMac()
}
// Restoring window position.
var win_pos_x_str string = "0"
var win_pos_y_str string = "0"
@@ -74,9 +85,14 @@ func (m *MainWindow) Initialize() {
// Dialogs initialization.
m.options_dialog = &OptionsDialog{}
m.server_cvars_dialog = &ServerCVarsDialog{}
// Main menu.
m.InitializeMainMenu()
if runtime.GOOS == "darwin" {
m.initializeMacMenu()
} else {
m.InitializeMainMenu()
}
// Toolbar.
m.InitializeToolbar()
@@ -116,7 +132,7 @@ func (m *MainWindow) Initialize() {
m.vbox.PackStart(profile_and_launch_hbox, false, true, 5)
// Separator
sep := gtk.NewHSeparator()
sep := gtk.NewHBox(false, 0)
profile_and_launch_hbox.PackStart(sep, true, true, 5)
// Profile selection.
@@ -135,11 +151,16 @@ func (m *MainWindow) Initialize() {
m.launch_button = gtk.NewButtonWithLabel("Launch!")
m.launch_button.SetTooltipText("Launch Urban Terror")
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)
profile_and_launch_hbox.PackStart(m.launch_button, false, true, 5)
m.window.Add(m.vbox)
if runtime.GOOS == "darwin" {
m.initializeMacAfter()
}
m.window.ShowAll()
// Launch events.
@@ -150,6 +171,9 @@ func (m *MainWindow) Initialize() {
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "URTrator is ready."})
// Set flag that shows to other parts that we're initialized.
m.initialized = true
gtk.Main()
}
@@ -160,6 +184,7 @@ func (m *MainWindow) initializeEvents() {
ctx.Eventer.AddEventHandler("loadFavoriteServers", m.loadFavoriteServers)
ctx.Eventer.AddEventHandler("loadProfilesIntoMainWindow", m.loadProfiles)
ctx.Eventer.AddEventHandler("serversUpdateCompleted", m.serversUpdateCompleted)
ctx.Eventer.AddEventHandler("setQuickConnectDetails", m.setQuickConnectDetails)
ctx.Eventer.AddEventHandler("setToolbarLabelText", m.setToolbarLabelText)
}
@@ -220,6 +245,7 @@ func (m *MainWindow) initializeSidebar() {
// Scrolled thing.
si_scroll := gtk.NewScrolledWindow(nil, nil)
si_scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
si_vbox.PackStart(si_scroll, true, true, 5)
// Server's information.
@@ -234,10 +260,32 @@ func (m *MainWindow) initializeSidebar() {
si_scroll.Add(m.server_info)
// Button to view additional server info.
additional_srv_info_button := gtk.NewButtonWithLabel("Additional information")
additional_srv_info_button.Clicked(m.showServerInformation)
si_vbox.PackStart(additional_srv_info_button, false, true, 5)
// Players information.
players_info_frame := gtk.NewFrame("Players")
sidebar_vbox.PackStart(players_info_frame, true, true, 5)
pi_scroll := gtk.NewScrolledWindow(nil, nil)
pi_scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
players_info_frame.Add(pi_scroll)
m.players_info = gtk.NewTreeView()
m.players_info.SetModel(m.players_info_store)
pi_scroll.Add(m.players_info)
name_column := gtk.NewTreeViewColumnWithAttributes("Player name", gtk.NewCellRendererText(), "markup", 0)
m.players_info.AppendColumn(name_column)
frags_column := gtk.NewTreeViewColumnWithAttributes("Frags", gtk.NewCellRendererText(), "markup", 1)
m.players_info.AppendColumn(frags_column)
ping_column := gtk.NewTreeViewColumnWithAttributes("Ping", gtk.NewCellRendererText(), "markup", 2)
m.players_info.AppendColumn(ping_column)
// Show CVars button.
show_cvars_button := gtk.NewButtonWithLabel("Show CVars")
show_cvars_button.SetTooltipText("Show server's CVars")
show_cvars_button.Clicked(m.showServerCVars)
sidebar_vbox.PackStart(show_cvars_button, false, true, 5)
// Quick connect frame.
quick_connect_frame := gtk.NewFrame("Quick connect")
@@ -280,6 +328,9 @@ func (m *MainWindow) initializeSidebar() {
// Initializes internal storages.
func (m *MainWindow) initializeStorages() {
// Application isn't initialized.
m.initialized = false
m.use_other_servers_tab = false
// Gamemodes.
m.gamemodes = make(map[string]string)
m.gamemodes = map[string]string{
@@ -330,6 +381,10 @@ func (m *MainWindow) initializeStorages() {
// Server's information store. Used for quick preview in main window.
m.server_info_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING)
// Players information store. Used in sidebar for players list for
// currently selected server.
m.players_info_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING)
// Profiles count after filling combobox. Defaulting to 0.
m.old_profiles_count = 0
@@ -338,19 +393,37 @@ func (m *MainWindow) initializeStorages() {
// Pixbufs.
// 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.
m.server_online_pic = gtk.NewImage().RenderIcon(gtk.STOCK_OK, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
// Passworded server.
m.server_passworded_pic = gtk.NewImage().RenderIcon(gtk.STOCK_CLOSE, gtk.ICON_SIZE_SMALL_TOOLBAR, "")
srv_online_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_ONLINE)
srv_online_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
srv_online_pixbuf.SetSize(24, 24)
srv_online_pixbuf.Write(srv_online_bytes)
m.server_online_pic = srv_online_pixbuf.GetPixbuf()
// Private server.
srv_private_bytes, _ := base64.StdEncoding.DecodeString(common.SERVER_PRIVATE)
srv_private_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
srv_private_pixbuf.SetSize(24, 24)
srv_private_pixbuf.Write(srv_private_bytes)
m.server_private_pic = srv_private_pixbuf.GetPixbuf()
// Public server.
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.
func (m *MainWindow) InitializeTabs() {
// Create tabs widget.
m.tab_widget = gtk.NewNotebook()
m.tab_widget.Connect("switch-page", m.tabChanged)
tab_allsrv_hbox := gtk.NewHBox(false, 0)
swin1 := gtk.NewScrolledWindow(nil, nil)
@@ -406,9 +479,15 @@ func (m *MainWindow) InitializeTabs() {
// Sorting.
// 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)
// Sorting functions.
// Race conditions and GC crazyness appears when activated, so for
// now commenting it out.
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Name"], m.sortServersByName)
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Players"], m.sortServersByPlayers)
m.all_servers_store_sortable.SetSortFunc(m.column_pos["Servers"]["Ping"], m.sortServersByPing)
// Selection changed signal, which will update server's short info pane.
m.all_servers.Connect("cursor-changed", m.showShortServerInformation)
@@ -421,12 +500,75 @@ func (m *MainWindow) InitializeTabs() {
m.all_servers_hide_offline.SetTooltipText("Hide offline servers on Servers tab")
tab_all_srv_ctl_vbox.PackStart(m.all_servers_hide_offline, false, true, 5)
m.all_servers_hide_offline.Clicked(m.hideOfflineAllServers)
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)
} 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.
ctl_sep := gtk.NewVSeparator()
ctl_sep := gtk.NewVBox(false, 0)
tab_all_srv_ctl_vbox.PackStart(ctl_sep, true, true, 5)
// Favorites servers
@@ -460,7 +602,11 @@ func (m *MainWindow) InitializeTabs() {
width_int, _ := strconv.Atoi(width)
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.SetResizable(true)
// GtkTreeViewColumn.SetFixedWidth() accepts only positive integers.
@@ -491,12 +637,69 @@ func (m *MainWindow) InitializeTabs() {
m.fav_servers_hide_offline.SetTooltipText("Hide offline servers on Favorites tab")
tab_fav_srv_ctl_vbox.PackStart(m.fav_servers_hide_offline, false, true, 5)
m.fav_servers_hide_offline.Clicked(m.hideOfflineFavoriteServers)
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)
} 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.
ctl_fav_sep := gtk.NewVSeparator()
ctl_fav_sep := gtk.NewVBox(false, 0)
tab_fav_srv_ctl_vbox.PackStart(ctl_fav_sep, true, true, 5)
// Add tab_widget widget to window.
@@ -509,14 +712,22 @@ func (m *MainWindow) InitializeToolbar() {
m.vbox.PackStart(m.toolbar, false, false, 5)
// Update servers button.
button_update_all_servers := gtk.NewToolButtonFromStock(gtk.STOCK_REFRESH)
button_update_all_servers.SetLabel("Update all servers")
button_update_all_servers.SetTooltipText("Update all servers in all tabs")
button_update_all_servers_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ALL_SERVERS)
button_update_all_servers_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
button_update_all_servers_icon_pixbuf.SetSize(24, 24)
button_update_all_servers_icon_pixbuf.Write(button_update_all_servers_icon_bytes)
button_update_all_servers_icon := gtk.NewImageFromPixbuf(button_update_all_servers_icon_pixbuf.GetPixbuf())
button_update_all_servers := gtk.NewToolButton(button_update_all_servers_icon, "Update all servers")
button_update_all_servers.SetTooltipText("Update all servers in currently selected tab")
button_update_all_servers.OnClicked(m.UpdateServers)
m.toolbar.Insert(button_update_all_servers, 0)
button_update_one_server := gtk.NewToolButtonFromStock(gtk.STOCK_REDO)
button_update_one_server.SetLabel("Update selected server")
button_update_one_server_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REFRESH_ONE_SERVER)
button_update_one_server_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
button_update_one_server_icon_pixbuf.SetSize(24, 24)
button_update_one_server_icon_pixbuf.Write(button_update_one_server_icon_bytes)
button_update_one_server_icon := gtk.NewImageFromPixbuf(button_update_one_server_icon_pixbuf.GetPixbuf())
button_update_one_server := gtk.NewToolButton(button_update_one_server_icon, "Update selected server")
button_update_one_server.SetTooltipText("Update only selected server")
button_update_one_server.OnClicked(m.updateOneServer)
m.toolbar.Insert(button_update_one_server, 1)
@@ -526,34 +737,57 @@ func (m *MainWindow) InitializeToolbar() {
m.toolbar.Insert(separator, 2)
// Add server to favorites button.
fav_button := gtk.NewToolButtonFromStock(gtk.STOCK_ADD)
fav_button.SetLabel("Add to favorites")
fav_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.ADD_TO_FAVORITES)
fav_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
fav_button_icon_pixbuf.SetSize(24, 24)
fav_button_icon_pixbuf.Write(fav_button_icon_bytes)
fav_button_icon := gtk.NewImageFromPixbuf(fav_button_icon_pixbuf.GetPixbuf())
fav_button := gtk.NewToolButton(fav_button_icon, "Add to favorites")
fav_button.SetTooltipText("Add selected server to favorites")
fav_button.OnClicked(m.addToFavorites)
m.toolbar.Insert(fav_button, 3)
fav_edit_button := gtk.NewToolButtonFromStock(gtk.STOCK_EDIT)
fav_edit_button.SetLabel("Edit favorite")
fav_edit_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.EDIT_FAVORITE)
fav_edit_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
fav_edit_button_icon_pixbuf.SetSize(24, 24)
fav_edit_button_icon_pixbuf.Write(fav_edit_button_icon_bytes)
fav_edit_button_icon := gtk.NewImageFromPixbuf(fav_edit_button_icon_pixbuf.GetPixbuf())
fav_edit_button := gtk.NewToolButton(fav_edit_button_icon, "Edit favorite")
fav_edit_button.SetTooltipText("Edit selected favorite server")
fav_edit_button.OnClicked(m.editFavorite)
m.toolbar.Insert(fav_edit_button, 4)
// Remove server from favorites button.
fav_delete_button := gtk.NewToolButtonFromStock(gtk.STOCK_REMOVE)
fav_delete_button.SetLabel("Remove from favorites")
fav_delete_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.REMOVE_FAVORITE)
fav_delete_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
fav_delete_button_icon_pixbuf.SetSize(24, 24)
fav_delete_button_icon_pixbuf.Write(fav_delete_button_icon_bytes)
fav_delete_button_icon := gtk.NewImageFromPixbuf(fav_delete_button_icon_pixbuf.GetPixbuf())
fav_delete_button := gtk.NewToolButton(fav_delete_button_icon, "Remove from favorites")
fav_delete_button.SetTooltipText("Remove selected server from favorites")
fav_delete_button.OnClicked(m.deleteFromFavorites)
m.toolbar.Insert(fav_delete_button, 5)
// Copy server address button.
copy_srv_addr_button_icon_bytes, _ := base64.StdEncoding.DecodeString(common.COPY_CREDENTIALS)
copy_srv_addr_button_icon_pixbuf, _ := gdkpixbuf.NewLoaderWithType("png")
copy_srv_addr_button_icon_pixbuf.SetSize(24, 24)
copy_srv_addr_button_icon_pixbuf.Write(copy_srv_addr_button_icon_bytes)
copy_srv_addr_button_icon := gtk.NewImageFromPixbuf(copy_srv_addr_button_icon_pixbuf.GetPixbuf())
copy_srv_addr_button := gtk.NewToolButton(copy_srv_addr_button_icon, "Copy server's creds")
copy_srv_addr_button.SetTooltipText("Copy server's credentials to clipboard for sharing")
copy_srv_addr_button.OnClicked(m.copyServerCredentialsToClipboard)
m.toolbar.Insert(copy_srv_addr_button, 6)
// Separator for toolbar's label and buttons.
toolbar_separator_toolitem := gtk.NewToolItem()
toolbar_separator_toolitem.SetExpand(true)
m.toolbar.Insert(toolbar_separator_toolitem, 6)
m.toolbar.Insert(toolbar_separator_toolitem, 7)
// Toolbar's label.
m.toolbar_label = gtk.NewLabel("URTrator is ready")
toolbar_label_toolitem := gtk.NewToolItem()
toolbar_label_toolitem.Add(m.toolbar_label)
m.toolbar.Insert(toolbar_label_toolitem, 7)
m.toolbar.Insert(toolbar_label_toolitem, 8)
}
// Tray icon initialization.

32
ui/mainwindow_init_mac.go Normal file
View File

@@ -0,0 +1,32 @@
package ui
import (
// stdlib
"os"
"path/filepath"
"runtime"
// other
"github.com/mattn/go-gtk/gtk"
)
func (m *MainWindow) initializeMac() {
if runtime.GOOS == "darwin" {
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
gtk.RCParse(dir + "/../Resources/themes/gtkrc-keybindings")
// ToDo: theming support and theme seletion in settings.
gtk.RCParse(dir + "/../Resources/themes/ClearlooksBrave/gtk-2.0/gtkrc")
}
}
func (m *MainWindow) initializeMacAfter() {
m.toolbar.SetStyle(gtk.TOOLBAR_ICONS)
}
func (m *MainWindow) initializeMacMenu() {
// This is a placeholder, in future we will use native mac menu.
// For now it launches default menu initialization.
m.InitializeMainMenu()
}

24
ui/mainwindow_init_win.go Normal file
View File

@@ -0,0 +1,24 @@
package ui
import (
// stdlib
"os"
"path/filepath"
// other
"github.com/mattn/go-gtk/gtk"
"github.com/couchbase/goutils/platform"
)
func (m *MainWindow) closeWin() {
platform.HideConsole(false)
}
func (m *MainWindow) initializeWin() {
platform.HideConsole(true)
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
// ToDo: theming support and theme seletion in settings.
gtk.RCParse(dir + "/themes/MS-Windows/gtk-2.0/gtkrc")
}

View File

@@ -4,6 +4,7 @@ import (
// stdlib
"errors"
"fmt"
"runtime"
"strings"
// Local
@@ -51,25 +52,46 @@ func (m *MainWindow) launchAsUsual() error {
model.GetValue(iter, m.column_pos["Favorites"]["IP"], srv_address_gval)
}
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
// Check for proper server name. If length == 0: server is offline,
// we should show notification to user.
if len(server_profile.Name) == 0 {
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."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
m.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
})
m.Response(func() {
m.Destroy()
})
m.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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."
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
messagebox.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
messagebox.Destroy()
})
messagebox.Run()
} else {
// We're okay to connect to empty server, temporary.
will_continue = true
}
if !will_continue {
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
// have profiles defined (see next).
if len(profile_name) == 0 {
mbox_string := "Invalid game profile selected.\n\nPlease, select profile and retry."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
// 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 selected.\n\nPlease, select 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 selected.</span></markup>"})
}
return errors.New("User didn't select valid profile.")
}
user_profile = ctx.Cache.Profiles[profile_name].Profile
} else if strings.Contains(current_tab, "Favorites") {
// For favorite servers profile specified in favorite server
// 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, "", "")
@@ -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 {
if server_profile.Name == "" {
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."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
m.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
})
m.Response(func() {
m.Destroy()
})
m.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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."
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
messagebox.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
messagebox.Destroy()
})
messagebox.Run()
} else {
// We're ok here, temporary.
will_continue = true
}
if !will_continue {
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.
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."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
// 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 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)
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.")
}
@@ -183,6 +239,9 @@ func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_prof
srv_name_for_label := server_profile.Name
if strings.Contains(server_profile.Name, "markup") {
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.
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>"})

View 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
}

View File

@@ -12,6 +12,7 @@ package ui
import (
// stdlib
"fmt"
"runtime"
// Local
"github.com/pztrn/urtrator/datamodels"
@@ -66,12 +67,16 @@ func (o *OptionsDialog) closeOptionsDialogWithSaving() {
o.saveGeneral()
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.Response(func() {
m.Destroy()
})
m.Run()
// Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" {
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.Response(func() {
m.Destroy()
})
m.Run()
}
o.window.Destroy()
}
@@ -128,18 +133,46 @@ func (o *OptionsDialog) fill() {
}
}
// Appearance tab initialization.
func (o *OptionsDialog) initializeAppearanceTab() {
appearance_vbox := gtk.NewVBox(false, 0)
l := gtk.NewLabel("There will be some appearance configuration options soon.")
appearance_vbox.PackStart(l, false, true, 5)
o.tab_widget.AppendPage(appearance_vbox, gtk.NewLabel("Appearance"))
}
func (o *OptionsDialog) initializeGeneralTab() {
general_vbox := gtk.NewVBox(false, 0)
general_table := gtk.NewTable(2, 2, false)
// 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")
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.
o.autoupdate = gtk.NewCheckButtonWithLabel("Automatically update URTrator?")
o.autoupdate.SetTooltipText("Should URTrator check for updates and update itself? Not working now.")
general_vbox.PackStart(o.autoupdate, false, true, 5)
autoupdate_tooltip := "Should URTrator check for updates and update itself? Not working now."
autoupdate_label := gtk.NewLabel("Automatically update URTrator?")
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"))
}
@@ -153,13 +186,15 @@ func (o *OptionsDialog) initializeStorages() {
func (o *OptionsDialog) initializeTabs() {
o.initializeStorages()
o.tab_widget = gtk.NewNotebook()
o.tab_widget.SetTabPos(gtk.POS_LEFT)
o.initializeGeneralTab()
o.initializeAppearanceTab()
o.initializeUrtTab()
// Buttons for saving and discarding changes.
buttons_hbox := gtk.NewHBox(false, 0)
sep := gtk.NewHSeparator()
sep := gtk.NewHBox(false, 0)
cancel_button := gtk.NewButtonWithLabel("Cancel")
cancel_button.Clicked(o.closeOptionsDialogByCancel)
@@ -178,7 +213,7 @@ func (o *OptionsDialog) initializeTabs() {
}
func (o *OptionsDialog) initializeUrtTab() {
urt_hbox := gtk.NewHBox(false, 0)
urt_hbox := gtk.NewHBox(false, 5)
// Profiles list.
o.profiles_list = gtk.NewTreeView()
@@ -188,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("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.
urt_profiles_buttons_vbox := gtk.NewVBox(false, 0)
button_add := gtk.NewButtonWithLabel("Add")
button_add.SetTooltipText("Add new profile")
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.SetTooltipText("Edit selected profile. Do nothing if no profile was selected.")
@@ -206,13 +237,13 @@ func (o *OptionsDialog) initializeUrtTab() {
urt_profiles_buttons_vbox.PackStart(button_edit, false, true, 5)
// Spacer for profiles list buttons.
sep := gtk.NewVSeparator()
sep := gtk.NewVBox(false, 0)
urt_profiles_buttons_vbox.PackStart(sep, true, true, 5)
button_delete := gtk.NewButtonWithLabel("Delete")
button_delete.SetTooltipText("Delete selected profile. Do nothing if no profile was selected.")
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)

View File

@@ -27,8 +27,8 @@ import (
type OptionsProfile struct {
// Window.
window *gtk.Window
// Main Vertical Box.
vbox *gtk.VBox
// Main table.
table *gtk.Table
// Profile name.
profile_name *gtk.Entry
// Binary path.
@@ -71,12 +71,18 @@ func (op *OptionsProfile) browseForBinaryHelper() {
if runtime.GOARCH == "amd64" {
if len(filename) > 0 && strings.Split(filename, ".")[1] != "x86_64" && strings.Split(filename, ".")[0] != "Quake3-UrT" {
fmt.Println("Invalid binary selected!")
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.Response(func() {
m.Destroy()
})
m.Run()
// 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.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("")
}
}
@@ -87,21 +93,33 @@ func (op *OptionsProfile) browseForBinaryHelper() {
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") {
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.Response(func() {
m.Destroy()
})
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.SetIcon(logo)
op.vbox = gtk.NewVBox(false, 0)
op.table = gtk.NewTable(6, 2, false)
op.table.SetRowSpacings(2)
// Profile name.
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.SetTooltipText(profile_name_tooltip)
profile_name_sep := gtk.NewHSeparator()
profile_name_sep.SetTooltipText(profile_name_tooltip)
pn_label.SetAlignment(0, 0)
op.table.Attach(pn_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
op.profile_name = gtk.NewEntry()
op.profile_name.SetTooltipText(profile_name_tooltip)
pn_hbox.PackStart(pn_label, false, true, 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)
op.table.Attach(op.profile_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
// Urban Terror version.
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.SetTooltipText(urt_version_tooltip)
urt_version_sep := gtk.NewHSeparator()
urt_version_sep.SetTooltipText(urt_version_tooltip)
urt_version_label.SetAlignment(0, 0)
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.SetTooltipText(urt_version_tooltip)
op.urt_version_combo.AppendText("4.2.023")
op.urt_version_combo.AppendText("4.3.0")
op.urt_version_combo.AppendText("4.3.1")
op.urt_version_combo.SetActive(1)
urt_version_hbox.PackStart(urt_version_label, false, true, 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)
op.urt_version_combo.SetActive(2)
op.table.Attach(op.urt_version_combo, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
// 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"
binpath_hbox := gtk.NewHBox(false, 0)
binpath_label := gtk.NewLabel("Urban Terror binary:")
binpath_label.SetTooltipText(select_binary_tooltip)
binpath_sep := gtk.NewHSeparator()
binpath_sep.SetTooltipText(select_binary_tooltip)
binpath_label.SetAlignment(0, 0)
op.table.Attach(binpath_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
op.binary_path = gtk.NewEntry()
op.binary_path.SetTooltipText(select_binary_tooltip)
button_select_binary := gtk.NewButtonWithLabel("Browse")
button_select_binary.SetTooltipText(select_binary_tooltip)
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(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?
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.vbox.PackStart(op.another_x_session, false, true, 5)
// macOS can't do that :).
// macOS and Windows can't do that :).
if runtime.GOOS != "linux" {
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.
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.SetTooltipText(params_tooltip)
params_sep := gtk.NewHSeparator()
params_sep.SetTooltipText(params_tooltip)
params_label.SetAlignment(0, 0)
op.table.Attach(params_label, 0, 1, 4, 5, gtk.FILL, gtk.SHRINK, 5, 5)
op.additional_parameters = gtk.NewEntry()
op.additional_parameters.SetTooltipText(params_tooltip)
params_hbox.PackStart(params_label, false, true, 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)
op.table.Attach(op.additional_parameters, 1, 2, 4, 5, gtk.FILL, gtk.FILL, 5, 5)
// Vertical separator.
vert_sep := gtk.NewVSeparator()
op.vbox.PackStart(vert_sep, true, true, 5)
// Invisible thing.
inv_label := gtk.NewLabel("")
op.table.Attach(inv_label, 1, 2, 5, 6, gtk.EXPAND, gtk.FILL, 5, 5)
// The buttons.
buttons_box := gtk.NewHBox(false, 0)
buttons_sep := gtk.NewHSeparator()
buttons_sep := gtk.NewHBox(false, 0)
cancel_button := gtk.NewButtonWithLabel("Cancel")
cancel_button.SetTooltipText("Close without saving")
@@ -233,9 +246,14 @@ func (op *OptionsProfile) Initialize(update bool) {
add_button.Clicked(op.saveProfile)
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()
}
@@ -244,26 +262,23 @@ func (op *OptionsProfile) InitializeUpdate(profile_name string) {
op.Initialize(true)
// Get profile data.
profile := []datamodels.Profile{}
err := ctx.Database.Db.Select(&profile, ctx.Database.Db.Rebind("SELECT * FROM urt_profiles WHERE name=?"), profile_name)
if err != nil {
fmt.Println(err.Error())
}
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" {
profile := ctx.Cache.Profiles[profile_name].Profile
op.profile_name.SetText(profile.Name)
op.binary_path.SetText(profile.Binary)
op.additional_parameters.SetText(profile.Additional_params)
if profile.Second_x_session == "1" {
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)
} else if profile.Version == "4.3.1" {
op.urt_version_combo.SetActive(2)
} else {
op.urt_version_combo.SetActive(0)
}
op.old_profile = &profile[0]
op.old_profile = profile
}

104
ui/server_cvars.go Normal file
View 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)
}

View File

@@ -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...")
}

View File

@@ -18,9 +18,6 @@ import (
// stdlib
"fmt"
"runtime"
// other
"github.com/couchbase/goutils/platform"
)
func main() {
@@ -29,11 +26,6 @@ func main() {
numCPUs := runtime.NumCPU()
runtime.GOMAXPROCS(numCPUs)
if runtime.GOOS == "windows" {
platform.HideConsole(true)
defer platform.HideConsole(false)
}
ctx := context.New()
ctx.Initialize()