From a901d5f2372ad7f791e070f0f5c83424ca89360b Mon Sep 17 00:00:00 2001
From: phear
Date: Tue, 20 Sep 2005 07:05:05 +0000
Subject: [PATCH] small changes here and there. a debug function (SPOT), css,
start of a navigation bar.
---
default.css | 373 +++++++++++++++++++++++++++++
deletegame.py | 7 +-
documentation/development/DATABASE | 16 ++
documentation/development/README | 1 +
gamecreation.py | 9 +-
generate_goban_images.py | 14 +-
goban.py | 29 +--
helper.py | 31 ++-
img/bottomleftline_black.png | Bin 4343 -> 4486 bytes
img/bottomleftline_white.png | Bin 4764 -> 4850 bytes
img/bottomline_black.png | Bin 4357 -> 4466 bytes
img/bottomline_white.png | Bin 4761 -> 4834 bytes
img/bottomrightline_black.png | Bin 4343 -> 4469 bytes
img/bottomrightline_white.png | Bin 4759 -> 4844 bytes
img/centerline_black.png | Bin 4364 -> 4475 bytes
img/centerline_white.png | Bin 4771 -> 4844 bytes
img/hoshi_black.png | Bin 4364 -> 4475 bytes
img/hoshi_white.png | Bin 4771 -> 4844 bytes
img/leftline_black.png | Bin 4351 -> 4490 bytes
img/leftline_white.png | Bin 4773 -> 4857 bytes
img/rightline_black.png | Bin 4350 -> 4478 bytes
img/rightline_white.png | Bin 4769 -> 4854 bytes
img/topleftline_black.png | Bin 4336 -> 4480 bytes
img/topleftline_white.png | Bin 4762 -> 4844 bytes
img/topline_black.png | Bin 4351 -> 4471 bytes
img/topline_white.png | Bin 4766 -> 4849 bytes
img/toprightline_black.png | Bin 4339 -> 4482 bytes
img/toprightline_white.png | Bin 4761 -> 4847 bytes
imgsource/blackstone.png | Bin 1493 -> 1262 bytes
imgsource/whitestone.png | Bin 1623 -> 1708 bytes
init_webgo.py | 1 -
login.py | 55 +++--
main.py | 37 ++-
playgame.py | 7 +-
psql.py | 2 +
35 files changed, 511 insertions(+), 71 deletions(-)
create mode 100644 default.css
create mode 100644 documentation/development/DATABASE
create mode 100644 documentation/development/README
diff --git a/default.css b/default.css
new file mode 100644
index 0000000..7bcc1d7
--- /dev/null
+++ b/default.css
@@ -0,0 +1,373 @@
+body {
+ background-position: top center;
+ background-attachment: fixed;
+ background-repeat: no-repeat;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ font-family: verdana, lucida, arial, helvetica, sans-serif;
+ }
+
+#main {
+ background: none;
+ width: 600px;
+ padding: 0px;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+#main h1, h2, h3 {
+ font-family: sans-serif, arial;
+ font-weight: normal;
+ letter-spacing: 0.05em;
+ color: #acacac;
+ font-variant: small-caps;
+ padding: 0 1em;
+ text-align: left;
+ }
+
+#main h1 {
+ font-size: 2em;
+ }
+
+#main h2 {
+ font-size: 1.5em;
+ }
+
+#main h3 {
+ font-size: 1.2em;
+ }
+
+#head {
+ width: 600px;
+ height: 120px;
+ margin: 0;
+ padding: 0;
+ background-image: url(cryptobox-img/vault_pingu.png);
+ background-position: top right;
+ background-attachment: scroll;
+ background-repeat: no-repeat;
+ }
+
+#content {
+ margin: 0;
+ padding: 0;
+ width: 600px;
+ font-size: 0.9em;
+ }
+
+#content a {
+ line-height: 1.2em;
+ color: #000000;
+ text-decoration: none;
+ font-weight: bold;
+ font-size: 0.9em;
+ }
+
+#content a:hover {
+ text-decoration: underline;
+ }
+
+#content a:visited {
+ color: #acacac;
+ }
+
+#content p {
+ font-size: 0.9em;
+ padding: 0 1em;
+ text-align: justify;
+ }
+
+#menu {
+ text-align: center;
+ border-top: 1px solid #5e5e5e;
+ border-bottom: 1px solid #5e5e5e;
+ background-color: #ACE149;
+ }
+
+#menu a:link, #menu a:visited {
+ color: #5e5e5e;
+ margin: 5px;
+ text-decoration: none;
+ border: none;
+ padding: 4px;
+ font-size: 0.8em;
+ }
+
+#menu a:hover {
+ color: #8e8e8e;
+ }
+
+#words {
+ width: 565px;
+ padding: 1.1em 0em 1.1em 1.1em;
+ margin-top: 0;
+ }
+
+#words h1{
+ font-size: 1.8em;
+ }
+
+#words h2{
+ font-size: 1.4em;
+ }
+
+#words ol, #words ul {
+ font-size: 0.9em;
+ }
+
+#words ol li {
+ padding: 0 1em;
+ line-height: 1.7em;
+ }
+
+#words ul li {
+ padding: 0 1em;
+ line-height: 1.7em;
+ list-style: none;
+ background: url(cryptobox-img/list.gif) center left no-repeat;
+ }
+
+#footer {
+ clear: both;
+ text-align: center;
+ border-top: 1px solid #5e5e5e;
+ border-bottom: 1px solid #5e5e5e;
+ background-color: #ACE149;
+ font-size: 0.8em;
+ color: #5e5e5e;
+ }
+
+#footer a:link, #footer a:visited {
+ color: white;
+ margin: 5px;
+ text-decoration: none;
+ border: none;
+ padding: 4px;
+ color: #5e5e5e;
+ }
+
+#footer a:hover {
+ text-decoration: underline;
+ }
+
+#confirmtext span {
+ color: red;
+ font-weight: bold;
+ }
+
+
+/* -------=-=-=- warnings, errors and success messages-=-=-=-------- */
+
+#words div.warning,div.error,div.success {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ padding-top: 10px;
+ padding-bottom: 15px;
+ color: #707070;
+ }
+
+#words .warning,.error,.success {
+ border: 1px dashed #808080;
+ text-align: center;
+ color: #5e5e5e;
+ text-decoration: none;
+ font-weight: bold;
+ font-size: 0.9em;
+ padding-left: 40px;
+ padding-right: 40px;
+ }
+
+#words .warning {
+ background-color: #f5f5f5;
+ }
+
+#words .error {
+ background-color: #f5f5f5;
+ }
+
+#words .success {
+/* background-color: #90EE90; */
+ }
+
+#words div.warning,div.error,div.success h1,h2 {
+ color: #808080;
+ }
+
+#words .warning,.error,.success a {
+// TODO: WHY line-height???
+// line-height: 5em;
+ color: #5e5e5e;
+ text-decoration: none;
+ font-weight: bold;
+ font-size: 0.9em;
+}
+
+#words .note {
+ text-align: center;
+ color: #F48659;
+ font-style: italic;
+ }
+
+/* ----------------------=-=-=- Forms -=-=-=--------------------- */
+/* pretty forms and buttons */
+input {
+ border: 1px solid #333333;
+ color: #333333;
+ background: #fff;
+ padding: 2px 5px 1px 5px;
+ font-size: 1em;
+
+ }
+
+input:hover {
+ background: #fff;
+ border: 1px solid #ACE149;
+ color: #7DA721;
+ font-size: 1em;
+
+ }
+
+textarea {
+ font-family: arial, verdana, helvetica;
+ font-size: 1.1em;
+ border: 1px solid #BFBFBF;
+ color: #949494;
+ padding: 2px 5px 1px 5px;
+ width: 450px;
+
+ }
+
+textarea:hover {
+ background: #fff;
+ border: 1px solid #ACE149;
+ color: #7DA721;
+
+ }
+/* the submit buttons have to have id="submit" for the following style: ------------------------------------- */
+input#submit {
+ background-color: #ACE149;
+ border: 1px solid #222222;
+ color: #222;
+ font-size: 0.8em;
+ font-weight: bold;
+ cursor: pointer;
+ }
+
+input#submit:hover {
+ background-color: #fff;
+ border: 1px solid #222;
+ color: #222;
+ font-size: 0.8em;
+ font-weight: bold;
+ cursor: pointer;
+ }
+/* the submit buttons have to have id="goban" for the following style, for use in goban display ------------- */
+input#goban {
+ padding: 0px;
+ border: 0px;
+ cursor: pointer;
+ }
+
+
+
+#words form label {
+ min-width: 20em;
+ }
+
+#words form p {
+ text-align: center;
+ }
+
+/* ------------=-=-=- language selection -=-=-=------------- */
+
+#lang {
+ position: fixed;
+ float: right;
+ right: 5px;
+ top: 5px;
+ text-align: right;
+ }
+
+#lang a {
+ color: #acacac;
+ font-family: verdana, lucida, arial, helvetica, sans-serif;
+ font-size: smaller;
+ }
+
+#lang a:hover {
+ color: #707070;
+ }
+
+
+/* ------------=-=-=- documentation -=-=-=------------- */
+
+#doc ol,ul li {
+ text-align: left;
+ margin-left: 20px;
+ }
+
+#doc dl dt {
+ text-align: left;
+ margin-left: 20px;
+ font-style: italic;
+ }
+
+#doc h1 {
+ padding-top: 25px;
+}
+
+#doc h2 {
+ padding-top: 20px;
+}
+
+#doc h3 {
+ padding-top: 10px;
+ }
+
+/* ------------=-=-=- special things -=-=-=------------- */
+
+#partition_info p {
+ margin-left: 10%;
+ margin-right: 10%;
+ font-family: monospace
+ }
+
+#words a.popup {
+ line-height: inherit;
+ color: inherit;
+ text-decoration: inherit;
+ font-weight: inherit;
+ font-size: inherit;
+ }
+
+#words a.popup:hover {
+ text-decoration: inherit;
+ }
+
+#words a.popup span {
+ display: none;
+ position: fixed;
+ bottom: 10px;
+ left: 9%;
+ width: 80%;
+ background: #f0f0f0;
+ padding: 10px;
+ border-color: #e0e0e0;
+ border-width: 2px;
+ border-style: solid;
+ margin: 0;
+ }
+
+#words a.popup:hover span {
+ display: inline;
+ }
+
+#words a.popup span p {
+ text-align: left;
+ }
+
+#words a.popup span h3 {
+ color: #909090;
+ margin-top: 0px;
+ }
diff --git a/deletegame.py b/deletegame.py
index 4636e33..d14f7fb 100644
--- a/deletegame.py
+++ b/deletegame.py
@@ -1,5 +1,7 @@
import psql,login
+DEBUG = 1
+
def delete_game(gamename,username):
"""
get name of game and name of user.
@@ -24,7 +26,8 @@ def main(req,form):
manage the removal of game from game slots of players and
delete game from database.
"""
- req.write(str(form.keys())+" sessionid in form:"+form["sessionid"]+"
")
+ if DEBUG:
+ req.write(str(form.keys())+" sessionid in form:"+form["sessionid"]+"
")
try:
gamename = form["game"]
except:
@@ -41,7 +44,7 @@ def main(req,form):
#delete table
psql.drop_table(gamename)
#now display game overview form.
- login.game_overview_form(req,player,form["sessionid"])
+ login.game_overview_form(req,form,player,form["sessionid"])
else:
req.write('Error: You have to select a game to delete it!')
\ No newline at end of file
diff --git a/documentation/development/DATABASE b/documentation/development/DATABASE
new file mode 100644
index 0000000..a2446cd
--- /dev/null
+++ b/documentation/development/DATABASE
@@ -0,0 +1,16 @@
+this file describes the database of the game.
+there are currently 2 types of tables in the game.
+
+One is the user table. this table is unique.
+do the following to get the details:
+cd webgo
+python
+import psql
+print psql.create_user_table.__doc__
+
+the other one is a goban table. for each game there exists one goban
+table. do the following to get the details:
+cd webgo
+python
+import psql
+print psql.create_goban_table.__doc__
diff --git a/documentation/development/README b/documentation/development/README
new file mode 100644
index 0000000..07809be
--- /dev/null
+++ b/documentation/development/README
@@ -0,0 +1 @@
+this is webgo, a browser-based version of go.
diff --git a/gamecreation.py b/gamecreation.py
index 017fb77..6c4c658 100644
--- a/gamecreation.py
+++ b/gamecreation.py
@@ -1,6 +1,8 @@
from mod_python import *
import psql,helper,login
+DEBUG = 1
+
def display_game_creation_form(req,sessionid,username):
"""
prints a html form with multiple drop-down lists for choosing players,
@@ -21,7 +23,7 @@ def display_game_creation_form(req,sessionid,username):
Goban Size: %s fields
-
+
""" % (p1data,p2data,gobansize,sessionid,username)
@@ -54,7 +56,7 @@ def process_creation_form(req,form):
#display form again
display_game_creation_form(req,form["sessionid"],username)
#TODO:game created, now display game overview form
- login.game_overview_form(req,username,form["sessionid"])
+ login.game_overview_form(req,form,username,form["sessionid"])
else:
#give error message
req.write("Sorry, you must be one of the players!
")
@@ -97,7 +99,8 @@ def main(req,form):
gets a request object and a util.FieldStorage form.
returns nothing.
"""
- req.write(str(form.keys())+"
")
+ if DEBUG:
+ req.write(str(form.keys())+"
")
username = form["username"]
#TODO:check if valid session id
diff --git a/generate_goban_images.py b/generate_goban_images.py
index 2993d12..16e1357 100755
--- a/generate_goban_images.py
+++ b/generate_goban_images.py
@@ -2,7 +2,7 @@
"""
a simple script using pil to generate the goban from background, grid and stone images.
"""
-import Image
+import Image,ImageOps
gridlist = ["bottomleftline","bottomline","bottomrightline",
"centerline","hoshi","leftline","rightline",
"topleftline", "topline","toprightline"]
@@ -15,11 +15,13 @@ for item in gridlist:
bg = Image.open("imgsource/background.png").convert("RGBA")
img = Image.open("imgsource/"+item+".png").convert("RGBA")
bg.paste(img,None,img)
+ #bg = Image.composite(img,bg,img)
bg.save("img/"+item+".png")
- tmp = bg #for the black stones
+ tmp = bg #for the white stones
+ tmp2 = bg #for the black stones
#filling with white stones
- bg.paste(whitestone,None,whitestone)
- bg.save("img/"+item+"_white.png")
+ tmp.paste(whitestone,None,whitestone)
+ tmp.save("img/"+item+"_white.png")
#filling with black stones
- tmp.paste(blackstone,None,blackstone)
- tmp.save("img/"+item+"_black.png")
+ tmp2.paste(blackstone.convert("RGB"),None,blackstone)
+ tmp2.save("img/"+item+"_black.png")
diff --git a/goban.py b/goban.py
index 53c65d5..65ccb8b 100755
--- a/goban.py
+++ b/goban.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
+DEBUG = 1
import sys,string
import cgi
@@ -24,7 +25,7 @@ def display_goban(goban,req,form):
hoshis9x9 = [(3,3),(3,7),(5,5),(7,3),(7,7)]
- data += ''
+ data += '\n
'
return data
diff --git a/helper.py b/helper.py
index 033fa33..6c523a7 100644
--- a/helper.py
+++ b/helper.py
@@ -1,14 +1,39 @@
import string
+DEBUG = 1
+
def header():
"""return html header"""
data = """
-
-
-
+
+
+
+
+
+ WebGo
+
+
+
+
+
+
+
+ WebGo
"""
return data
+def debug(req,form, optstr = ""):
+ """
+ print various debug infos, e.g. form content.
+ gets request, util.FieldStorage form, optional extra string.
+ returns nothing, writes with request.write.
+ """
+ if DEBUG:
+ if optstr == "":
+ req.write(str(form.keys()))
+ else:
+ req.write(optstr)
+
def footer():
"""return html footer"""
data = """
diff --git a/img/bottomleftline_black.png b/img/bottomleftline_black.png
index a04599201cbc1107777655bdf7679faceb5e1504..a152200305e934b9cf4a357e6a295bbbabf0b8c8 100644
GIT binary patch
delta 4137
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