smagacor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/ChangeLog +111 -0
- data/README +48 -0
- data/Rakefile +255 -0
- data/TODO +19 -0
- data/VERSION +1 -0
- data/bin/smagacor +23 -0
- data/data/smagacor/smagacor.png +0 -0
- data/data/smagacor/tictactoe/game.info +7 -0
- data/data/smagacor/tictactoe/o.png +0 -0
- data/data/smagacor/tictactoe/tictactoe.png +0 -0
- data/data/smagacor/tictactoe/tictactoe.rb +300 -0
- data/data/smagacor/tictactoe/x.png +0 -0
- data/install.rb +21 -0
- data/lib/smagacor/controller.rb +129 -0
- data/lib/smagacor/smagacor-ui.rb +230 -0
- data/setup.rb +1331 -0
- data/test/games/tictactoe/game.info +7 -0
- data/test/runtests.rb +2 -0
- data/test/smagacor/tc_controller.rb +48 -0
- metadata +69 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
#
|
2
|
+
#--
|
3
|
+
#
|
4
|
+
# $Id: controller.rb 197 2005-02-09 13:42:17Z thomas $
|
5
|
+
#
|
6
|
+
# smagacor - a collection of small games in ruby
|
7
|
+
# Copyright (C) 2004 Thomas Leitner
|
8
|
+
#
|
9
|
+
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU
|
10
|
+
# General Public License as published by the Free Software Foundation; either version 2 of the
|
11
|
+
# License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
14
|
+
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License along with this program; if not,
|
18
|
+
# write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
require 'rbconfig'
|
23
|
+
require "yaml"
|
24
|
+
require 'logger'
|
25
|
+
|
26
|
+
class Object
|
27
|
+
|
28
|
+
LOGGER = Logger.new( STDERR )
|
29
|
+
LOGGER.datetime_format = "%Y-%m-%d %H:%M:%S"
|
30
|
+
def logger
|
31
|
+
LOGGER
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class Logger
|
37
|
+
|
38
|
+
def set_log_dev( dev )
|
39
|
+
@logdev = LogDevice.new( dev )
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
module Smagacor
|
45
|
+
|
46
|
+
# The version of this copy of Smagacor
|
47
|
+
VERSION = [0, 0, 1]
|
48
|
+
|
49
|
+
class GameInfo
|
50
|
+
|
51
|
+
Domain = 'thomasleitner,2004'
|
52
|
+
Name = 'gameinfo'
|
53
|
+
|
54
|
+
attr_reader :name
|
55
|
+
attr_reader :icon
|
56
|
+
attr_reader :description
|
57
|
+
attr_reader :file
|
58
|
+
attr_accessor :directory
|
59
|
+
attr_reader :classname
|
60
|
+
attr_reader :category
|
61
|
+
|
62
|
+
def get_class_object
|
63
|
+
@classname.split( /::/ ).inject( Object ) {|mod, name| mod.const_get( name )}
|
64
|
+
end
|
65
|
+
|
66
|
+
def ==( other )
|
67
|
+
@name == other.name && \
|
68
|
+
@icon == other.icon && \
|
69
|
+
@description == other.description && \
|
70
|
+
@file == other.file && \
|
71
|
+
@directory == other.directory && \
|
72
|
+
@classname == other.classname && \
|
73
|
+
@category == other.category
|
74
|
+
end
|
75
|
+
|
76
|
+
alias :to_s :to_yaml
|
77
|
+
|
78
|
+
def to_yaml_type
|
79
|
+
"!#{Domain}/#{Name}"
|
80
|
+
end
|
81
|
+
|
82
|
+
YAML::add_domain_type( Domain, Name ) do |type, val|
|
83
|
+
YAML::object_maker( GameInfo, val )
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
class Controller
|
90
|
+
|
91
|
+
attr_reader :gamespath
|
92
|
+
attr_reader :games
|
93
|
+
|
94
|
+
def initialize
|
95
|
+
@gamespath = [ File.join( ::Config::CONFIG["datadir"], "smagacor" ), 'data/smagacor' ]
|
96
|
+
if defined? Gem::Cache
|
97
|
+
gem = Gem::Cache.from_installed_gems.search( "smagacor", "=#{::Smagacor::VERSION.join('.')}" ).last
|
98
|
+
@gamespath << File.join( gem.full_gem_path, "data", "smagacor" ) if gem
|
99
|
+
end
|
100
|
+
begin
|
101
|
+
homepath = File.expand_path( '~' )
|
102
|
+
rescue
|
103
|
+
homepath = ENV['USERPROFILE'] || ENV['HOMEDRIVE']+ENV['HOMEPATH']
|
104
|
+
end
|
105
|
+
@gamespath.unshift File.join( homepath, '.smagacor' )
|
106
|
+
@games = []
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_file( file )
|
110
|
+
@gamespath.each do |path|
|
111
|
+
name = File.join( path, file )
|
112
|
+
return name if File.exists?( name )
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def load_games
|
117
|
+
@games = []
|
118
|
+
@gamespath.each do |path|
|
119
|
+
Dir[path + '/*/game.info'].each do |file|
|
120
|
+
gi = YAML::load( File.open( file ) )
|
121
|
+
gi.directory = File.dirname( file )
|
122
|
+
@games.push gi
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
#
|
2
|
+
#--
|
3
|
+
#
|
4
|
+
# $Id: smagacor-ui.rb 195 2005-02-09 13:16:44Z thomas $
|
5
|
+
#
|
6
|
+
# smagacor - a collection of small games in ruby
|
7
|
+
# Copyright (C) 2004 Thomas Leitner
|
8
|
+
#
|
9
|
+
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU
|
10
|
+
# General Public License as published by the Free Software Foundation; either version 2 of the
|
11
|
+
# License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
14
|
+
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License along with this program; if not,
|
18
|
+
# write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
require 'logger'
|
23
|
+
require 'fox'
|
24
|
+
require 'fox/colors'
|
25
|
+
require 'smagacor/controller'
|
26
|
+
|
27
|
+
include Fox
|
28
|
+
|
29
|
+
module Smagacor
|
30
|
+
|
31
|
+
# Widget for listing all installed games.
|
32
|
+
class GameMenuShutter < FXShutter
|
33
|
+
|
34
|
+
# Returns a default version of the class.
|
35
|
+
def initialize( p )
|
36
|
+
super( p, nil, 0, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y )
|
37
|
+
@categories = {}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Initializes the list of games. The +switcher+ parameter has to be an object of class
|
41
|
+
# GameSwitcher. The method uses the list of games supplied by the +controller+ object.
|
42
|
+
def init_game_list( switcher, controller )
|
43
|
+
each_child do |child|
|
44
|
+
removeChild( child )
|
45
|
+
child.destroy
|
46
|
+
end
|
47
|
+
controller.load_games
|
48
|
+
controller.games.each do |game|
|
49
|
+
@categories[game.category] ||= CategoryShutterItem.new( self, game.category )
|
50
|
+
btn = GameShutterButton.new( @categories[game.category].content, game.name )
|
51
|
+
btn.tipText = game.description
|
52
|
+
btn.helpText = game.description
|
53
|
+
btn.icon = SmagacorWindow.load_image( getApp(), File.join( game.directory, game.icon ) )
|
54
|
+
btn.connect( SEL_COMMAND ) { switcher.select_game( game ) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Widget for creating category shutter items easily.
|
62
|
+
class CategoryShutterItem < FXShutterItem
|
63
|
+
|
64
|
+
# Create a new category shutter item for category +text+ with +icon+.
|
65
|
+
def initialize( p, text, icon=nil, opts=0 )
|
66
|
+
super( p, text, icon, opts|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10 )
|
67
|
+
button.padTop = 2
|
68
|
+
button.padBottom = 2
|
69
|
+
self.helpText = text
|
70
|
+
self.tipText = text
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Widget for creating buttons for games easily.
|
77
|
+
class GameShutterButton < FXButton
|
78
|
+
|
79
|
+
# Create a new game button for the game +name+.
|
80
|
+
def initialize( p, name )
|
81
|
+
super( p, name, nil, nil, 0, BUTTON_TOOLBAR|TEXT_BELOW_ICON|FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT )
|
82
|
+
self.backColor = p.backColor
|
83
|
+
self.textColor = FXRGB(255, 255, 255)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# Game switcher widget. Used to display the different games in the space.
|
90
|
+
class GameSwitcher < FXSwitcher
|
91
|
+
|
92
|
+
# Create a new switcher.
|
93
|
+
def initializer( p )
|
94
|
+
super( p, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y )
|
95
|
+
end
|
96
|
+
|
97
|
+
# Selects the specified +game+ [GameInfo] for playing. If the game has been selected earlier,
|
98
|
+
# the widget only displays the game area. Otherwise the information in +game+ is used for
|
99
|
+
# loading the necessary game files and for creating the game widget.
|
100
|
+
def select_game( game )
|
101
|
+
game_index = 0
|
102
|
+
children.each_with_index do |child, index|
|
103
|
+
game_index = index if child.userData == game
|
104
|
+
end
|
105
|
+
if game_index == 0
|
106
|
+
begin
|
107
|
+
require File.join( game.directory, game.file )
|
108
|
+
content = game.get_class_object.new( self, game )
|
109
|
+
content.create
|
110
|
+
content.userData = game
|
111
|
+
game_index = children.length - 1
|
112
|
+
rescue StandardError => e
|
113
|
+
FXMessageBox.new( self, "Error loading game",
|
114
|
+
"Could not load the game #{game.name}\nError: #{e.message}\n#{e.backtrace.join("\n")}",
|
115
|
+
nil, MBOX_OK ).execute
|
116
|
+
end
|
117
|
+
end
|
118
|
+
self.current = game_index
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Log window for viewing the log statements (information, error descriptions, etc ).
|
125
|
+
class LogWindow < FXDialogBox
|
126
|
+
|
127
|
+
# Create a LogWindow
|
128
|
+
def initialize( p )
|
129
|
+
super( p, "Log Window", DECOR_ALL, 0, 0, 600, 400 )
|
130
|
+
vertical = FXVerticalFrame.new( self, LAYOUT_SIDE_TOP|LAYOUT_SIDE_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_Y )
|
131
|
+
@log = FXText.new( vertical, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y )
|
132
|
+
@log.editable = false
|
133
|
+
FXButton.new( vertical, "Close", nil, self, ID_ACCEPT, FRAME_RAISED|LAYOUT_FILL_X )
|
134
|
+
end
|
135
|
+
|
136
|
+
# Invoked by the logger library for writing log messages. The +message+ is appended to log.
|
137
|
+
def write( message )
|
138
|
+
@log.appendText( message )
|
139
|
+
@log.makePositionVisible( @log.text.length )
|
140
|
+
end
|
141
|
+
|
142
|
+
# Invoked by the logger library for closing the log device. Does nothing.
|
143
|
+
def close() end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# Main window for Smagacor.
|
149
|
+
class SmagacorWindow < FXMainWindow
|
150
|
+
|
151
|
+
# Small description of Smagacor, for the about view.
|
152
|
+
DESCRIPTION = "\n\nSmagacor #{::Smagacor::VERSION.join('.')}
|
153
|
+
|
154
|
+
Smagacor is a collection of some small games.
|
155
|
+
It provides an easy interface for adding new games and has
|
156
|
+
a pleasing :-) appearance.
|
157
|
+
|
158
|
+
Select a game from the menu on the left side!
|
159
|
+
And have fun with Smagacor!!!
|
160
|
+
|
161
|
+
smagacor.rubyforge.org"
|
162
|
+
|
163
|
+
# Used to load *.png images into FXPNGIcon objects.
|
164
|
+
def self.load_image( app, file )
|
165
|
+
img = FXPNGIcon.new( app, nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP )
|
166
|
+
FXFileStream.open( file, FXStreamLoad ) {|str| img.loadPixels(str) }
|
167
|
+
img.create
|
168
|
+
img
|
169
|
+
end
|
170
|
+
|
171
|
+
# Create the main window, using +app+ [FXApplication] and +controller+ [Controller].
|
172
|
+
def initialize( app, controller )
|
173
|
+
super( app, "Smagacor Game Collection", nil, nil, DECOR_ALL, 100, 100, 800, 600 )
|
174
|
+
@controller = controller
|
175
|
+
|
176
|
+
@logwindow = LogWindow.new( app )
|
177
|
+
logger.set_log_dev( @logwindow )
|
178
|
+
|
179
|
+
menubar = FXMenubar.new( self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X )
|
180
|
+
|
181
|
+
filemenu = FXMenuPane.new( self )
|
182
|
+
FXMenuCommand.new( filemenu, "Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT )
|
183
|
+
FXMenuTitle.new( menubar, "&File", nil, filemenu )
|
184
|
+
|
185
|
+
editmenu = FXMenuPane.new( self )
|
186
|
+
FXMenuCommand.new( editmenu, "Undo\tCtl-Z" ).connect( SEL_COMMAND, method( :onUndo ) )
|
187
|
+
FXMenuTitle.new( menubar, "&Edit", nil, editmenu )
|
188
|
+
|
189
|
+
helpmenu = FXMenuPane.new( self )
|
190
|
+
FXMenuCommand.new( helpmenu, "Log Window...\tCtl-L" ).connect( SEL_COMMAND ) { @logwindow.show }
|
191
|
+
FXMenuCommand.new( helpmenu, "About Smagacor\tCtl-A" ).connect( SEL_COMMAND ) { @switcher.current = 0 }
|
192
|
+
FXMenuTitle.new( menubar, "&Help", nil, helpmenu )
|
193
|
+
|
194
|
+
status = FXStatusbar.new( self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER )
|
195
|
+
|
196
|
+
splitter = FXSplitter.new( self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING )
|
197
|
+
|
198
|
+
@shutter = GameMenuShutter.new( splitter )
|
199
|
+
@switcher = GameSwitcher.new( splitter )
|
200
|
+
@shutter.init_game_list( @switcher, controller )
|
201
|
+
|
202
|
+
FXLabel.new( @switcher, DESCRIPTION, SmagacorWindow.load_image( getApp(), controller.get_file( 'smagacor.png' ) ), ICON_ABOVE_TEXT )
|
203
|
+
end
|
204
|
+
|
205
|
+
def create
|
206
|
+
super
|
207
|
+
@shutter.width = 150
|
208
|
+
show
|
209
|
+
end
|
210
|
+
|
211
|
+
def onUndo( sender, sel, event )
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# Wraps the creation of the Smagacor Application.
|
218
|
+
class SmagacorUI
|
219
|
+
|
220
|
+
# Builds the application and runs it.
|
221
|
+
def start
|
222
|
+
app = FXApp.new( "Smagacor Game Collection", "Smagacor Game Collection" )
|
223
|
+
window = SmagacorWindow.new( app, Controller.new )
|
224
|
+
app.create
|
225
|
+
app.run
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|