smagacor 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -0,0 +1,50 @@
1
+ module Listener
2
+
3
+ # Adds a new message listener for the object. The message +msgName+
4
+ # will be dispatched to either the given +callableObject+ (has to respond
5
+ # to +call+) or the given block. If both are specified the +callableObject+
6
+ # is used.
7
+ def add_msg_listener( msgName, callableObject = nil, &block )
8
+ return unless defined?( @msgNames ) && @msgNames.has_key?( msgName )
9
+
10
+ if !callableObject.nil?
11
+ raise NoMethodError, "listener needs to respond to 'call'" unless callableObject.respond_to? :call
12
+ @msgNames[msgName].push callableObject
13
+ elsif !block.nil?
14
+ @msgNames[msgName].push block
15
+ else
16
+ raise "you have to provide a callback object or a block"
17
+ end
18
+ end
19
+
20
+ # Removes the given object from the dispatcher queue of the message +msgName+.
21
+ def del_msg_listener( msgName, object )
22
+ @msgNames[msgName].delete object if defined? @msgNames
23
+ end
24
+
25
+ #######
26
+ private
27
+ #######
28
+
29
+ # Adds a new message target called +msgName+
30
+ def add_msg_name( msgName )
31
+ @msgNames = {} unless defined? @msgNames
32
+ @msgNames[msgName] = [] unless @msgNames.has_key? msgName
33
+ end
34
+
35
+ # Deletes the message target +msgName+.
36
+ def del_msg_name( msgName )
37
+ @msgNames.delete msgName if defined? @msgNames
38
+ end
39
+
40
+ # Dispatches the message +msgName+ to all listeners for this message,
41
+ # providing the given arguments
42
+ def dispatch_msg( msgName, *args )
43
+ if defined? @msgNames and @msgNames.has_key? msgName
44
+ @msgNames[msgName].each do |obj|
45
+ obj.call( *args )
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -1,7 +1,7 @@
1
1
  #
2
2
  #--
3
3
  #
4
- # $Id: smagacor-ui.rb 195 2005-02-09 13:16:44Z thomas $
4
+ # $Id: smagacor-ui.rb 362 2005-11-26 17:56:46Z thomas $
5
5
  #
6
6
  # smagacor - a collection of small games in ruby
7
7
  # Copyright (C) 2004 Thomas Leitner
@@ -19,196 +19,276 @@
19
19
  #
20
20
  #++
21
21
  #
22
+
23
+ require 'Qt'
22
24
  require 'logger'
23
- require 'fox'
24
- require 'fox/colors'
25
- require 'smagacor/controller'
25
+ require 'ostruct'
26
+ require 'smagacor/util'
26
27
 
27
- include Fox
28
28
 
29
29
  module Smagacor
30
30
 
31
- # Widget for listing all installed games.
32
- class GameMenuShutter < FXShutter
31
+ # Used to identify a game in the list view
32
+ class GameMenuItem < Qt::ListViewItem
33
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 = {}
34
+ attr_reader :game_info
35
+
36
+ def initialize( parent, gameinfo )
37
+ super( parent, gameinfo.name )
38
+ @game_info = gameinfo
38
39
  end
39
40
 
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
41
+ def rtti
42
+ 1001
56
43
  end
57
44
 
58
45
  end
59
46
 
47
+ # Widget for listing all installed games.
48
+ class GameMenu < Qt::ListView
60
49
 
61
- # Widget for creating category shutter items easily.
62
- class CategoryShutterItem < FXShutterItem
50
+ slots 'toggleShown()'
63
51
 
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
52
+ # Returns a default version of the class.
53
+ def initialize( p )
54
+ super( p )
55
+ @categories = {}
56
+ setRootIsDecorated( true )
57
+ addColumn( "Games" )
58
+ setSorting( 0 )
59
+ setColumnWidthMode( 0, Qt::ListView::Maximum )
60
+ setShowToolTips( true )
61
+ setResizeMode( Qt::ListView::LastColumn )
62
+ setFixedWidth( 250 )
63
+ init_game_list
71
64
  end
72
65
 
73
- end
74
-
75
-
76
- # Widget for creating buttons for games easily.
77
- class GameShutterButton < FXButton
66
+ def init_game_list
67
+ clear
68
+ Config.load_games
69
+ Config.games.each do |game|
70
+ @categories[game.category] ||= Qt::ListViewItem.new( self, game.category )
71
+ item = GameMenuItem.new( @categories[game.category], game )
72
+ item.setPixmap( 0, Qt::Pixmap.new( File.join( game.directory, game.icon ) ) )
73
+ end
74
+ end
78
75
 
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)
76
+ def toggleShown
77
+ if isShown then hide else show end
84
78
  end
85
79
 
86
80
  end
87
81
 
82
+ class GameView < Qt::WidgetStack
83
+
84
+ slots 'select_game(QListViewItem*)', 'about()'
85
+
86
+ attr_reader :cur_game_data
88
87
 
89
- # Game switcher widget. Used to display the different games in the space.
90
- class GameSwitcher < FXSwitcher
88
+ # Small description of Smagacor, for the about view.
89
+ DESCRIPTION = "<p><img src=\"smagacor\" /><br /><br /><b>Smagacor #{::Smagacor::VERSION.join('.')}</b><br />
90
+ <br />
91
+ Smagacor is a collection of some small games.<br />
92
+ It provides an easy interface for adding new games and has<br />
93
+ a pleasing :-) appearance.<br />
94
+ <br />
95
+ Select a game from the menu on the left side!<br />
96
+ And have fun with Smagacor!!!<br />
97
+ <br />
98
+ <a href=\"http://smagacor.rubyforge.org\">smagacor.rubyforge.org</a>"
91
99
 
92
- # Create a new switcher.
93
- def initializer( p )
94
- super( p, FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y )
100
+ def initialize( p )
101
+ super( p )
102
+ @loaded = {}
103
+ Qt::MimeSourceFactory.defaultFactory.setImage( 'smagacor', Qt::Image.new( Config.get_file( 'smagacor.png' ) ) )
104
+ aboutPage = Qt::Label.new( DESCRIPTION, self )
105
+ aboutPage.setAlignment( Qt::AlignVCenter | Qt::AlignCenter )
106
+ @aboutId = addWidget( aboutPage )
107
+ @cur_game_data = nil
95
108
  end
96
109
 
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
110
+ def select_game( item )
111
+ return if item.nil? || item.rtti < 1000
112
+ gi = item.game_info
113
+
114
+ if @cur_game_data
115
+ save_game_state( @cur_game_data )
116
+ self.parent.parent.menuBar.removeItem( @cur_game_data.menu_id ) if @cur_game_data.menu_id
104
117
  end
105
- if game_index == 0
118
+
119
+ data = OpenStruct.new
120
+ unless @loaded.has_key?( gi )
106
121
  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
122
+ require File.join( gi.directory, gi.file )
123
+ data.game_info = gi
124
+ data.game_obj = gi.interface_class.new( self, gi )
125
+ data.undo_manager = UndoManager.new
126
+ data.game_obj.set_undo_manager( data.undo_manager )
127
+ data.menu = data.game_obj.menu
128
+ data.widget_id = addWidget( data.game_obj.game_widget )
129
+ @loaded[gi] = data
112
130
  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
131
+ Qt::MessageBox.critical( self, "Error loading game",
132
+ "Could not load the game #{gi.name}\nError: #{e.message}\n#{e.backtrace.join("\n")}",
133
+ Qt::MessageBox::Ok | Qt::MessageBox::Default, Qt::MessageBox::NoButton )
134
+ data = nil
116
135
  end
136
+ else
137
+ data = @loaded[gi]
138
+ end
139
+
140
+ unless data.nil?
141
+ load_game_state( data )
142
+ data.menu_id = self.parent.parent.menuBar.insertItem( data.game_info.name, data.menu ) if data.menu
143
+ self.parent.parent.undoManager = data.undo_manager
144
+ raiseWidget( @loaded[item.game_info].widget_id )
145
+ @cur_game_data = data
117
146
  end
118
- self.current = game_index
147
+ end
148
+
149
+ def about
150
+ raiseWidget( @aboutId )
151
+ end
152
+
153
+ #######
154
+ private
155
+ #######
156
+
157
+ def load_game_state( game_data )
158
+ end
159
+
160
+ def save_game_state( game_data )
161
+
119
162
  end
120
163
 
121
164
  end
122
165
 
123
166
 
124
167
  # Log window for viewing the log statements (information, error descriptions, etc ).
125
- class LogWindow < FXDialogBox
168
+ class LogWindow < Qt::Dialog
169
+
170
+ attr_reader :logdev
171
+
172
+ class Logdev
173
+
174
+ def initialize( window )
175
+ @window = window
176
+ end
177
+
178
+ def write( message )
179
+ @window.write( message )
180
+ end
181
+
182
+ def close(); end
183
+
184
+ end
126
185
 
127
186
  # Create a LogWindow
128
187
  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 )
188
+ super( p )
189
+ setMinimumSize( 400, 400 )
190
+ setCaption( "Log Window" )
191
+
192
+ @log = Qt::TextEdit.new( self )
193
+ @log.setTextFormat( Qt::LogText )
194
+ button = Qt::PushButton.new( "Close", self )
195
+ connect( button, SIGNAL('clicked()'), self, SLOT('hide()') )
196
+
197
+ verticalLayout = Qt::VBoxLayout.new( self )
198
+ verticalLayout.addWidget( @log )
199
+ verticalLayout.addWidget( button )
200
+ @logdev = Logdev.new( self )
134
201
  end
135
202
 
136
203
  # Invoked by the logger library for writing log messages. The +message+ is appended to log.
137
204
  def write( message )
138
- @log.appendText( message )
139
- @log.makePositionVisible( @log.text.length )
205
+ @log.append( message )
140
206
  end
141
207
 
142
- # Invoked by the logger library for closing the log device. Does nothing.
143
- def close() end
144
-
145
208
  end
146
209
 
147
210
 
148
211
  # Main window for Smagacor.
149
- class SmagacorWindow < FXMainWindow
212
+ class SmagacorWindow < Qt::MainWindow
150
213
 
151
- # Small description of Smagacor, for the about view.
152
- DESCRIPTION = "\n\nSmagacor #{::Smagacor::VERSION.join('.')}
214
+ slots 'undo()', 'redo()'
153
215
 
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.
216
+ attr_reader :undoManager
157
217
 
158
- Select a game from the menu on the left side!
159
- And have fun with Smagacor!!!
218
+ # Create the main window
219
+ def initialize( app )
220
+ super()
221
+ setCaption( 'Smagacor Game Collection' )
222
+ setIcon( Qt::Pixmap.new( Config.get_file( 'smagacor-logo.png' ) ) )
223
+ setIconText( 'Smagacor Game Collection' )
160
224
 
161
- smagacor.rubyforge.org"
225
+ @logwindow = LogWindow.new( self )
226
+ logger.set_log_dev( @logwindow.logdev )
162
227
 
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
228
+ statusBar = Qt::StatusBar.new( self )
229
+
230
+ mainWidget = Qt::Widget.new( self )
231
+ setCentralWidget( mainWidget )
170
232
 
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
233
+ mainLayout = Qt::HBoxLayout.new( mainWidget )
175
234
 
176
- @logwindow = LogWindow.new( app )
177
- logger.set_log_dev( @logwindow )
235
+ gamelist = GameMenu.new( mainWidget )
236
+ mainLayout.addWidget( gamelist )
178
237
 
179
- menubar = FXMenubar.new( self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X )
238
+ gameview = GameView.new( mainWidget )
239
+ mainLayout.addWidget( gameview, 1 )
180
240
 
181
- filemenu = FXMenuPane.new( self )
182
- FXMenuCommand.new( filemenu, "Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT )
183
- FXMenuTitle.new( menubar, "&File", nil, filemenu )
241
+ connect( gamelist, SIGNAL('doubleClicked(QListViewItem*, const QPoint&, int)'), gameview, SLOT('select_game(QListViewItem*)') )
184
242
 
185
- editmenu = FXMenuPane.new( self )
186
- FXMenuCommand.new( editmenu, "Undo\tCtl-Z" ).connect( SEL_COMMAND, method( :onUndo ) )
187
- FXMenuTitle.new( menubar, "&Edit", nil, editmenu )
243
+ quitAction = Qt::Action.new( "&Quit", Qt::KeySequence.new( CTRL+Key_Q ), self )
244
+ connect( quitAction, SIGNAL('activated()'), app, SLOT("quit()") )
245
+ @undoAction = Qt::Action.new( "&Undo", Qt::KeySequence.new( CTRL+Key_Z ), self )
246
+ @undoAction.setEnabled( false )
247
+ connect( @undoAction, SIGNAL('activated()'), self, SLOT("undo()") )
248
+ @redoAction = Qt::Action.new( "&Redo", Qt::KeySequence.new( CTRL+Key_R ), self )
249
+ @redoAction.setEnabled( false )
250
+ connect( @redoAction, SIGNAL('activated()'), self, SLOT("redo()") )
251
+ showLogWindowAction = Qt::Action.new( "Log Window...", Qt::KeySequence.new( CTRL+Key_L ), self )
252
+ connect( showLogWindowAction, SIGNAL('activated()'), @logwindow, SLOT("show()") )
253
+ showGameListAction = Qt::Action.new( "Toogle game list", Qt::KeySequence.new( CTRL+Key_G ), self )
254
+ connect( showGameListAction, SIGNAL('activated()'), gamelist, SLOT("toggleShown()") )
255
+ aboutAction = Qt::Action.new( "About Smagacor", Qt::KeySequence.new( CTRL+Key_A ), self )
256
+ connect( aboutAction, SIGNAL('activated()'), gameview, SLOT("about()") )
188
257
 
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 )
258
+ filemenu = Qt::PopupMenu.new( self )
259
+ quitAction.addTo( filemenu )
193
260
 
194
- status = FXStatusbar.new( self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER )
261
+ editmenu = Qt::PopupMenu.new( self )
262
+ @undoAction.addTo( editmenu )
263
+ @redoAction.addTo( editmenu )
195
264
 
196
- splitter = FXSplitter.new( self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING )
265
+ helpmenu = Qt::PopupMenu.new( self )
266
+ showLogWindowAction.addTo( helpmenu )
267
+ showGameListAction.addTo( helpmenu )
268
+ aboutAction.addTo( helpmenu )
197
269
 
198
- @shutter = GameMenuShutter.new( splitter )
199
- @switcher = GameSwitcher.new( splitter )
200
- @shutter.init_game_list( @switcher, controller )
270
+ self.menuBar.insertItem( "&File", filemenu )
271
+ self.menuBar.insertItem( "&Edit", editmenu )
272
+ self.menuBar.insertItem( "&Help", helpmenu )
273
+ end
274
+
275
+ def undoManager=( manager )
276
+ @undoManager.del_msg_listener( :possible_actions, method(:activateUndoRedo) ) if @undoManager
277
+ @undoManager = manager
278
+ @undoManager.add_msg_listener( :possible_actions, method(:activateUndoRedo) ) if @undoManager
279
+ end
201
280
 
202
- FXLabel.new( @switcher, DESCRIPTION, SmagacorWindow.load_image( getApp(), controller.get_file( 'smagacor.png' ) ), ICON_ABOVE_TEXT )
281
+ def activateUndoRedo( actions )
282
+ @undoAction.setEnabled( actions.include?( :undo ) )
283
+ @redoAction.setEnabled( actions.include?( :redo ) )
203
284
  end
204
285
 
205
- def create
206
- super
207
- @shutter.width = 150
208
- show
286
+ def undo
287
+ @undoManager.undo
209
288
  end
210
289
 
211
- def onUndo( sender, sel, event )
290
+ def redo
291
+ @undoManager.redo
212
292
  end
213
293
 
214
294
  end
@@ -219,10 +299,11 @@ smagacor.rubyforge.org"
219
299
 
220
300
  # Builds the application and runs it.
221
301
  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
302
+ app = Qt::Application.new( ARGV )
303
+ main = SmagacorWindow.new( app )
304
+ app.setMainWidget( main )
305
+ main.show
306
+ app.exec
226
307
  end
227
308
 
228
309
  end