# FlagsGTK.py Copyright (c) 2009 Kari Laitinen # http://www.naturalprogramming.com # 2009-02-19 File created. # 2009-03-17 Last modification. # This program demonstrates: # - the use of inherited classes # - the use of a constructor that accepts a varying # number of arguments (actual parameters) # - how to build a multi-layered user interface with a gtk.Notebook # object. A gtk.Notebook object can contain several tabs, and each # tab may contain, for example, a gtk.VBox into which GUI components # can be attached. # This program displays flags of some countries. Flags are a nice example # of classification: some flags contain three colored stripes in vertical # direction, some flags contain colored stripes in horizontal direction, # the flags of Nordic countries contain a cross, etc. # In this program flags are classified in this way, and they are drawn # according to this classification. I must, however, apologize and # warn that all the flags are not displayed according to the exact # specifications of the flags. For example, many flags are displayed # so that their length-to-height ratio is a certain fixed value. # In reality, however, the mentioned ratio can vary from country to # country. Moreover, the flag colors shown by this program are not # necessarily the exact variations of blue, green, red, or yellow # that are used in real flags. # The specifications of national flags are stipulated by laws # of each country in question, and it is possible that this program # thus breaks the laws of many countries. However, I hope that you might # enjoy this program despite the fact that some flags are not drawn # according to the official specifications. # This program shows only flags that are relatively easy to draw. # So, those flags that contain decorations that do not consist of # straight lines cannot be displayed by this program. In some cases, # which are mentioned, this program shows only the flag bacground, # leaving a complicated detail undrawn. import gtk # Class Flag is a kind of 'abstract' superclass for the other # flag classes. It is abstract only in the sense that no objects of # type Flag are used in this program. Python does not have # abstract classes in the sense like other languages such as Java. # Each subclass of class Flag has its own draw() method which draws # the flag in question. class Flag : def __init__( self ) : self.flag_height = 240 self.flag_length = int( self.flag_height * 3 / 2 ) self.flag_position_x = 100 self.flag_position_y = 80 self.flag_description = "" self.flag_colors = () # The constructor parameter declared as *given_colors in # classes VerticalStripesFlag and HorizontalStripesFlag is # a tuple containing the color strings that are given as # individual strings when the constructors are called. # A formal parameter declared with a * is a tuple that # represents a varying number of actual parameters (arguments) class VerticalStripesFlag ( Flag ) : def __init__( self, given_flag_description, *given_colors ) : Flag.__init__( self ) self.flag_description = given_flag_description self.flag_colors = given_colors self.number_of_stripes_to_draw = len( self.flag_colors ) self.stripe_width = self.flag_length / self.number_of_stripes_to_draw # The following statement adjusts flag_length in the case # when the previous statement "lost pixels" in rounding. self.flag_length = self.number_of_stripes_to_draw * self.stripe_width def draw( self, given_drawing_area ) : graphics_context = given_drawing_area.get_style().fg_gc[gtk.STATE_NORMAL] given_drawable = given_drawing_area.window for stripe_index in range( self.number_of_stripes_to_draw ) : graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( self.flag_colors[ stripe_index ] ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x + stripe_index * self.stripe_width, self.flag_position_y, self.stripe_width, self.flag_height ) graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( "black" ) given_drawable.draw_rectangle( graphics_context, False, self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) flag_description_as_layout = \ given_drawing_area.create_pango_layout( self.flag_description ) given_drawable.draw_layout( graphics_context, self.flag_position_x, self.flag_position_y + self.flag_height + 20, flag_description_as_layout ) class HorizontalStripesFlag ( Flag ) : def __init__( self, given_flag_description, *given_colors ) : Flag.__init__( self ) self.flag_description = given_flag_description self.flag_colors = given_colors self.number_of_stripes_to_draw = len( self.flag_colors ) self.stripe_height = self.flag_height / self.number_of_stripes_to_draw # The following statement ensures that the flag height, # which is an int value, corresponds with the stripe height. self.flag_height = self.number_of_stripes_to_draw * self.stripe_height def draw( self, given_drawing_area ) : graphics_context = given_drawing_area.get_style().fg_gc[gtk.STATE_NORMAL] given_drawable = given_drawing_area.window for stripe_index in range( self.number_of_stripes_to_draw ) : graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( self.flag_colors[ stripe_index ] ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x, self.flag_position_y + stripe_index * self.stripe_height, self.flag_length, self.stripe_height ) graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( "black" ) given_drawable.draw_rectangle( graphics_context, False, self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) flag_description_as_layout = \ given_drawing_area.create_pango_layout( self.flag_description ) given_drawable.draw_layout( graphics_context, self.flag_position_x, self.flag_position_y + self.flag_height + 20, flag_description_as_layout ) class CrossFlag ( Flag ) : # The ratios, which must be given when a CrossFlag # object is created, describe flag dimensions in relation to # the length of the flag. The term "wide cross" means the cross # that is underneath the other cross, the "narrow cross". In the flag # of Norway, for instance, the wide cross is white and the narrow cross is # blue. Not all cross flags (e.g., the Swedish flag) have a wide cross. # Such flags can be defined so that the color and width of the wide cross # are the same as the color and the width of the narrow cross. # The cross_point_ratio tells in which horizontal point the the # vertical cross bar is located. The horizontal cross bar is always # at the middle of the flag. # If the ratios are correctly specified, cross flags will be # shown with right proportional dimensions by this program. # These ratios are fairly easy to specify if you see (e.g. on # the Internet) how flags are officially defined. More information # about this subject can be found at the end of this file. def __init__( self, given_flag_description, given_background_color, given_wide_cross_color, given_narrow_cross_color, given_flag_ratio, given_cross_point_ratio, given_wide_cross_width_ratio, given_narrow_cross_width_ratio ) : Flag.__init__( self ) self.flag_description = given_flag_description # We'll construct a tuple of the given flag colors self.flag_colors = ( given_background_color, given_wide_cross_color, given_narrow_cross_color ) self.flag_length = (int) ( self.flag_height / given_flag_ratio ) self.cross_point = (int) ( self.flag_length * given_cross_point_ratio ) self.wide_cross_width = (int) ( self.flag_length * given_wide_cross_width_ratio ) self.narrow_cross_width = (int) (self.flag_length * given_narrow_cross_width_ratio) def draw( self, given_drawing_area ) : graphics_context = given_drawing_area.get_style().fg_gc[gtk.STATE_NORMAL] given_drawable = given_drawing_area.window # Let's set the flag background color as drawing color. graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( self.flag_colors[ 0 ] ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) # wide cross color graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( self.flag_colors[ 1 ] ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x, self.flag_position_y + self.flag_height / 2 - self.wide_cross_width / 2, self.flag_length, self.wide_cross_width ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x + self.cross_point - self.wide_cross_width / 2, self.flag_position_y, self.wide_cross_width, self.flag_height ) # narrow cross color graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( self.flag_colors[ 2 ] ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x, self.flag_position_y + self.flag_height / 2 - self.narrow_cross_width / 2, self.flag_length, self.narrow_cross_width ) given_drawable.draw_rectangle( graphics_context, True, self.flag_position_x + self.cross_point - self.narrow_cross_width / 2, self.flag_position_y, self.narrow_cross_width, self.flag_height ) graphics_context.foreground = \ given_drawable.get_colormap().alloc_color( "black" ) given_drawable.draw_rectangle( graphics_context, False, self.flag_position_x, self.flag_position_y, self.flag_length, self.flag_height ) flag_description_as_layout = \ given_drawing_area.create_pango_layout( self.flag_description ) given_drawable.draw_layout( graphics_context, self.flag_position_x, self.flag_position_y + self.flag_height + 20, flag_description_as_layout ) class FlagPanel ( gtk.VBox ) : def __init__( self ) : gtk.VBox.__init__( self, False, 0 ) self.flags_to_be_shown = [] self.index_of_currently_shown_flag = 0 button_to_see_previous_flag = gtk.Button( " < " ) button_to_see_next_flag = gtk.Button( " > " ) button_to_see_previous_flag.connect( "clicked", self.previous_button_clicked ) button_to_see_next_flag.connect( "clicked", self.next_button_clicked ) button_panel = gtk.HBox( False, 0 ) button_panel.pack_start( button_to_see_previous_flag ) button_panel.pack_start( button_to_see_next_flag ) self.flag_area = gtk.DrawingArea() self.flag_area.set_size_request( 580, 400 ) self.flag_area.connect( "expose-event", self.flag_area_exposed ) self.pack_start( self.flag_area, False, False, 3 ) self.pack_start( button_panel, False, False, 3 ) def add_flag( self, new_flag_to_this_panel ) : self.flags_to_be_shown.append( new_flag_to_this_panel ) def previous_button_clicked( self, widget, data=None ) : self.index_of_currently_shown_flag -= 1 if self.index_of_currently_shown_flag < 0 : self.index_of_currently_shown_flag = len( self.flags_to_be_shown ) - 1 self.flag_area.queue_draw() def next_button_clicked( self, widget, data=None ) : self.index_of_currently_shown_flag += 1 if self.index_of_currently_shown_flag >= len( self.flags_to_be_shown ) : self.index_of_currently_shown_flag = 0 self.flag_area.queue_draw() def flag_area_exposed( self, area, event ) : self.flags_to_be_shown[ self.index_of_currently_shown_flag ]. \ draw( self.flag_area ) class FlagsApplication : def __init__( self ) : self.application_window = gtk.Window( gtk.WINDOW_TOPLEVEL ) self.application_window.set_title( "VIEW FLAGS OF VARIOUS COUNTRIES" ) self.application_window.connect("destroy", lambda w: gtk.main_quit() ) self.application_window.set_size_request( 580, 470 ) panel_for_flags_of_africa = FlagPanel() panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Botswana","cyan","cyan","cyan","cyan","cyan", "cyan","cyan","cyan","cyan","white", "black","black","black","black", "white","cyan","cyan","cyan","cyan", "cyan","cyan","cyan","cyan","cyan")) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Chad", "blue", "yellow", "red" ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Ethiopia","green", "yellow", "red" ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Gabon", "green", "yellow", "blue" ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "The Gambia", "red", "red", "red", "red", "red", "red", "white", "blue","blue","blue", "blue", "white", "green", "green", "green","green","green","green" ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Guinea", "red", "yellow", "green" ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Ivory Coast", "orange", "white", "green" ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Libya", "green4" ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Mali", "green", "yellow", "red" ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Mauritius", "red", "blue", "yellow", "green" ) ) panel_for_flags_of_africa.add_flag( VerticalStripesFlag( "Nigeria", "green4", "white", "green4")) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Sierra Leone", "green", "white", "blue" ) ) panel_for_flags_of_africa.add_flag( HorizontalStripesFlag( "Uganda (flag background)", "black", "yellow", "red", "black", "yellow", "red" ) ) panel_for_flags_of_europe = FlagPanel() panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Austria", "red", "white", "red" )) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Belgium", "black", "yellow", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Bulgaria","white", "green", "red" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Denmark", "red", "red", "white", 28.0/37, 14.0/37, 4.0/37, 4.0/37 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Denmark, Faroe Islands", "white", "blue", "red", 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Estonia", "blue", "black", "white" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Finland", "white", "blue", "blue", 11.0/18, 6.5/18, 3.0/18, 3.0/18 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Finland, Aland Province","MidnightBlue","yellow","red", 34.0/52, 21.0/52, 10.0/52, 4.0/52 ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "France", "blue", "white", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Germany", "black", "red", "orange" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Holland", "red", "white", "blue" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Hungary", "red", "white", "green" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Iceland", "blue", "white", "red", 18.0/25, 9.0/25, 4.0/25, 2.0/25 ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Ireland", "green", "white", "orange" ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Italy", "green", "white", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Latvia", "red", "red", "white", "red", "red")) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Liechtenstein (flag background)", "blue", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Lithuania", "yellow", "green", "red" ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Malta (flag background)", "white", "red" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Norway", "red", "white", "blue", 16.0/22, 8.0/22, 4.0/22, 2.0/22 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Poland", "white", "red" ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Portugal (flag background)", "green4", "green4", "red", "red", "red" ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Romania", "blue", "yellow", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Russia", "white", "blue", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "San Marino (Civil flag)", "white", "cyan" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain (flag background)", "red", "yellow", "yellow", "red" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain, Andalucia Civil flag", "green", "white", "green" ) ) panel_for_flags_of_europe.add_flag( VerticalStripesFlag( "Spain, Canary Islands Civil flag", "white", "blue", "yellow" ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Spain, Catalonia ", "yellow", "red", "yellow", "red", "yellow", "red", "yellow", "red", "yellow" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Sweden", "blue", "yellow", "yellow", 10.0/16, 6.0/16, 2.0/16, 2.0/16 ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "Sweden, Scania Region", "red", "yellow", "yellow", 14.0/17, 7.0/17, 2.0/17, 2.0/17 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Ukraine", "blue", "yellow" ) ) panel_for_flags_of_europe.add_flag( CrossFlag( "United Kingdom, England", "white", "red", "red", 3.0/5, 0.5, 3.0/25, 3.0/25 ) ) panel_for_flags_of_europe.add_flag( HorizontalStripesFlag( "Armenia", "red", "blue", "orange" ) ) panel_for_flags_of_asia = FlagPanel() panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "India (flag background)", "orange", "white", "green4" ) ) panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "Indonesia", "red", "white" ) ) panel_for_flags_of_asia.add_flag( VerticalStripesFlag( "Mongolia (flag backround)", "red", "blue", "red" ) ) panel_for_flags_of_asia.add_flag( HorizontalStripesFlag( "Thailand", "red", "white", "blue", "blue", "white", "red" ) ) panel_for_flags_of_the_americas = FlagPanel() panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Argentina (flag background)", "cyan", "white", "cyan")) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Chile, old flag of 1810", "blue", "white", "yellow") ) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Colombia", "yellow", "yellow", "blue", "red" ) ) panel_for_flags_of_the_americas.add_flag( HorizontalStripesFlag( "Costa Rica (flag background)", "blue", "white", "red", "red", "white", "blue" ) ) panel_for_flags_of_the_americas.add_flag( VerticalStripesFlag( "Guatemala civil flag", "#0066FF", "white", "#0066FF" )) panel_for_flags_of_the_americas.add_flag( VerticalStripesFlag( "Peru", "red", "white", "red" ) ) notebook_for_flag_panels = gtk.Notebook() # The second parameter for the append_page() method must be a gtk.Widget. notebook_for_flag_panels.append_page( panel_for_flags_of_africa, gtk.Label( "Africa" ) ) notebook_for_flag_panels.append_page( panel_for_flags_of_europe, gtk.Label( "Europe" ) ) notebook_for_flag_panels.append_page( panel_for_flags_of_asia, gtk.Label( "Asia" ) ) notebook_for_flag_panels.append_page( panel_for_flags_of_the_americas, gtk.Label( "Americas" ) ) self.application_window.add( notebook_for_flag_panels ) self.application_window.show_all() def run( self ) : gtk.main() if __name__ == "__main__": this_application = FlagsApplication() this_application.run() # NOTES: # In this program flag colors are specified as strings, and those # strings are supplied to the gtk.Colormap.alloc_color() method # In Linux and UNIX the RGB colors are specified as strings # in a file named rgb.txt. # The possible locations where this file can be found are # /etc/X11/rgb.txt # /usr/lib/X11/rgb.txt # See, for example, http://tin.le.org/vault/colors.html # to find out what the colors look like on the screen.