// Windows.kt Copyright (c) Kari Laitinen // http://www.naturalprogramming.com // 2020-10-29 File created. /* This program displays simple character-based 'windows' to the Terminal screen. The classes of this program provide an example of a class hierarchy. Each class has at least one constructor. */ /* Class Window is the topmost class in the class hierarchy. A Window could look like //////////// //////////// //////////// //////////// In this window the width is 12, the height is 4, and the background character is '/' */ open class Window( var window_width : Int = Window.MAXIMUM_WINDOW_WIDTH, var window_height : Int = Window.MAXIMUM_WINDOW_HEIGHT, var background_character : Char = ' ' ) { companion object { const val MAXIMUM_WINDOW_WIDTH = 78 const val MAXIMUM_WINDOW_HEIGHT = 22 } // Window contents consist of characters that are stored // in a two-dimensional array. var window_contents : Array init { window_contents = Array( window_width ) { CharArray( window_height ) } fill_with_character( background_character ) } fun fill_with_character( filling_character : Char ) { for ( row_index in 0 .. window_height - 1 ) { for ( column_index in 0 .. window_width - 1 ) { window_contents[ column_index ] [ row_index ] = filling_character ; } } } fun print_this_window() { print( "\n" ) for ( row_index in 0 .. window_height - 1 ) { for ( column_index in 0 .. window_width - 1 ) { print( window_contents[ column_index ] [ row_index ] ) } print( "\n" ) } } // The following method moves another window over 'this' window. fun move( given_destination_x_index : Int, given_destination_y_index : Int, another_window : Window ) { // Swift no longer accepts function parameters to be used // as variables. Therefore, we copy the given parameters // to local variables. var destination_x_index = given_destination_x_index var destination_y_index = given_destination_y_index var source_y_index = 0 while ( source_y_index < another_window.window_height ) { if ( destination_y_index >= 0 && destination_y_index < window_height ) { var source_x_index = 0 val saved_destination_x_index = destination_x_index while ( source_x_index < another_window.window_width ) { if ( destination_x_index >= 0 && destination_x_index < window_width ) { window_contents [ destination_x_index ][ destination_y_index ] = another_window.window_contents[ source_x_index ] [ source_y_index ] } source_x_index += 1 destination_x_index += 1 } destination_x_index = saved_destination_x_index } source_y_index += 1 destination_y_index += 1 } } } /* Class FrameWindow represents a window that looks like |----------------------| | | | | | | | | | | |----------------------| The window has frames that are made by using characters '|' and '-'. The inner area of the window contains space characters. */ open class FrameWindow( window_width : Int, window_height : Int ) : Window( window_width, window_height, '|' ) { init { val horizontal_frames = Window( window_width - 2, window_height, '-' ) val spaces_inside_window = Window( window_width - 2, window_height - 2, ' ' ) move( 1, 0, horizontal_frames ) move( 1, 1, spaces_inside_window ) } constructor() : this( 40, 10 ) } /* A TextWindow can look like the following |----------------------------| | | | | | | | Hello, world. | | | | | |----------------------------| */ open class TextWindow( window_width : Int, window_height : Int, var text_inside_window : String = "" ) : FrameWindow( window_width, window_height ) { fun embed_text_in_window() { val text_length = text_inside_window.length val text_row = window_height / 2 val text_start_column = (window_width - text_length) / 2 for ( character_index in 0 .. text_length - 1 ) { val character_column = text_start_column + character_index window_contents[ character_column ] [ text_row ] = text_inside_window[ character_index ] } } init { embed_text_in_window() } fun change_text( new_line_of_text : String ) { text_inside_window = new_line_of_text embed_text_in_window() } } /* The lowest class in the hierarchy is DecoratedTextWindow. Such a window has a decoration frame that is made with characters '*': **************************** *|------------------------|* *| |* *| |* *| |* *| Smile! |* *| |* *| |* *| |* *|------------------------|* **************************** */ class DecoratedTextWindow( desired_window_width : Int, desired_window_height : Int, given_line_of_text : String ) : TextWindow( desired_window_width, desired_window_height, given_line_of_text ) { init { val decoration_frame = Window( desired_window_width, desired_window_height, '*' ) val window_inside_window = TextWindow( desired_window_width - 2, desired_window_height - 2, given_line_of_text ) decoration_frame.move( 1, 1, window_inside_window ) move( 0, 0, decoration_frame ) } } fun main() { var background_window = Window( 76, 22, '/' ) var empty_window = FrameWindow( 24, 7 ) var greeting_window = TextWindow( 30, 8, "Hello, world." ) var smiling_window = DecoratedTextWindow( 28, 11, "Smile!" ) background_window.move( 6, 2, empty_window ) background_window.move( 4, 12, greeting_window ) greeting_window.change_text( "HELLO, UNIVERSE!" ) background_window.move( 43, 11, greeting_window ) background_window.move( 40, 3, smiling_window ) background_window.print_this_window() }