smagacor 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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