Centering text in Gosu - ruby

I've been having trouble centering text in the Gosu library to the absolute middle of the screen.
require 'gosu'
class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
#message = Gosu::Image.from_text(
self, 'HELLO WORLD', Gosu.default_font_name, 45)
end
def draw
#message.draw(377.5,277.5,0)
end
end
window = GameWindow.new
window.show
My first approach was to take the height of the screen, subtract it by the height of the text 45, and then divide by 2. Now that seemed to work when aligning vertically.
However, horizontally is a different story...It seems to
be taking the top left corner of the text and centering it which I expected it to do, instead of the middle of the text.
Anyone got a formula for this ? I tried a whole bunch of things, and only came close.

class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
#message = Gosu::Image.from_text(
self, 'HELLO WORLD', Gosu.default_font_name, 45)
end
def draw
#message.draw(377.5,277.5,0)
end
end
Your #message is an instance of Gosu::Image
As far as I can see, the class has a method that allows you to align the image's rotational center to a specified point, draw_rot
Using draw_rot instead of draw should work for you once you've found the center of the frame.

I know this is an old question, but I was having this issue earlier today and came up with this solution.
def draw_centered_text(text, size, font)
centered_text = Gosu::Image.from_text(text, size, {:width => WIDTH, :align => :center, :font => font})
end
The above function converts the passed text to an image with a width equal to WIDTH (which in my case is a constant that stores the window width) and the text centred. You can then call the function like so:
draw_centered_text("Your text", 20, "Arial Bold").draw(0, 50, 0, 1, 1, Gosu::Color::WHITE)
You can replace 20 and 50 with any line height (font size) and y-position you want, just as you can change "Arial Bold" to "Arial" or any other font on your system. However, keep the 0 for the x-position (first parameter of draw()), since the centred text image is the same width as the window width.
See the links below for further information on from_text() and draw():
https://www.rubydoc.info/github/gosu/gosu/Gosu/Image#from_text-class_method
https://www.rubydoc.info/github/gosu/gosu/Gosu/Image#draw-instance_method

Better late than never...
No need to convert your text to an image. Just center the text using two parameters available on the Font.draw_text_rel method: rel_x and rel_y. See your code (modified a bit) below.
See: https://www.rubydoc.info/gems/gosu/Gosu%2FFont:draw_text_rel
require 'gosu'
class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
# #message = Gosu::Image.from_text(
# self, 'HELLO WORLD', Gosu.default_font_name, 45)
#font = Gosu::Font.new(45)
#message = "HELLO WORLD"
end
def draw
#font.draw_text_rel(#message, width / 2, height / 2, 1, rel_x = 0.5, rel_y = 0.5)
end
end
window = GameWindow.new
window.show

Related

Strange behaviour with ScrolledWindow

I have written the program below. It displays an image within a hbox inside a scrolledwindow. The image moves forward when space key is pressed, backwards when backspace is pressed. Whenever an image is changed, I set the scrolledwindow adjustments value to 0.0 so that it will always display from the start. But this is not working correctly, for example when I use the mouse wheel to scroll the image up or down, press space or backspace, it will sometimes show the next/previous image from the top or stay at that position. I want it to always show the next/prev image from the top. Have I messed up somewhere? I'm using ruby-gtk 4.0.8.
require 'gtk3'
class Window < Gtk::ApplicationWindow
def initialize(app)
super(app)
set_default_size(800, 600)
path = File.expand_path('~/Manga/Deadman Wonderland')
#images = Dir.children(path).map { |file| "#{path}/#{file}" }
#sc_win = Gtk::ScrolledWindow.new
#box = Gtk::Box.new(:horizontal)
#box.halign = :center
#box.valign = :center
#image = Gtk::Image.new
#image_index = -1
signal_connect('key-press-event') do |_widg, event|
case event.keyval
when Gdk::Keyval::KEY_space
reset_viewport
next_image
when Gdk::Keyval::KEY_BackSpace
reset_viewport
prev_image
end
end
next_image
#box.add(#image)
#sc_win.add(#box)
add(#sc_win)
end
def next_image
if #image_index < #images.length - 1
#image.pixbuf.unref if #image.pixbuf
#image_index += 1
#image.set_pixbuf(GdkPixbuf::Pixbuf.new(:file => #images[#image_index]))
end
end
def prev_image
if #image_index > 0
#image.pixbuf.unref if #image.pixbuf
#image_index -= 1
#image.set_pixbuf(GdkPixbuf::Pixbuf.new(:file => #images[#image_index]))
end
end
def reset_viewport
#sc_win.hadjustment.set_value(0.0)
#sc_win.vadjustment.set_value(0.0)
end
end
app = Gtk::Application.new(nil, :flags_none)
app.signal_connect('activate') { Window.new(app).show_all }
app.run
I tried printing out the value of vertical adjustment whenever it changed. I noticed that at some point after calling reset_viewport, its value reset from 0.0 to the previous one.
#sc_win.vadjustment.signal_connect('value-changed') do
p #sc_win.vadjustment.value
end
494.0 #at bottom of image
0.0 #after pressing space key
494.0 #jumps back!

Music and image failed to initialize

I was trying to make a multiple-choice music player using Gosu but the picture and music Iwanted would not initialize despite the program running, it showed a black screen. The single block of codes works:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song.play
end
def draw
#beth.draw(0, 0)
end
end
window = MW.new
window.show
But adding the multiple choice elements would not work(note: read_integer_in_range is defined in input function, the name itself is self explanatory). Full code:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#dimitri = Gosu::Image.new("media/dimitri.png")
#vil = Gosu::Image.new("media/vilva.png")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song2=Gosu::Song.new("media/2ndwaltz.mp3")
#song3=Gosu::Song.new("media/1stseason.mp3")
read_integer_in_range( "What song you want play
1st Spring
2nd Waltz
3rd movement", 1, 3)
choice = gets.chomp.to_i()
case choice
when 1
#song3.play
#vil.draw(0, 0)
when 2
#song2.play
#dimitri.draw(0, 0)
when 3
#song.play
draw_beth()
end
end
end
def draw_beth
#beth.draw(0, 0)
end
window = MW.new
window.show
All of the Png/Jpg and mp3 file works just fine..
I tried separating the draw_beth to call it in case but it did not work. I hope some passing by could help me with this one
As I can see, you are creating a music player with GUI, and if you are doing so, you shouldn't use gets function, instead you should track for the cursor's position and return a test value; for example:
def update
#locs = [mouse_x, mouse_y]
#cursor_choice_album = mouse_over_button(mouse_x, mouse_y)
end
def needs_cursor?; true; end
def mouse_over_button(mouse_x, mouse_y)
if ((mouse_x > 100 and mouse_x < 500) and (mouse_y < 500 and mouse_y > 100))
return 1
end
then you can use the case condition in the "button down ID" function

Cannot print a text with Gosu in Ruby

Im sitting here with what I think is a very simple bug I just can not figure out.. Im trying to learn how to make games with Gosu gem with Ruby, but have hit a speed bump. Here is my code.
require "gosu"
class Hello < Gosu::Window
def initialize width = 800, height = 600, fullscreen = false
super
self.caption = "Ruby Practise"
#image = Gosu::Image.from_text self. "My text to print".
Gosu.default_font_name.
100
end
def button_down id
close if id == Gosu::KbEscape
end
def update
end
def draw
#image.draw 0, 0, 0
end
end
Hello.new.show
There is something wrong but I do not know what. I have spent at least 1 hour on it.. It complains on the String, here is the output from terminal.
hello.rb:8: syntax error, unexpected tSTRING_BEG
#image = Gosu::Image.from_text self. "My text to print".
^
hello.rb:10: syntax error, unexpected tINTEGER
I do not what I am doing wrong, do some one know? It is probably something really simple..
Use commas to separate function arguments, not dots:
#image = Gosu::Image.from_text self, "My text to print",
Gosu.default_font_name,
100

Controlling content flow with Prawn

Let's say we want to display a title on the first page that takes up the top half of the page. The bottom half of the page should then fill up with our article text, and the text should continue to flow over into the subsequent pages until it runs out:
This is a pretty basic layout scenario but I don't understand how one would implement it in Prawn.
Here's some example code derived from their online documentation:
pdf = Prawn::Document.new do
text "The Prince", :align => :center, :size => 48
text "Niccolò Machiavelli", :align => :center, :size => 20
move_down 42
column_box([0, cursor], :columns => 3, :width => bounds.width) do
text((<<-END.gsub(/\s+/, ' ') + "\n\n") * 20)
All the States and Governments by which men are or ever have been ruled,
have been and are either Republics or Princedoms. Princedoms are either
hereditary, in which the bla bla bla bla .....
END
end
end.render
but that will just continue to show the title space for every page:
What's the right way to do this?
I have been fighting with this same problem. I ended up subclassing ColumnBox and adding a helper to invoke it like so:
module Prawn
class Document
def reflow_column_box(*args, &block)
init_column_box(block) do |parent_box|
map_to_absolute!(args[0])
#bounding_box = ReflowColumnBox.new(self, parent_box, *args)
end
end
private
class ReflowColumnBox < ColumnBox
def move_past_bottom
#current_column = (#current_column + 1) % #columns
#document.y = #y
if 0 == #current_column
#y = #parent.absolute_top
#document.start_new_page
end
end
end
end
end
Then it is invoked exactly like a normal column box, but on the next page break will reflow to the parents bounding box. Change your line:
column_box([0, cursor], :columns => 3, :width => bounds.width) do
to
reflow_column_box([0, cursor], :columns => 3, :width => bounds.width) do
Hope it helps you. Prawn is pretty low level, which is a two-edged sword, it sometimes fails to do what you need, but the tools are there to extend and build more complicated structures.
I know this is old, but I thought I'd share that a new option has been added to fix this in v0.14.0.
:reflow_margins is an option that sets column boxes to fill their parent boxes on new page creation.
column_box(reflow_margins: true, columns: 3)
So, the column_box method creates a bounding box. The documented behavior of the bounding box is that it starts at the same position as on the previous page if it changes to the next page. So the behavior you are seeing is basically correct, also not what you want. The suggested workaround I have found by googling is to use a span instead, because spans do not have this behavior.
The problem now is, how to build text columns with spans? They don't seem to support spans natively. I tried to build a small script that mimicks columns with spans. It creates one span for each column and aligns them accordingly. Then, the text is written with text_box, which has the overflow: :truncate option. This makes the method return the text that did not fit in the text box, so that this text can then be rendered in the next column. The code probably needs some tweaking, but it should be enough to demonstrate how to do this.
require 'prawn'
text_to_write = ((<<-END.gsub(/\s+/, ' ') + "\n\n") * 20)
All the States and Governments by which men are or ever have been ruled,
have been and are either Republics or Princedoms. Princedoms are either
hereditary, in which the bla bla bla bla .....
END
pdf = Prawn::Document.generate("test.pdf") do
text "The Prince", :align => :center, :size => 48
text "Niccolò Machiavelli", :align => :center, :size => 20
move_down 42
starting_y = cursor
starting_page = page_number
span(bounds.width / 3, position: :left) do
text_to_write = text_box text_to_write, at: [bounds.left, 0], overflow: :truncate
end
go_to_page(starting_page)
move_cursor_to(starting_y)
span(bounds.width / 3, position: :center) do
text_to_write = text_box text_to_write, at: [bounds.left, 0], overflow: :truncate
end
go_to_page(starting_page)
move_cursor_to(starting_y)
span(bounds.width / 3, position: :right) do
text_box text_to_write, at: [bounds.left, 0]
end
end
I know this is not an ideal solution. However, this was the best I could come up with.
Use floats.
float do
span((bounds.width / 3) - 20, :position => :left) do
# Row Table Code
end
end
float do
span((bounds.width / 3) - 20, :position => :center) do
# Row Table Code
end
end
float do
span((bounds.width / 3) - 20, :position => :right) do
# Row Table Code
end
end
Use Prawns grid layout instead. It is very well documented...and easier to control your layout.

Prawn doesn't seem to push layout down when using repeat(:all)

I am generating a document with data that flows onto each subsequent page, each page has a standard header. However, when I use repeat(:all) to put the header on each page, I find that on every page but the first page, the next content is not being moved down by the size of the header banner I have put on the page.
My code for generating the banner:
class SmartsoftPdf < Prawn::Document
BOX_MARGIN = 30
RHYTHM = 10
INNER_MARGIN = 30
# Colors
#
BLACK = "000000"
LIGHT_GRAY = "F2F2F2"
GRAY = "DDDDDD"
DARK_GRAY = "333333"
BROWN = "A4441C"
ORANGE = "F28157"
LIGHT_GOLD = "FBFBBE"
DARK_GOLD = "EBE389"
BLUE = "08C"
GREEN = "00ff00"
RED = "ff0000"
def show_header(text,date)
header_box do
image "#{Rails.root}/app/assets/images/smart_records_logo_h60.png", :height => 40
draw_text text,
:at => [80,25], :size => 12, :style => :bold, :color => BLUE
draw_text "Date: #{ausDate(date)}",
:at => [bounds.right - 100,bounds.top - 15], :size => 10 if date
end
end
def header_box(&block)
bounding_box([-bounds.absolute_left, cursor + BOX_MARGIN + 8],
:width => bounds.absolute_left + bounds.absolute_right,
:height => BOX_MARGIN*2) do
fill_color LIGHT_GRAY
fill_rectangle([bounds.left, bounds.top],
bounds.right,
bounds.top - bounds.bottom)
fill_color BLACK
move_down(RHYTHM)
indent(BOX_MARGIN, &block)
end
stroke_color GRAY
stroke_horizontal_line(-BOX_MARGIN, bounds.width + BOX_MARGIN, :at => cursor)
stroke_color BLACK
move_down(RHYTHM*4)
end
end
Then within the pdf generation itself I do:
repeat(:all) do
show_header("Custom Report",DateTime.now())
end
However, when I start putting content onto the pages, I expect when the content overflows onto the next page that the content will show up after the header. I'm finding that the header overlaps the content instead.
Here is an image which illustrates the problem: http://i.imgur.com/mSy2but.png
Am I building the header box incorrectly? Do I need to do something additional to make it so that the content which spills into the next page gets pushed down the appropriate amount?
Okay. I have solved this myself. Most recent version of Prawn has a better way to handle this case. When you use repeat(:all) the page is reopened AFTER document creation and your content creation items are then added. This doesn't push the page down. The correct way to add this header to every page is to use the "canvas" method which allows you to operate out of the bounds of the page margin. Use canvas to draw a box at the top of the page, and set the top_margin of the page to push all content below the banner.
canvas do
bounding_box([bounds.left,bounds.top],
:width => bounds.absolute_left + bounds.absolute_right,
:height => BOX_MARGIN*2) do
fill_color LIGHT_GRAY
fill_rectangle([bounds.left, bounds.top],
bounds.right,
bounds.top - bounds.bottom)
fill_color BLACK
move_down(RHYTHM)
indent(BOX_MARGIN, &block)
end
stroke_color GRAY
stroke_horizontal_line(-BOX_MARGIN, bounds.width + BOX_MARGIN, :at => cursor)
stroke_color BLACK
end
at document creation...
def initialize(options = {})
super(:page_layout => :landscape,:top_margin => HEIGHT_OF_BANNER)
end

Resources