I am using ruby 2.6.3, installed by compiling the source.
When using Gtk::FontChooserDialog.new, the default font size given is 10.
Is it possible to call Gtk::FontChooserDialog.new with a different size, such
as 24, so that I can avoid having to change the size each time I select a font.
Here is how I am doing things:
dialog = Gtk::FontChooserDialog.new(:title => "Select font",
:parent => self,
:action => Gtk::FileChooserAction::OPEN,
:buttons => [[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT], [Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
I have tried (in the argument list) :size => 24, :default_size => 24, etc. This does not work. I'm just guessing here. I have searched a lot, with no luck. I also looked in the gem sample dirs at test-gtk-font-chooser-dialog.rb and other files but no luck.
I am using Linux Mint Mate 19.1, installed a couple of weeks ago.
You need to set the size through a Pango.FontDescription. A short example in Python would be:
font_chooser = Gtk.FontChooserDialog.new(title = "Select font", parent = self)
font_description = Pango.FontDescription.new()
font_description.set_size(24 * Pango.SCALE)
font_chooser.set_font_desc(font_description)
EDIT
And here is a complete example in Ruby:
#!/usr/bin/ruby
'''
ZetCode Ruby GTK tutorial
This program runs a font dialog with a default (settable) font size.
Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''
require 'gtk3'
require 'pango'
class RubyApp < Gtk::Window
def initialize
super
init_ui
end
def init_ui
set_title "Center"
signal_connect "destroy" do
Gtk.main_quit
end
button = Gtk::Button.new
button.set_label "Font"
button.signal_connect "clicked" do
dialog = Gtk::FontChooserDialog.new(:title => "Select font", :parent => self, :action => Gtk::FileChooserAction::OPEN, :buttons => [[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT], [Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
font_description = Pango::FontDescription.new
font_description.set_size 24 * Pango::SCALE
dialog.set_font_desc font_description
dialog.run
end
add button
set_default_size 300, 200
set_window_position Gtk::WindowPosition::CENTER
show_all
end
end
window = RubyApp.new
Gtk.main
Related
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.
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
I'm trying to make a small program to mung some data into usable form. One thing I'd like it to do is to be able to select some files and perform actions on them, so I thought i'd use the listbox object in Tk to do that. I want to be able to open a file and see its filename displayed in the listbox. As far as I've read this is precisely what using listvariable in the listbox is for. Yet when I run my code the listbox is never updated (although items already in the listvariable variable are displayed fine).
So here's a close to MWE for this. What am I doing wrong, and what fundamental idea have I misunderstood?
require 'tk'
require 'tkextlib/tile'
$path_list = []
$populate_list = TkVariable.new( $path_list )
def get_file
file = Tk.getOpenFile
file = open(file) unless file.empty?
path = File.basename(file, ".out")
if $path_list.include?(path)
Tk.messageBox(
'type' => "ok",
'icon' => "warning",
'title' => " - Minimum Working Example - ",
'message' => "This file has already been added! Nothing was added to the list"
)
else
$path_list.push(path)
end
end
root = TkRoot.new {title "- Minimum Working Example -"}
frame = Tk::Tile::Frame.new(root) {padding "3 3 12 12"}.grid( :sticky => 'nsew') # 'north south east west'
TkGrid.columnconfigure root, 0, :weight => 1; TkGrid.rowconfigure root, 0, :weight => 1
$file_listbox = Tk::Listbox.new(frame) {
listvariable $populate_list}.grid( :column => 1, :row => 0, :rowspan => 6)
Tk::Tile::Button.new(frame) {
width 15; text 'Open file...'; command {get_file}}.grid( :column => 0, :row => 1)
Tk.mainloop
Do I maybe have to write it in some other order?
Just add one line of code:
$populate_list.value = $path_list
under this one:
$path_list.push(path)
It works for me, although looks weird.
TkVariable create a proxy for you ruby variable, thus bridge your ruby var references with Tk widgets. But i don't know why changes in proxy var don't affect the var it points to. I'm not sure whether it should do that automatically.
I'm trying to set the foreground color of text in a hyperlink cell but it doesn't seem to work.
Using something like: sheet["A1"].color = "0000FF" works fine for a normal cell, but not for a hyperlinked cell
This code simply creates a link to cell D1 on the "Log" sheet (which works fine) but A1 never turns blue!
sheet.add_hyperlink :location => "'Log'!D1", :target => :sheet, :ref => "A1"
sheet["A1"].color = "0000FF"
Thanks!
There are two important things to do before applying a color to a link:
You have to define the color within a style, and
You have to know the exact address of the cell in question.
Styles are normally applied to rows, but in this case you want to apply it to a specific cell. This is possible, but you need to address the cell directly through the Sheet Object. Also, and somewhat counter intuitively, the 'add_hyperlink' method is available to the Sheet object, not the Cell. So beware of that as well.
Here is an example of how to apply a style to a cell containing a link:
p = Axlsx::Package.new
p.workbook do |wb|
wb.styles do |s|
blue_link = s.add_style :fg_color => '0000FF'
wb.add_worksheet(:name => "Anchor Link Test") do |sheet|
sheet.add_row ['Title', 'Link']
# Define the row here, we will use that later
row = sheet.add_row ['Google', 'Click to go']
# Add the hyperlink by addressing the column you have used and add 1 to the row's index value.
sheet.add_hyperlink :location => "http://www.google.com", :ref => "B#{row.index + 1}"
sheet["B#{row.index + 1}"].style = blue_link
end
s = p.to_stream()
File.open("anchor_link_test.xlsx", 'w') { |f| f.write(s.read) }
end
end
Final note: You might note that I have written this spreadsheet using the methods
s = p.to_stream()
File.open("anchor_link_test.xlsx", 'w') { |f| f.write(s.read) }
There is evidence presented on the Axlsx Github Issues Page which shows that this means of writing out the file is significantly faster than
p.serialize
Just thought that deserved mention somewhere on StackOverflow!
This seems to work:
require 'axlsx'
p = Axlsx::Package.new
ws = p.workbook.add_worksheet
ws.add_row ['hoge-hoge']
ws['A1'].color = '0000FF'
ws.add_hyperlink :location => 'F6', :target => :sheet, :ref => 'A1'
p.serialize 'where_is_my_color.xlsx'
Can you post a larger example of your code that does not set the color?
Apparently Axlsx is only applying custom styles to String data types. Fixed this by setting each column to type :string like this:
Sheet.add_row [ "1", "2", "3" ], :types => [:string, :string, :string]
Thanks Randy!
I want to create a document with prawn one or more pages long that uses a different template for each page.
Prawn::Document.generate("test.pdf") do
doc.faces.each do |face|
start_new_page(:template => face.background_path)
end
end
This works and creates a document, however the first page is a blank letter sized page and then my pages added with start_new_page show up. Is there a way to have prawn not generate that first page?
thanks!
pdf = Prawn::Document.new(:skip_page_creation => true)
doc.faces.each do |face|
pdf.start_new_page(:template => face.background_path)
< your page building code here >
end
should work if I'm reading the docs correctly.
My controller code looks like:
def pdf
#person = Person.find(params[:id])
send_data #person.as_pdf, :filename => "#{#person.pdfName}.pdf", :type => "application/pdf"
end
and the as_pdf method in person.rb looks like
def as_pdf(type = 'short')
pdf = Prawn::Document.new(:margin => [36, 36, 36, 36] )
driver = self.pdf_layout_info
driver.each do |element|
< lots of ugly layout logic >
end
pdf.render
end